Skip to content

Commit 533e088

Browse files
peffgitster
authored andcommitted
upload-pack: strip namespace from symref data
Since 7171d8c (upload-pack: send symbolic ref information as capability, 2013-09-17), we've sent cloning and fetching clients special information about which branch HEAD is pointing to, so that they don't have to guess based on matching up commit ids. However, this feature has never worked properly with the GIT_NAMESPACE feature. Because upload-pack uses head_ref_namespaced(find_symref), we do find and report on refs/namespaces/foo/HEAD instead of the actual HEAD of the repo. This makes sense, since the branch pointed to by the top-level HEAD may not be advertised at all. But we do two things wrong: 1. We report the full name refs/namespaces/foo/HEAD, instead of just HEAD. Meaning no client is going to bother doing anything with that symref, since we're not otherwise advertising it. 2. We report the symref destination using its full name (e.g., refs/namespaces/foo/refs/heads/master). That's similarly useless to the client, who only saw "refs/heads/master" in the advertisement. We should be stripping the namespace prefix off of both places (which this patch fixes). Likely nobody noticed because we tend to do the right thing anyway. Bug (1) means that we said nothing about HEAD (just refs/namespace/foo/HEAD). And so the client half of the code, from a45b5f0 (connect: annotate refs with their symref information in get_remote_head(), 2013-09-17), does not annotate HEAD, and we use the fallback in guess_remote_head(), matching refs by object id. Which is usually right. It only falls down in ambiguous cases, like the one laid out in the included test. This also means that we don't have to worry about breaking anybody who was putting pre-stripped names into their namespace symrefs when we fix bug (2). Because of bug (1), nobody would have been using the symref we advertised in the first place (not to mention that those symrefs would have appeared broken for any non-namespaced access). Note that we have separate fixes here for the v0 and v2 protocols. The symref advertisement moved in v2 to be a part of the ls-refs command. This actually gets part (1) right, since the symref annotation piggy-backs on the existing ref advertisement, which is properly stripped. But it still needs a fix for part (2). The included tests cover both protocols. Reported-by: Bryan Turner <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent aeb582a commit 533e088

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

ls-refs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ static int send_ref(const char *refname, const struct object_id *oid,
5757
if (!symref_target)
5858
die("'%s' is a symref but it is not?", refname);
5959

60-
strbuf_addf(&refline, " symref-target:%s", symref_target);
60+
strbuf_addf(&refline, " symref-target:%s",
61+
strip_namespace(symref_target));
6162
}
6263

6364
if (data->peel) {

t/t5509-fetch-push-namespaces.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,32 @@ test_expect_success 'try to update a hidden full ref' '
124124
test_must_fail git -C original push pushee-namespaced master
125125
'
126126

127+
test_expect_success 'set up ambiguous HEAD' '
128+
git init ambiguous &&
129+
(
130+
cd ambiguous &&
131+
git commit --allow-empty -m foo &&
132+
git update-ref refs/namespaces/ns/refs/heads/one HEAD &&
133+
git update-ref refs/namespaces/ns/refs/heads/two HEAD &&
134+
git symbolic-ref refs/namespaces/ns/HEAD \
135+
refs/namespaces/ns/refs/heads/two
136+
)
137+
'
138+
139+
test_expect_success 'clone chooses correct HEAD (v0)' '
140+
GIT_NAMESPACE=ns git -c protocol.version=0 \
141+
clone ambiguous ambiguous-v0 &&
142+
echo refs/heads/two >expect &&
143+
git -C ambiguous-v0 symbolic-ref HEAD >actual &&
144+
test_cmp expect actual
145+
'
146+
147+
test_expect_success 'clone chooses correct HEAD (v2)' '
148+
GIT_NAMESPACE=ns git -c protocol.version=2 \
149+
clone ambiguous ambiguous-v2 &&
150+
echo refs/heads/two >expect &&
151+
git -C ambiguous-v2 symbolic-ref HEAD >actual &&
152+
test_cmp expect actual
153+
'
154+
127155
test_done

upload-pack.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,8 +1032,8 @@ static int find_symref(const char *refname, const struct object_id *oid,
10321032
symref_target = resolve_ref_unsafe(refname, 0, NULL, &flag);
10331033
if (!symref_target || (flag & REF_ISSYMREF) == 0)
10341034
die("'%s' is a symref but it is not?", refname);
1035-
item = string_list_append(cb_data, refname);
1036-
item->util = xstrdup(symref_target);
1035+
item = string_list_append(cb_data, strip_namespace(refname));
1036+
item->util = xstrdup(strip_namespace(symref_target));
10371037
return 0;
10381038
}
10391039

0 commit comments

Comments
 (0)