git-branch --track: fix tracking branch computation.
The original code did not take hierarchical branch names into account at all. Tested-by: Gerrit Pape <pape@smarden.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
@ -317,8 +317,6 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev)
|
|||||||
static char *config_repo;
|
static char *config_repo;
|
||||||
static char *config_remote;
|
static char *config_remote;
|
||||||
static const char *start_ref;
|
static const char *start_ref;
|
||||||
static int start_len;
|
|
||||||
static int base_len;
|
|
||||||
|
|
||||||
static int get_remote_branch_name(const char *value)
|
static int get_remote_branch_name(const char *value)
|
||||||
{
|
{
|
||||||
@ -334,26 +332,41 @@ static int get_remote_branch_name(const char *value)
|
|||||||
|
|
||||||
end = value + strlen(value);
|
end = value + strlen(value);
|
||||||
|
|
||||||
/* Try an exact match first. */
|
/*
|
||||||
|
* Try an exact match first. I.e. handle the case where the
|
||||||
|
* value is "$anything:refs/foo/bar/baz" and start_ref is exactly
|
||||||
|
* "refs/foo/bar/baz". Then the name at the remote is $anything.
|
||||||
|
*/
|
||||||
if (!strcmp(colon + 1, start_ref)) {
|
if (!strcmp(colon + 1, start_ref)) {
|
||||||
/* Truncate the value before the colon. */
|
/* Truncate the value before the colon. */
|
||||||
nfasprintf(&config_repo, "%.*s", colon - value, value);
|
nfasprintf(&config_repo, "%.*s", colon - value, value);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try with a wildcard match now. */
|
/*
|
||||||
if (end - value > 2 && end[-2] == '/' && end[-1] == '*' &&
|
* Is this a wildcard match?
|
||||||
colon - value > 2 && colon[-2] == '/' && colon[-1] == '*' &&
|
*/
|
||||||
(end - 2) - (colon + 1) == base_len &&
|
if ((end - 2 <= value) || end[-2] != '/' || end[-1] != '*' ||
|
||||||
!strncmp(colon + 1, start_ref, base_len)) {
|
(colon - 2 <= value) || colon[-2] != '/' || colon[-1] != '*')
|
||||||
/* Replace the star with the remote branch name. */
|
return 0;
|
||||||
nfasprintf(&config_repo, "%.*s%s",
|
|
||||||
(colon - 2) - value, value,
|
|
||||||
start_ref + base_len);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
/*
|
||||||
|
* Value is "refs/foo/bar/<asterisk>:refs/baz/boa/<asterisk>"
|
||||||
|
* and start_ref begins with "refs/baz/boa/"; the name at the
|
||||||
|
* remote is refs/foo/bar/ with the remaining part of the
|
||||||
|
* start_ref. The length of the prefix on the RHS is (end -
|
||||||
|
* colon - 2), including the slash immediately before the
|
||||||
|
* asterisk.
|
||||||
|
*/
|
||||||
|
if ((strlen(start_ref) < end - colon - 2) ||
|
||||||
|
memcmp(start_ref, colon + 1, end - colon - 2))
|
||||||
|
return 0; /* does not match prefix */
|
||||||
|
|
||||||
|
/* Replace the asterisk with the remote branch name. */
|
||||||
|
nfasprintf(&config_repo, "%.*s%s",
|
||||||
|
(colon - 1) - value, value,
|
||||||
|
start_ref + (end - colon - 2));
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_remote_config(const char *key, const char *value)
|
static int get_remote_config(const char *key, const char *value)
|
||||||
@ -363,10 +376,12 @@ static int get_remote_config(const char *key, const char *value)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var = strrchr(key, '.');
|
var = strrchr(key, '.');
|
||||||
if (var == key + 6)
|
if (var == key + 6 || strcmp(var, ".fetch"))
|
||||||
return 0;
|
return 0;
|
||||||
|
/*
|
||||||
if (!strcmp(var, ".fetch") && get_remote_branch_name(value))
|
* Ok, we are looking at key == "remote.$foo.fetch";
|
||||||
|
*/
|
||||||
|
if (get_remote_branch_name(value))
|
||||||
nfasprintf(&config_remote, "%.*s", var - (key + 7), key + 7);
|
nfasprintf(&config_remote, "%.*s", var - (key + 7), key + 7);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -392,14 +407,14 @@ static void set_branch_merge(const char *name, const char *config_remote,
|
|||||||
|
|
||||||
static void set_branch_defaults(const char *name, const char *real_ref)
|
static void set_branch_defaults(const char *name, const char *real_ref)
|
||||||
{
|
{
|
||||||
const char *slash = strrchr(real_ref, '/');
|
/*
|
||||||
|
* name is the name of new branch under refs/heads;
|
||||||
if (!slash)
|
* real_ref is typically refs/remotes/$foo/$bar, where
|
||||||
return;
|
* $foo is the remote name (there typically are no slashes)
|
||||||
|
* and $bar is the branch name we map from the remote
|
||||||
|
* (it could have slashes).
|
||||||
|
*/
|
||||||
start_ref = real_ref;
|
start_ref = real_ref;
|
||||||
start_len = strlen(real_ref);
|
|
||||||
base_len = slash - real_ref;
|
|
||||||
git_config(get_remote_config);
|
git_config(get_remote_config);
|
||||||
if (!config_repo && !config_remote &&
|
if (!config_repo && !config_remote &&
|
||||||
!prefixcmp(real_ref, "refs/heads/")) {
|
!prefixcmp(real_ref, "refs/heads/")) {
|
||||||
|
@ -136,8 +136,8 @@ test_expect_success 'test tracking setup (non-wildcard, not matching)' \
|
|||||||
git-config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
|
git-config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
|
||||||
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
||||||
git-branch --track my5 local/master &&
|
git-branch --track my5 local/master &&
|
||||||
! test $(git-config branch.my5.remote) = local &&
|
! test "$(git-config branch.my5.remote)" = local &&
|
||||||
! test $(git-config branch.my5.merge) = refs/heads/master'
|
! test "$(git-config branch.my5.merge)" = refs/heads/master'
|
||||||
|
|
||||||
test_expect_success 'test tracking setup via config' \
|
test_expect_success 'test tracking setup via config' \
|
||||||
'git-config branch.autosetupmerge true &&
|
'git-config branch.autosetupmerge true &&
|
||||||
@ -155,14 +155,22 @@ test_expect_success 'test overriding tracking setup via --no-track' \
|
|||||||
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
||||||
git-branch --no-track my2 local/master &&
|
git-branch --no-track my2 local/master &&
|
||||||
git-config branch.autosetupmerge false &&
|
git-config branch.autosetupmerge false &&
|
||||||
! test $(git-config branch.my2.remote) = local &&
|
! test "$(git-config branch.my2.remote)" = local &&
|
||||||
! test $(git-config branch.my2.merge) = refs/heads/master'
|
! test "$(git-config branch.my2.merge)" = refs/heads/master'
|
||||||
|
|
||||||
test_expect_success 'test local tracking setup' \
|
test_expect_success 'test local tracking setup' \
|
||||||
'git branch --track my6 s &&
|
'git branch --track my6 s &&
|
||||||
test $(git-config branch.my6.remote) = . &&
|
test $(git-config branch.my6.remote) = . &&
|
||||||
test $(git-config branch.my6.merge) = refs/heads/s'
|
test $(git-config branch.my6.merge) = refs/heads/s'
|
||||||
|
|
||||||
|
test_expect_success 'test tracking setup via --track but deeper' \
|
||||||
|
'git-config remote.local.url . &&
|
||||||
|
git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
|
||||||
|
(git-show-ref -q refs/remotes/local/o/o || git-fetch local) &&
|
||||||
|
git-branch --track my7 local/o/o &&
|
||||||
|
test "$(git-config branch.my7.remote)" = local &&
|
||||||
|
test "$(git-config branch.my7.merge)" = refs/heads/o/o'
|
||||||
|
|
||||||
# Keep this test last, as it changes the current branch
|
# Keep this test last, as it changes the current branch
|
||||||
cat >expect <<EOF
|
cat >expect <<EOF
|
||||||
0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
|
0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
|
||||||
|
Reference in New Issue
Block a user