diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 9da4647061..262fb01aec 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -215,9 +215,10 @@ leave out at most one of A and B, in which case it defaults to HEAD. --keep-base:: Set the starting point at which to create the new commits to the - merge base of . Running + merge base of and . Running 'git rebase --keep-base ' is equivalent to - running 'git rebase --onto ... '. + running + 'git rebase --onto ... '. + This option is useful in the case where one is developing a feature on top of an upstream branch. While the feature is being worked on, the diff --git a/builtin/rebase.c b/builtin/rebase.c index 27fde7bf28..7f3bffc0a2 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1583,33 +1583,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) options.upstream_arg = "--root"; } - /* Make sure the branch to rebase onto is valid. */ - if (keep_base) { - strbuf_reset(&buf); - strbuf_addstr(&buf, options.upstream_name); - strbuf_addstr(&buf, "..."); - options.onto_name = xstrdup(buf.buf); - } else if (!options.onto_name) - options.onto_name = options.upstream_name; - if (strstr(options.onto_name, "...")) { - if (get_oid_mb(options.onto_name, &merge_base) < 0) { - if (keep_base) - die(_("'%s': need exactly one merge base with branch"), - options.upstream_name); - else - die(_("'%s': need exactly one merge base"), - options.onto_name); - } - options.onto = lookup_commit_or_die(&merge_base, - options.onto_name); - } else { - options.onto = - lookup_commit_reference_by_name(options.onto_name); - if (!options.onto) - die(_("Does not point to a valid commit '%s'"), - options.onto_name); - } - /* * If the branch to rebase is given, that is the branch we will rebase * branch_name -- branch/commit being rebased, or @@ -1659,6 +1632,34 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } else BUG("unexpected number of arguments left to parse"); + /* Make sure the branch to rebase onto is valid. */ + if (keep_base) { + strbuf_reset(&buf); + strbuf_addstr(&buf, options.upstream_name); + strbuf_addstr(&buf, "..."); + strbuf_addstr(&buf, branch_name); + options.onto_name = xstrdup(buf.buf); + } else if (!options.onto_name) + options.onto_name = options.upstream_name; + if (strstr(options.onto_name, "...")) { + if (get_oid_mb(options.onto_name, &merge_base) < 0) { + if (keep_base) + die(_("'%s': need exactly one merge base with branch"), + options.upstream_name); + else + die(_("'%s': need exactly one merge base"), + options.onto_name); + } + options.onto = lookup_commit_or_die(&merge_base, + options.onto_name); + } else { + options.onto = + lookup_commit_reference_by_name(options.onto_name); + if (!options.onto) + die(_("Does not point to a valid commit '%s'"), + options.onto_name); + } + if (options.fork_point > 0) { struct commit *head = lookup_commit_reference(the_repository, diff --git a/t/t3416-rebase-onto-threedots.sh b/t/t3416-rebase-onto-threedots.sh index 3716a42e81..3e04802cb0 100755 --- a/t/t3416-rebase-onto-threedots.sh +++ b/t/t3416-rebase-onto-threedots.sh @@ -129,6 +129,20 @@ test_expect_success 'rebase --keep-base main from topic' ' test_cmp expect actual ' +test_expect_success 'rebase --keep-base main topic from main' ' + git checkout main && + git branch -f topic G && + + git rebase --keep-base main topic && + git rev-parse C >base.expect && + git merge-base main HEAD >base.actual && + test_cmp base.expect base.actual && + + git rev-parse HEAD~2 >actual && + git rev-parse C^0 >expect && + test_cmp expect actual +' + test_expect_success 'rebase --keep-base main from side' ' git reset --hard && git checkout side && @@ -153,6 +167,21 @@ test_expect_success 'rebase -i --keep-base main from topic' ' test_cmp expect actual ' +test_expect_success 'rebase -i --keep-base main topic from main' ' + git checkout main && + git branch -f topic G && + + set_fake_editor && + EXPECT_COUNT=2 git rebase -i --keep-base main topic && + git rev-parse C >base.expect && + git merge-base main HEAD >base.actual && + test_cmp base.expect base.actual && + + git rev-parse HEAD~2 >actual && + git rev-parse C^0 >expect && + test_cmp expect actual +' + test_expect_success 'rebase -i --keep-base main from side' ' git reset --hard && git checkout side &&