Merge branch 'dl/branch-from-3dot-merge-base'

"git branch new A...B" and "git checkout -b new A...B" have been
taught that in their contexts, the notation A...B means "the merge
base between these two commits", just like "git checkout A...B"
detaches HEAD at that commit.

* dl/branch-from-3dot-merge-base:
  branch: make create_branch accept a merge base rev
  t2018: cleanup in current test
This commit is contained in:
Junio C Hamano 2019-05-19 16:45:28 +09:00
commit 4ac8371a1c
5 changed files with 50 additions and 32 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

@ -313,6 +313,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

@ -269,7 +269,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

@ -60,38 +60,47 @@ test_expect_success 'setup' '
' '
test_expect_success 'checkout -b to a new branch, set to HEAD' ' test_expect_success 'checkout -b to a new branch, set to HEAD' '
test_when_finished "
git checkout branch1 &&
test_might_fail git branch -D branch2" &&
do_checkout branch2 do_checkout branch2
' '
test_expect_success 'checkout -b to a new branch, set to an explicit ref' ' test_expect_success 'checkout -b to a merge base' '
git checkout branch1 && test_when_finished "
git branch -D branch2 && 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_when_finished "
git checkout branch1 &&
test_might_fail git branch -D branch2" &&
do_checkout branch2 $HEAD1 do_checkout branch2 $HEAD1
' '
test_expect_success 'checkout -b to a new branch with unmergeable changes fails' ' test_expect_success 'checkout -b to a new branch with unmergeable changes fails' '
git checkout branch1 &&
# clean up from previous test
git branch -D branch2 &&
setup_dirty_unmergeable && setup_dirty_unmergeable &&
test_must_fail do_checkout branch2 $HEAD1 && test_must_fail do_checkout branch2 $HEAD1 &&
test_dirty_unmergeable test_dirty_unmergeable
' '
test_expect_success 'checkout -f -b to a new branch with unmergeable changes discards changes' ' test_expect_success 'checkout -f -b to a new branch with unmergeable changes discards changes' '
test_when_finished "
git checkout branch1 &&
test_might_fail git branch -D branch2" &&
# still dirty and on branch1 # still dirty and on branch1
do_checkout branch2 $HEAD1 "-f -b" && do_checkout branch2 $HEAD1 "-f -b" &&
test_must_fail test_dirty_unmergeable test_must_fail test_dirty_unmergeable
' '
test_expect_success 'checkout -b to a new branch preserves mergeable changes' ' test_expect_success 'checkout -b to a new branch preserves mergeable changes' '
git checkout branch1 && test_when_finished "
git reset --hard &&
# clean up from previous test git checkout branch1 &&
git branch -D branch2 && test_might_fail git branch -D branch2" &&
setup_dirty_mergeable && setup_dirty_mergeable &&
do_checkout branch2 $HEAD1 && do_checkout branch2 $HEAD1 &&
@ -99,27 +108,18 @@ test_expect_success 'checkout -b to a new branch preserves mergeable changes' '
' '
test_expect_success 'checkout -f -b to a new branch with mergeable changes discards changes' ' test_expect_success 'checkout -f -b to a new branch with mergeable changes discards changes' '
# clean up from previous test test_when_finished git reset --hard HEAD &&
git reset --hard &&
git checkout branch1 &&
# clean up from previous test
git branch -D branch2 &&
setup_dirty_mergeable && setup_dirty_mergeable &&
do_checkout branch2 $HEAD1 "-f -b" && do_checkout branch2 $HEAD1 "-f -b" &&
test_must_fail test_dirty_mergeable test_must_fail test_dirty_mergeable
' '
test_expect_success 'checkout -b to an existing branch fails' ' test_expect_success 'checkout -b to an existing branch fails' '
git reset --hard HEAD && test_when_finished git reset --hard HEAD &&
test_must_fail do_checkout branch2 $HEAD2 test_must_fail do_checkout branch2 $HEAD2
' '
test_expect_success 'checkout -b to @{-1} fails with the right branch name' ' test_expect_success 'checkout -b to @{-1} fails with the right branch name' '
git reset --hard HEAD &&
git checkout branch1 && git checkout branch1 &&
git checkout branch2 && git checkout branch2 &&
echo >expect "fatal: A branch named '\''branch1'\'' already exists." && echo >expect "fatal: A branch named '\''branch1'\'' already exists." &&
@ -133,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) &&
@ -160,6 +166,7 @@ test_expect_success 'checkout -f -B to an existing branch with unmergeable chang
' '
test_expect_success 'checkout -B to an existing branch preserves mergeable changes' ' test_expect_success 'checkout -B to an existing branch preserves mergeable changes' '
test_when_finished git reset --hard &&
git checkout branch1 && git checkout branch1 &&
setup_dirty_mergeable && setup_dirty_mergeable &&
@ -168,9 +175,6 @@ test_expect_success 'checkout -B to an existing branch preserves mergeable chang
' '
test_expect_success 'checkout -f -B to an existing branch with mergeable changes discards changes' ' test_expect_success 'checkout -f -B to an existing branch with mergeable changes discards changes' '
# clean up from previous test
git reset --hard &&
git checkout branch1 && git checkout branch1 &&
setup_dirty_mergeable && setup_dirty_mergeable &&

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
' '
@ -316,8 +320,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
' '
@ -339,6 +343,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
@ -356,8 +361,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
' '
@ -381,6 +386,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