Skip to content

Commit 6c55fbf

Browse files
committed
transports: local: fix assert when fetching into repo with symrefs
When fetching into a repository which has symbolic references via the "local" transport we run into an assert. The assert is being triggered while we negotiate the packfile between the two repositories. When hiding known revisions from the packbuilder revwalk, we unconditionally hide all references of the local refdb. In case one of these references is a symbolic reference, though, this means we're trying to hide a `NULL` OID, which triggers the assert. Fix the issue by only hiding OID references from the revwalk. Add a test to catch this issue in the future.
1 parent 0eca423 commit 6c55fbf

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

src/transports/local.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,8 +510,12 @@ static int local_counting(int stage, unsigned int current, unsigned int total, v
510510
static int foreach_reference_cb(git_reference *reference, void *payload)
511511
{
512512
git_revwalk *walk = (git_revwalk *)payload;
513+
int error;
514+
515+
if (git_reference_type(reference) != GIT_REF_OID)
516+
return 0;
513517

514-
int error = git_revwalk_hide(walk, git_reference_target(reference));
518+
error = git_revwalk_hide(walk, git_reference_target(reference));
515519
/* The reference is in the local repository, so the target may not
516520
* exist on the remote. It also may not be a commit. */
517521
if (error == GIT_ENOTFOUND || error == GITERR_INVALID) {

tests/fetchhead/nonetwork.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,29 @@ void test_fetchhead_nonetwork__unborn_with_upstream(void)
343343
cl_fixture_cleanup("./repowithunborn");
344344
}
345345

346+
void test_fetchhead_nonetwork__fetch_into_repo_with_symrefs(void)
347+
{
348+
git_repository *repo;
349+
git_remote *remote;
350+
git_reference *symref;
351+
352+
repo = cl_git_sandbox_init("empty_standard_repo");
353+
354+
/*
355+
* Testing for a specific constellation where the repository has at
356+
* least one symbolic reference in its refdb.
357+
*/
358+
cl_git_pass(git_reference_symbolic_create(&symref, repo, "refs/heads/symref", "refs/heads/master", 0, NULL));
359+
360+
cl_git_pass(git_remote_set_url(repo, "origin", cl_fixture("testrepo.git")));
361+
cl_git_pass(git_remote_lookup(&remote, repo, "origin"));
362+
cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL));
363+
364+
git_remote_free(remote);
365+
git_reference_free(symref);
366+
cl_git_sandbox_cleanup();
367+
}
368+
346369
void test_fetchhead_nonetwork__quote_in_branch_name(void)
347370
{
348371
cl_set_cleanup(&cleanup_repository, "./test1");

0 commit comments

Comments
 (0)