diff options
author | Shawn O. Pearce <spearce@spearce.org> | 2007-09-18 04:54:53 -0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2007-09-19 03:22:31 -0700 |
commit | 85682c1903a4ae776b0bf2d30d9ecd1e19689131 (patch) | |
tree | 1027268e54eadbbe07ceeddaf0cfc813b5361cd4 /builtin-fetch.c | |
parent | d8b3a2bf189a9e7fea76454157b77fa71c9abc05 (diff) | |
download | git-85682c1903a4ae776b0bf2d30d9ecd1e19689131.tar.gz |
Correct handling of branch.$name.merge in builtin-fetch
My prior bug fix for git-push titled "Don't configure remote "." to
fetch everything to itself" actually broke t5520 as we were unable
to evaluate a branch configuration of:
[branch "copy"]
remote = .
merge = refs/heads/master
as remote "." did not have a "remote...fetch" configuration entry to
offer up refs/heads/master as a possible candidate available to be
fetched and merged. In shell script git-fetch and prior to the above
mentioned commit this was hardcoded for a url of "." to be the set of
local branches.
Chasing down this bug led me to the conclusion that our prior behavior
with regards to branch.$name.merge was incorrect. In the shell script
based git-fetch implementation we only fetched and merged a branch if
it appeared both in branch.$name.merge *and* in remote.$r.fetch, where
$r = branch.$name.remote. In other words in the following config file:
[remote "origin"]
url = git://git.kernel.org/pub/scm/git/git.git
fetch = refs/heads/master:refs/remotes/origin/master
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "pu"]
remote = origin
merge = refs/heads/pu
Attempting to run `git pull` while on branch "pu" would always give
the user "Already up-to-date" as git-fetch did not fetch pu and thus
did not mark it for merge in .git/FETCH_HEAD. The configured merge
would always be ignored and the user would be left scratching her
confused head wondering why merge did not work on "pu" but worked
fine on "master".
If we are using the "default fetch" specification for the current
branch and the current branch has a branch.$name.merge configured
we now union it with the list of refs in remote.$r.fetch. This
way the above configuration does what the user expects it to do,
which is to fetch only "master" by default but when on "pu" to
fetch both "master" and "pu".
This uncovered some breakage in the test suite where old-style Cogito
branches (.git/branches/$r) did not fetch the branches listed in
.git/config for merging and thus did not actually merge them if the
user tried to use `git pull` on that branch. Junio and I discussed
it on list and felt that the union approach here makes more sense to
DWIM for the end-user than silently ignoring their configured request
so the test vectors for t5515 have been updated to include for-merge
lines in .git/FETCH_HEAD where they have been configured for-merge
in .git/config.
Since we are now performing a union of the fetch specification and
the merge specification and we cannot allow a branch to be listed
twice (otherwise it comes out twice in .git/FETCH_HEAD) we need to
perform a double loop here over all of the branch.$name.merge lines
and try to set their merge flag if we have already schedule that
branch for fetching by remote.$r.fetch. If no match is found then
we must add new specifications to fetch the branch but not store it
as no local tracking branch has been designated.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Diffstat (limited to 'builtin-fetch.c')
-rw-r--r-- | builtin-fetch.c | 48 |
1 files changed, 35 insertions, 13 deletions
diff --git a/builtin-fetch.c b/builtin-fetch.c index 20926e0543..670af0b53f 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -28,20 +28,37 @@ static void unlock_pack_on_signal(int signo) raise(signo); } -static void find_merge_config(struct ref *ref_map, struct remote *remote) +static void add_merge_config(struct ref **head, + struct ref *remote_refs, + struct branch *branch, + struct ref ***tail) { - struct ref *rm = ref_map; - struct branch *branch = branch_get(NULL); + int i; - for (rm = ref_map; rm; rm = rm->next) { - if (!branch_has_merge_config(branch)) { - if (remote && remote->fetch && - !strcmp(remote->fetch[0].src, rm->name)) - rm->merge = 1; - } else { - if (branch_merges(branch, rm->name)) + for (i = 0; i < branch->merge_nr; i++) { + struct ref *rm, **old_tail = *tail; + struct refspec refspec; + + for (rm = *head; rm; rm = rm->next) { + if (branch_merge_matches(branch, i, rm->name)) { rm->merge = 1; + break; + } } + if (rm) + continue; + + /* Not fetched to a tracking branch? We need to fetch + * it anyway to allow this branch's "branch.$name.merge" + * to be honored by git-pull. + */ + refspec.src = branch->merge[i]->src; + refspec.dst = NULL; + refspec.pattern = 0; + refspec.force = 0; + get_fetch_map(remote_refs, &refspec, tail); + for (rm = *old_tail; rm; rm = rm->next) + rm->merge = 1; } } @@ -76,17 +93,22 @@ static struct ref *get_ref_map(struct transport *transport, } else { /* Use the defaults */ struct remote *remote = transport->remote; - if (remote->fetch_refspec_nr) { + struct branch *branch = branch_get(NULL); + int has_merge = branch_has_merge_config(branch); + if (remote && (remote->fetch_refspec_nr || has_merge)) { for (i = 0; i < remote->fetch_refspec_nr; i++) { get_fetch_map(remote_refs, &remote->fetch[i], &tail); if (remote->fetch[i].dst && remote->fetch[i].dst[0]) *autotags = 1; + if (!i && !has_merge && ref_map && + !strcmp(remote->fetch[0].src, ref_map->name)) + ref_map->merge = 1; } - find_merge_config(ref_map, remote); + if (has_merge) + add_merge_config(&ref_map, remote_refs, branch, &tail); } else { ref_map = get_remote_ref(remote_refs, "HEAD"); - ref_map->merge = 1; } } |