branch: make create_branch accept a merge base rev

When we ran something like

    $ git checkout -b test master...

it would fail with the message

    fatal: Not a valid object name: 'master...'.

This was caused by the call to `create_branch` where `start_name` is
expected to be a valid rev. However, git-checkout allows the branch to
be a valid _merge base_ rev (i.e. with a "...") so it was possible for
an invalid rev to be passed in.

Make `create_branch` accept a merge base rev so that this case does not
error out.

As a side-effect, teach git-branch how to handle merge base revs as
well.

Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Denton Liu
2019-04-27 05:02:22 -07:00
committed by Junio C Hamano
parent 27434bf08c
commit e3d6539d58
5 changed files with 33 additions and 6 deletions

View File

@ -45,7 +45,11 @@ argument is missing it defaults to `HEAD` (i.e. the tip of the current
branch). branch).
The command's second form creates a new branch head named <branchname> The command's second form creates a new branch head named <branchname>
which points to the current `HEAD`, or <start-point> if given. which points to the current `HEAD`, or <start-point> if given. As a
special case, for <start-point>, you may use `"A...B"` as a shortcut for
the merge base of `A` and `B` if there is exactly one merge base. You
can leave out at most one of `A` and `B`, in which case it defaults to
`HEAD`.
Note that this will create the new branch, but it will not switch the Note that this will create the new branch, but it will not switch the
working tree to it; use "git checkout <newbranch>" to switch to the working tree to it; use "git checkout <newbranch>" to switch to the

View File

@ -301,6 +301,10 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
<start_point>:: <start_point>::
The name of a commit at which to start the new branch; see The name of a commit at which to start the new branch; see
linkgit:git-branch[1] for details. Defaults to HEAD. linkgit:git-branch[1] for details. Defaults to HEAD.
+
As a special case, you may use `"A...B"` as a shortcut for the
merge base of `A` and `B` if there is exactly one merge base. You can
leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
<tree-ish>:: <tree-ish>::
Tree to checkout from (when paths are given). If not specified, Tree to checkout from (when paths are given). If not specified,

View File

@ -268,7 +268,7 @@ void create_branch(struct repository *r,
} }
real_ref = NULL; real_ref = NULL;
if (get_oid(start_name, &oid)) { if (get_oid_mb(start_name, &oid)) {
if (explicit_tracking) { if (explicit_tracking) {
if (advice_set_upstream_failure) { if (advice_set_upstream_failure) {
error(_(upstream_missing), start_name); error(_(upstream_missing), start_name);

View File

@ -66,6 +66,13 @@ test_expect_success 'checkout -b to a new branch, set to HEAD' '
do_checkout branch2 do_checkout branch2
' '
test_expect_success 'checkout -b to a merge base' '
test_when_finished "
git checkout branch1 &&
test_might_fail git branch -D branch2" &&
git checkout -b branch2 branch1...
'
test_expect_success 'checkout -b to a new branch, set to an explicit ref' ' test_expect_success 'checkout -b to a new branch, set to an explicit ref' '
test_when_finished " test_when_finished "
git checkout branch1 && git checkout branch1 &&
@ -126,6 +133,12 @@ test_expect_success 'checkout -B to an existing branch resets branch to HEAD' '
do_checkout branch2 "" -B do_checkout branch2 "" -B
' '
test_expect_success 'checkout -B to a merge base' '
git checkout branch1 &&
git checkout -B branch2 branch1...
'
test_expect_success 'checkout -B to an existing branch from detached HEAD resets branch to HEAD' ' test_expect_success 'checkout -B to an existing branch from detached HEAD resets branch to HEAD' '
git checkout $(git rev-parse --verify HEAD) && git checkout $(git rev-parse --verify HEAD) &&

View File

@ -42,6 +42,10 @@ test_expect_success 'git branch a/b/c should create a branch' '
git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c
' '
test_expect_success 'git branch mb master... should create a branch' '
git branch mb master... && test_path_is_file .git/refs/heads/mb
'
test_expect_success 'git branch HEAD should fail' ' test_expect_success 'git branch HEAD should fail' '
test_must_fail git branch HEAD test_must_fail git branch HEAD
' '
@ -292,8 +296,8 @@ test_expect_success 'git branch --list -v with --abbrev' '
test_expect_success 'git branch --column' ' test_expect_success 'git branch --column' '
COLUMNS=81 git branch --column=column >actual && COLUMNS=81 git branch --column=column >actual &&
cat >expected <<\EOF && cat >expected <<\EOF &&
a/b/c bam foo l * master n o/p r a/b/c bam foo l * master mb o/o q
abc bar j/k m/m master2 o/o q abc bar j/k m/m master2 n o/p r
EOF EOF
test_cmp expected actual test_cmp expected actual
' '
@ -315,6 +319,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
m/m m/m
* master * master
master2 master2
mb
n n
o/o o/o
o/p o/p
@ -332,8 +337,8 @@ test_expect_success 'git branch with column.*' '
git config --unset column.branch && git config --unset column.branch &&
git config --unset column.ui && git config --unset column.ui &&
cat >expected <<\EOF && cat >expected <<\EOF &&
a/b/c bam foo l * master n o/p r a/b/c bam foo l * master mb o/o q
abc bar j/k m/m master2 o/o q abc bar j/k m/m master2 n o/p r
EOF EOF
test_cmp expected actual test_cmp expected actual
' '
@ -357,6 +362,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
m/m m/m
* master * master
master2 master2
mb
n n
o/o o/o
o/p o/p