2929#include "rebase-interactive.h"
3030
3131static char const * const builtin_rebase_usage [] = {
32- N_ ("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
33- "[<upstream> ] [<branch>]" ),
32+ N_ ("git rebase [-i] [options] [--exec <cmd>] "
33+ "[--onto <newbase> | --keep-base ] [<upstream> [< branch>] ]" ),
3434 N_ ("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
3535 "--root [<branch>]" ),
3636 N_ ("git rebase --continue | --abort | --skip | --edit-todo" ),
@@ -1261,24 +1261,44 @@ static int is_linear_history(struct commit *from, struct commit *to)
12611261 return 1 ;
12621262}
12631263
1264- static int can_fast_forward (struct commit * onto , struct object_id * head_oid ,
1265- struct object_id * merge_base )
1264+ static int can_fast_forward (struct commit * onto , struct commit * upstream ,
1265+ struct commit * restrict_revision ,
1266+ struct object_id * head_oid , struct object_id * merge_base )
12661267{
12671268 struct commit * head = lookup_commit (the_repository , head_oid );
1268- struct commit_list * merge_bases ;
1269- int res ;
1269+ struct commit_list * merge_bases = NULL ;
1270+ int res = 0 ;
12701271
12711272 if (!head )
1272- return 0 ;
1273+ goto done ;
12731274
12741275 merge_bases = get_merge_bases (onto , head );
1275- if (merge_bases && !merge_bases -> next ) {
1276- oidcpy (merge_base , & merge_bases -> item -> object .oid );
1277- res = oideq (merge_base , & onto -> object .oid );
1278- } else {
1276+ if (!merge_bases || merge_bases -> next ) {
12791277 oidcpy (merge_base , & null_oid );
1280- res = 0 ;
1278+ goto done ;
12811279 }
1280+
1281+ oidcpy (merge_base , & merge_bases -> item -> object .oid );
1282+ if (!oideq (merge_base , & onto -> object .oid ))
1283+ goto done ;
1284+
1285+ if (restrict_revision && !oideq (& restrict_revision -> object .oid , merge_base ))
1286+ goto done ;
1287+
1288+ if (!upstream )
1289+ goto done ;
1290+
1291+ free_commit_list (merge_bases );
1292+ merge_bases = get_merge_bases (upstream , head );
1293+ if (!merge_bases || merge_bases -> next )
1294+ goto done ;
1295+
1296+ if (!oideq (& onto -> object .oid , & merge_bases -> item -> object .oid ))
1297+ goto done ;
1298+
1299+ res = 1 ;
1300+
1301+ done :
12821302 free_commit_list (merge_bases );
12831303 return res && is_linear_history (onto , head );
12841304}
@@ -1377,6 +1397,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
13771397 struct rebase_options options = REBASE_OPTIONS_INIT ;
13781398 const char * branch_name ;
13791399 int ret , flags , total_argc , in_progress = 0 ;
1400+ int keep_base = 0 ;
13801401 int ok_to_skip_pre_rebase = 0 ;
13811402 struct strbuf msg = STRBUF_INIT ;
13821403 struct strbuf revisions = STRBUF_INIT ;
@@ -1395,6 +1416,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
13951416 OPT_STRING (0 , "onto" , & options .onto_name ,
13961417 N_ ("revision" ),
13971418 N_ ("rebase onto given branch instead of upstream" )),
1419+ OPT_BOOL (0 , "keep-base" , & keep_base ,
1420+ N_ ("use the merge-base of upstream and branch as the current base" )),
13981421 OPT_BOOL (0 , "no-verify" , & ok_to_skip_pre_rebase ,
13991422 N_ ("allow pre-rebase hook to run" )),
14001423 OPT_NEGBIT ('q' , "quiet" , & options .flags ,
@@ -1548,6 +1571,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
15481571 warning (_ ("git rebase --preserve-merges is deprecated. "
15491572 "Use --rebase-merges instead." ));
15501573
1574+ if (keep_base ) {
1575+ if (options .onto_name )
1576+ die (_ ("cannot combine '--keep-base' with '--onto'" ));
1577+ if (options .root )
1578+ die (_ ("cannot combine '--keep-base' with '--root'" ));
1579+ }
1580+
15511581 if (action != ACTION_NONE && !in_progress )
15521582 die (_ ("No rebase in progress?" ));
15531583 setenv (GIT_REFLOG_ACTION_ENVIRONMENT , "rebase" , 0 );
@@ -1876,12 +1906,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
18761906 }
18771907
18781908 /* Make sure the branch to rebase onto is valid. */
1879- if (!options .onto_name )
1909+ if (keep_base ) {
1910+ strbuf_reset (& buf );
1911+ strbuf_addstr (& buf , options .upstream_name );
1912+ strbuf_addstr (& buf , "..." );
1913+ options .onto_name = xstrdup (buf .buf );
1914+ } else if (!options .onto_name )
18801915 options .onto_name = options .upstream_name ;
18811916 if (strstr (options .onto_name , "..." )) {
1882- if (get_oid_mb (options .onto_name , & merge_base ) < 0 )
1883- die (_ ("'%s': need exactly one merge base" ),
1884- options .onto_name );
1917+ if (get_oid_mb (options .onto_name , & merge_base ) < 0 ) {
1918+ if (keep_base )
1919+ die (_ ("'%s': need exactly one merge base with branch" ),
1920+ options .upstream_name );
1921+ else
1922+ die (_ ("'%s': need exactly one merge base" ),
1923+ options .onto_name );
1924+ }
18851925 options .onto = lookup_commit_or_die (& merge_base ,
18861926 options .onto_name );
18871927 } else {
@@ -2016,13 +2056,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
20162056
20172057 /*
20182058 * Check if we are already based on onto with linear history,
2019- * but this should be done only when upstream and onto are the same
2020- * and if this is not an interactive rebase.
2059+ * in which case we could fast-forward without replacing the commits
2060+ * with new commits recreated by replaying their changes. This
2061+ * optimization must not be done if this is an interactive rebase.
20212062 */
2022- if (can_fast_forward (options .onto , & options .orig_head , & merge_base ) &&
2023- !is_interactive (& options ) && !options .restrict_revision &&
2024- options .upstream &&
2025- !oidcmp (& options .upstream -> object .oid , & options .onto -> object .oid )) {
2063+ if (can_fast_forward (options .onto , options .upstream , options .restrict_revision ,
2064+ & options .orig_head , & merge_base ) &&
2065+ !is_interactive (& options )) {
20262066 int flag ;
20272067
20282068 if (!(options .flags & REBASE_FORCE )) {
0 commit comments