git_reference_next_name must match git_reference_next The git_reference_next API silently skips invalid references when scanning the loose refs. The git_reference_next_name API should skip the same ones even though it isn't creating the reference object. This adds a test with a an invalid loose reference and makes sure that both APIs skip the same entries and generate the same results.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index b9e283a..2f1a5b2 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -452,6 +452,9 @@ static int loose_lookup(
git_buf ref_file = GIT_BUF_INIT;
int error = 0;
+ if (out)
+ *out = NULL;
+
error = reference_read(&ref_file, NULL, backend->path, ref_name, NULL);
if (error < 0)
@@ -465,15 +468,17 @@ static int loose_lookup(
goto done;
}
- *out = git_reference__alloc_symbolic(ref_name, target);
+ if (out)
+ *out = git_reference__alloc_symbolic(ref_name, target);
} else {
if ((error = loose_parse_oid(&oid, ref_name, &ref_file)) < 0)
goto done;
- *out = git_reference__alloc(ref_name, &oid, NULL);
+ if (out)
+ *out = git_reference__alloc(ref_name, &oid, NULL);
}
- if (*out == NULL)
+ if (out && *out == NULL)
error = -1;
done:
@@ -679,6 +684,11 @@ static int refdb_fs_backend__iterator_next_name(
if (git_strmap_exists(packfile, path))
continue;
+ if (loose_lookup(NULL, backend, path) != 0) {
+ giterr_clear();
+ continue;
+ }
+
*out = path;
return 0;
}
diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c
index e827762..7c2fc00 100644
--- a/tests-clar/revwalk/basic.c
+++ b/tests-clar/revwalk/basic.c
@@ -142,6 +142,28 @@ void test_revwalk_basic__glob_heads(void)
cl_assert(i == 14);
}
+void test_revwalk_basic__glob_heads_with_invalid(void)
+{
+ int i;
+ git_oid oid;
+
+ test_revwalk_basic__cleanup();
+
+ _repo = cl_git_sandbox_init("testrepo");
+ cl_git_mkfile("testrepo/.git/refs/heads/garbage", "not-a-ref");
+
+ cl_git_pass(git_revwalk_new(&_walk, _repo));
+ cl_git_pass(git_revwalk_push_glob(_walk, "heads"));
+
+ for (i = 0; !git_revwalk_next(&oid, _walk); ++i)
+ /* walking */;
+
+ /* git log --branches --oneline | wc -l => 16 */
+ cl_assert_equal_i(16, i);
+
+ cl_fixture_cleanup("testrepo");
+}
+
void test_revwalk_basic__push_head(void)
{
int i = 0;