connect.c, when processing packfiles, treats a zero ID (with `capabilities^{}` in place of the refname) as an actual ref instead of a placeholder for a capability declaration, contrary to the specification in Reference Discovery in Documentation/technical/pack-protocol.txt. This is an issue when interacting with Git implementations that follow this specification. For example, `ls-remote` (against a git:// repository served by such a Git implementation) will report a ref when there are none, and `clone` (against something similar) will fail its checkout. Make connect.c follow the specification with respect to this, while maintaining compatibility with existing implementations that do not serve the zero ID when a repository has no refs. (git-daemon should probably also be changed to serve zero IDs, but such a change can be considered independently from this change; even if both the client and server changes were made in one commit, it is nearly impossible that all Git installations are updated at the same time - an updated client would still need to deal with unupdated servers and vice versa.) The test uses JGit's daemon feature, which is specification-compliant. Signed-off-by: Jonathan Tan <jonathantanmy@xxxxxxxxxx> --- connect.c | 7 +++++++ t/t5512-ls-remote.sh | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/connect.c b/connect.c index 722dc3f..d4a58de 100644 --- a/connect.c +++ b/connect.c @@ -165,6 +165,13 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, continue; } + if (is_null_oid(&old_oid)) { + if (strcmp(name, "capabilities^{}")) + warning("zero object ID received that is not accompanied by a " + "capability declaration, ignoring and continuing anyway"); + continue; + } + if (!check_ref(name, flags)) continue; ref = alloc_ref(buffer + GIT_SHA1_HEXSZ + 1); diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 819b9dd..c6f8b6f 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -207,5 +207,27 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' ' test_cmp expect actual ' +test_lazy_prereq GIT_DAEMON ' + test_have_prereq JGIT && + test_tristate GIT_TEST_GIT_DAEMON && + test "$GIT_TEST_GIT_DAEMON" != false +' + +JGIT_DAEMON_PORT=${JGIT_DAEMON_PORT-${this_test#t}} + +# This test spawns a daemon, so run it only if the user would be OK with +# testing with git-daemon. +test_expect_success JGIT,GIT_DAEMON 'indicate no refs in standards-compliant empty remote' ' + JGIT_DAEMON_PID= && + git init --bare empty.git && + touch empty.git/git-daemon-export-ok && + { + jgit daemon --port="$JGIT_DAEMON_PORT" . & + JGIT_DAEMON_PID=$! + } && + test_when_finished kill "$JGIT_DAEMON_PID" && + sleep 1 && # allow jgit daemon some time to set up + test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git +' test_done -- 2.8.0.rc3.226.g39d4020