mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
![Johan Herland](/assets/img/avatar_default.png)
The current code for validating tracking branches (e.g. the argument to the -t/--track option) hardcodes refs/heads/* and refs/remotes/* as the potential locations for tracking branches. This works with the refspecs created by "git clone" or "git remote add", but is suboptimal in other cases: - If "refs/remotes/foo/bar" exists without any association to a remote (i.e. there is no remote named "foo", or no remote with a refspec that matches "refs/remotes/foo/bar"), then it is impossible to set up a valid upstream config that tracks it. Currently, the code defaults to using "refs/remotes/foo/bar" from repo "." as the upstream, which works, but is probably not what the user had in mind when running "git branch baz --track foo/bar". - If the user has tweaked the fetch refspec for a remote to put its remote-tracking branches outside of refs/remotes/*, e.g. by running git config remote.foo.fetch "+refs/heads/*:refs/foo_stuff/*" then the current code will refuse to use its remote-tracking branches as --track arguments, since they do not match refs/remotes/*. This patch removes the "refs/remotes/*" requirement for upstream branches, and replaces it with explicit checking of the refspecs for each remote to determine whether a given --track argument is a valid remote-tracking branch. This solves both of the above problems, since the matching refspec guarantees that there is a both a remote name and a remote branch name that can be used for the upstream config. However, this means that refs located within refs/remotes/* without a corresponding remote/refspec will no longer be usable as upstreams. The few existing tests which depended on this behavioral quirk has already been fixed in the preceding patches. This patch fixes the last remaining test failure in t2024-checkout-dwim. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
168 lines
4.1 KiB
Bash
Executable file
168 lines
4.1 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
test_description='checkout <branch>
|
|
|
|
Ensures that checkout on an unborn branch does what the user expects'
|
|
|
|
. ./test-lib.sh
|
|
|
|
# Is the current branch "refs/heads/$1"?
|
|
test_branch () {
|
|
printf "%s\n" "refs/heads/$1" >expect.HEAD &&
|
|
git symbolic-ref HEAD >actual.HEAD &&
|
|
test_cmp expect.HEAD actual.HEAD
|
|
}
|
|
|
|
# Is branch "refs/heads/$1" set to pull from "$2/$3"?
|
|
test_branch_upstream () {
|
|
printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
|
|
{
|
|
git config "branch.$1.remote" &&
|
|
git config "branch.$1.merge"
|
|
} >actual.upstream &&
|
|
test_cmp expect.upstream actual.upstream
|
|
}
|
|
|
|
test_expect_success 'setup' '
|
|
test_commit my_master &&
|
|
git init repo_a &&
|
|
(
|
|
cd repo_a &&
|
|
test_commit a_master &&
|
|
git checkout -b foo &&
|
|
test_commit a_foo &&
|
|
git checkout -b bar &&
|
|
test_commit a_bar
|
|
) &&
|
|
git init repo_b &&
|
|
(
|
|
cd repo_b &&
|
|
test_commit b_master &&
|
|
git checkout -b foo &&
|
|
test_commit b_foo &&
|
|
git checkout -b baz &&
|
|
test_commit b_baz
|
|
) &&
|
|
git remote add repo_a repo_a &&
|
|
git remote add repo_b repo_b &&
|
|
git config remote.repo_b.fetch \
|
|
"+refs/heads/*:refs/remotes/other_b/*" &&
|
|
git fetch --all
|
|
'
|
|
|
|
test_expect_success 'checkout of non-existing branch fails' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D xyzzy &&
|
|
|
|
test_must_fail git checkout xyzzy &&
|
|
test_must_fail git rev-parse --verify refs/heads/xyzzy &&
|
|
test_branch master
|
|
'
|
|
|
|
test_expect_success 'checkout of branch from multiple remotes fails #1' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D foo &&
|
|
|
|
test_must_fail git checkout foo &&
|
|
test_must_fail git rev-parse --verify refs/heads/foo &&
|
|
test_branch master
|
|
'
|
|
|
|
test_expect_success 'checkout of branch from a single remote succeeds #1' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D bar &&
|
|
|
|
git checkout bar &&
|
|
test_branch bar &&
|
|
test_cmp_rev remotes/repo_a/bar HEAD &&
|
|
test_branch_upstream bar repo_a bar
|
|
'
|
|
|
|
test_expect_success 'checkout of branch from a single remote succeeds #2' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D baz &&
|
|
|
|
git checkout baz &&
|
|
test_branch baz &&
|
|
test_cmp_rev remotes/other_b/baz HEAD &&
|
|
test_branch_upstream baz repo_b baz
|
|
'
|
|
|
|
test_expect_success '--no-guess suppresses branch auto-vivification' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D bar &&
|
|
|
|
test_must_fail git checkout --no-guess bar &&
|
|
test_must_fail git rev-parse --verify refs/heads/bar &&
|
|
test_branch master
|
|
'
|
|
|
|
test_expect_success 'setup more remotes with unconventional refspecs' '
|
|
git checkout -B master &&
|
|
git init repo_c &&
|
|
(
|
|
cd repo_c &&
|
|
test_commit c_master &&
|
|
git checkout -b bar &&
|
|
test_commit c_bar
|
|
git checkout -b spam &&
|
|
test_commit c_spam
|
|
) &&
|
|
git init repo_d &&
|
|
(
|
|
cd repo_d &&
|
|
test_commit d_master &&
|
|
git checkout -b baz &&
|
|
test_commit f_baz
|
|
git checkout -b eggs &&
|
|
test_commit c_eggs
|
|
) &&
|
|
git remote add repo_c repo_c &&
|
|
git config remote.repo_c.fetch \
|
|
"+refs/heads/*:refs/remotes/extra_dir/repo_c/extra_dir/*" &&
|
|
git remote add repo_d repo_d &&
|
|
git config remote.repo_d.fetch \
|
|
"+refs/heads/*:refs/repo_d/*" &&
|
|
git fetch --all
|
|
'
|
|
|
|
test_expect_success 'checkout of branch from multiple remotes fails #2' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D bar &&
|
|
|
|
test_must_fail git checkout bar &&
|
|
test_must_fail git rev-parse --verify refs/heads/bar &&
|
|
test_branch master
|
|
'
|
|
|
|
test_expect_success 'checkout of branch from multiple remotes fails #3' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D baz &&
|
|
|
|
test_must_fail git checkout baz &&
|
|
test_must_fail git rev-parse --verify refs/heads/baz &&
|
|
test_branch master
|
|
'
|
|
|
|
test_expect_success 'checkout of branch from a single remote succeeds #3' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D spam &&
|
|
|
|
git checkout spam &&
|
|
test_branch spam &&
|
|
test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
|
|
test_branch_upstream spam repo_c spam
|
|
'
|
|
|
|
test_expect_success 'checkout of branch from a single remote succeeds #4' '
|
|
git checkout -B master &&
|
|
test_might_fail git branch -D eggs &&
|
|
|
|
git checkout eggs &&
|
|
test_branch eggs &&
|
|
test_cmp_rev refs/repo_d/eggs HEAD &&
|
|
test_branch_upstream eggs repo_d eggs
|
|
'
|
|
|
|
test_done
|