]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs/files: perform consistency checks for root refs
authorPatrick Steinhardt <ps@pks.im>
Mon, 12 Jan 2026 09:02:56 +0000 (10:02 +0100)
committerJunio C Hamano <gitster@pobox.com>
Mon, 12 Jan 2026 14:55:40 +0000 (06:55 -0800)
While the "files" backend already knows to perform consistency checks
for the "refs/" hierarchy, it doesn't verify any of its root refs. Plug
this omission.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs/files-backend.c
t/t0602-reffiles-fsck.sh

index abc21653395b132a577977f56275b6a2ec289ad9..9ae80b700aa315b28235614f355a52b997a5a24e 100644 (file)
@@ -3877,9 +3877,9 @@ static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
        if (filename[0] != '.' && ends_with(filename, ".lock"))
                goto cleanup;
 
-       /*
-        * This works right now because we never check the root refs.
-        */
+       if (is_root_ref(refname))
+               goto cleanup;
+
        if (check_refname_format(refname, 0)) {
                struct fsck_ref_report report = { 0 };
 
@@ -3974,19 +3974,63 @@ out:
        return ret;
 }
 
+struct files_fsck_root_ref_data {
+       struct files_ref_store *refs;
+       struct fsck_options *o;
+       struct worktree *wt;
+       struct strbuf refname;
+       struct strbuf path;
+};
+
+static int files_fsck_root_ref(const char *refname, void *cb_data)
+{
+       struct files_fsck_root_ref_data *data = cb_data;
+       struct stat st;
+
+       strbuf_reset(&data->refname);
+       if (!is_main_worktree(data->wt))
+               strbuf_addf(&data->refname, "worktrees/%s/", data->wt->id);
+       strbuf_addstr(&data->refname, refname);
+
+       strbuf_reset(&data->path);
+       strbuf_addf(&data->path, "%s/%s", data->refs->gitcommondir, data->refname.buf);
+
+       if (stat(data->path.buf, &st)) {
+               if (errno == ENOENT)
+                       return 0;
+               return error_errno("failed to read ref: '%s'", data->path.buf);
+       }
+
+       return files_fsck_ref(&data->refs->base, data->o, data->refname.buf,
+                             data->path.buf, st.st_mode);
+}
+
 static int files_fsck(struct ref_store *ref_store,
                      struct fsck_options *o,
                      struct worktree *wt)
 {
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_READ, "fsck");
+       struct files_fsck_root_ref_data data = {
+               .refs = refs,
+               .o = o,
+               .wt = wt,
+               .refname = STRBUF_INIT,
+               .path = STRBUF_INIT,
+       };
        int ret = 0;
 
        if (files_fsck_refs_dir(ref_store, o, wt) < 0)
                ret = -1;
+
+       if (for_each_root_ref(refs, files_fsck_root_ref, &data) < 0)
+               ret = -1;
+
        if (refs->packed_ref_store->be->fsck(refs->packed_ref_store, o, wt) < 0)
                ret = -1;
 
+       strbuf_release(&data.refname);
+       strbuf_release(&data.path);
        return ret;
 }
 
index 0ef483659d561f737b8d27716e098d148fb7ac92..479f3d528e6ca82ae802112cd197d47df8a9c141 100755 (executable)
@@ -905,4 +905,34 @@ test_expect_success '--[no-]references option should apply to fsck' '
        )
 '
 
+test_expect_success 'complains about broken root ref' '
+       test_when_finished "rm -rf repo" &&
+       git init repo &&
+       (
+               cd repo &&
+               echo "ref: refs/../HEAD" >.git/HEAD &&
+               test_must_fail git refs verify 2>err &&
+               cat >expect <<-EOF &&
+               error: HEAD: badReferentName: points to invalid refname ${SQ}refs/../HEAD${SQ}
+               EOF
+               test_cmp expect err
+       )
+'
+
+test_expect_success 'complains about broken root ref in worktree' '
+       test_when_finished "rm -rf repo worktree" &&
+       git init repo &&
+       (
+               cd repo &&
+               test_commit initial &&
+               git worktree add ../worktree &&
+               echo "ref: refs/../HEAD" >.git/worktrees/worktree/HEAD &&
+               test_must_fail git refs verify 2>err &&
+               cat >expect <<-EOF &&
+               error: worktrees/worktree/HEAD: badReferentName: points to invalid refname ${SQ}refs/../HEAD${SQ}
+               EOF
+               test_cmp expect err
+       )
+'
+
 test_done