Skip to content

Commit 33cae54

Browse files
glandiumgitster
authored andcommitted
transport-helper: do not request symbolic refs to remote helpers
A typical remote helper will return a `list` of refs containing a symbolic ref HEAD, pointing to, e.g. refs/heads/master. In the case of a clone, all the refs are being requested through `fetch` or `import`, including the symbolic ref. While this works properly, in some cases of a fetch, like `git fetch url` or `git fetch origin HEAD`, or any fetch command involving a symbolic ref without also fetching the corresponding ref it points to, the fetch command fails with: fatal: bad object 0000000000000000000000000000000000000000 error: <remote> did not send all necessary objects (in the case the remote helper returned '?' values to the `list` command). This is because there is only one ref given to fetch(), and it's not further resolved to something at the end of fetch_with_import(). While this can be somehow handled in the remote helper itself, by adding a refspec for the symbolic ref, and storing an explicit ref in a private namespace, and then handling the `import` for that symbolic ref specifically, very few existing remote helpers are actually doing that. So, instead of requesting the exact list of wanted refs to remote helpers, treat symbolic refs differently and request the ref they point to instead. Then, resolve the symbolic refs values based on the pointed ref. This assumes there is no more than one level of indirection (a symbolic ref doesn't point to another symbolic ref). Signed-off-by: Mike Hommey <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 627736c commit 33cae54

File tree

3 files changed

+39
-6
lines changed

3 files changed

+39
-6
lines changed

git-remote-testgit.sh

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
#!/bin/sh
22
# Copyright (c) 2012 Felipe Contreras
33

4-
alias=$1
4+
# The first argument can be a url when the fetch/push command was a url
5+
# instead of a configured remote. In this case, use a generic alias.
6+
if test "$1" = "testgit::$2"; then
7+
alias=_
8+
else
9+
alias=$1
10+
fi
511
url=$2
612

713
dir="$GIT_DIR/testgit/$alias"

t/t5801-remote-helpers.sh

+24
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,28 @@ test_expect_success 'push messages' '
281281
)
282282
'
283283

284+
test_expect_success 'fetch HEAD' '
285+
(cd server &&
286+
git checkout master &&
287+
echo more >>file &&
288+
git commit -a -m more
289+
) &&
290+
(cd local &&
291+
git fetch origin HEAD
292+
) &&
293+
compare_refs server HEAD local FETCH_HEAD
294+
'
295+
296+
test_expect_success 'fetch url' '
297+
(cd server &&
298+
git checkout master &&
299+
echo more >>file &&
300+
git commit -a -m more
301+
) &&
302+
(cd local &&
303+
git fetch "testgit::${PWD}/../server"
304+
) &&
305+
compare_refs server HEAD local FETCH_HEAD
306+
'
307+
284308
test_done

transport-helper.c

+8-5
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,8 @@ static int fetch_with_fetch(struct transport *transport,
356356
continue;
357357

358358
strbuf_addf(&buf, "fetch %s %s\n",
359-
sha1_to_hex(posn->old_sha1), posn->name);
359+
sha1_to_hex(posn->old_sha1),
360+
posn->symref ? posn->symref : posn->name);
360361
}
361362

362363
strbuf_addch(&buf, '\n');
@@ -454,7 +455,8 @@ static int fetch_with_import(struct transport *transport,
454455
if (posn->status & REF_STATUS_UPTODATE)
455456
continue;
456457

457-
strbuf_addf(&buf, "import %s\n", posn->name);
458+
strbuf_addf(&buf, "import %s\n",
459+
posn->symref ? posn->symref : posn->name);
458460
sendline(data, &buf);
459461
strbuf_reset(&buf);
460462
}
@@ -487,14 +489,15 @@ static int fetch_with_import(struct transport *transport,
487489
* fast-forward or this is a forced update.
488490
*/
489491
for (i = 0; i < nr_heads; i++) {
490-
char *private;
492+
char *private, *name;
491493
posn = to_fetch[i];
492494
if (posn->status & REF_STATUS_UPTODATE)
493495
continue;
496+
name = posn->symref ? posn->symref : posn->name;
494497
if (data->refspecs)
495-
private = apply_refspecs(data->refspecs, data->refspec_nr, posn->name);
498+
private = apply_refspecs(data->refspecs, data->refspec_nr, name);
496499
else
497-
private = xstrdup(posn->name);
500+
private = xstrdup(name);
498501
if (private) {
499502
read_ref(private, posn->old_sha1);
500503
free(private);

0 commit comments

Comments
 (0)