refs/files: perform consistency checks for root refs
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>
Patrick Steinhardt committed
Jan 12, 2026 at 10:02 UTC
7b8c36a2a74868b6fa47e3b11e2c1c0f89c88d43
2 files changed
+77
-3
refs/files-backend.c
+47
-3
@@ -3877,9 +3877,9 @@ static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
3877
if (filename[0] != '.' && ends_with(filename, ".lock"))
3878
goto cleanup;
3879
3880
- /*
3881
- * This works right now because we never check the root refs.
3882
- */
3880
+ if (is_root_ref(refname))
3881
+ goto cleanup;
3882
+
3883
if (check_refname_format(refname, 0)) {
3884
struct fsck_ref_report report = { 0 };
3885
@@ -3974,19 +3974,63 @@ out:
3974
return ret;
3975
}
3976
3977
+struct files_fsck_root_ref_data {
3978
+ struct files_ref_store *refs;
3979
+ struct fsck_options *o;
3980
+ struct worktree *wt;
3981
+ struct strbuf refname;
3982
+ struct strbuf path;
3983
+};
3984
+
3985
+static int files_fsck_root_ref(const char *refname, void *cb_data)
3986
+{
3987
+ struct files_fsck_root_ref_data *data = cb_data;
3988
+ struct stat st;
3989
+
3990
+ strbuf_reset(&data->refname);
3991
+ if (!is_main_worktree(data->wt))
3992
+ strbuf_addf(&data->refname, "worktrees/%s/", data->wt->id);
3993
+ strbuf_addstr(&data->refname, refname);
3994
+
3995
+ strbuf_reset(&data->path);
3996
+ strbuf_addf(&data->path, "%s/%s", data->refs->gitcommondir, data->refname.buf);
3997
+
3998
+ if (stat(data->path.buf, &st)) {
3999
+ if (errno == ENOENT)
4000
+ return 0;
4001
+ return error_errno("failed to read ref: '%s'", data->path.buf);
4002
+ }
4003
+
4004
+ return files_fsck_ref(&data->refs->base, data->o, data->refname.buf,
4005
+ data->path.buf, st.st_mode);
4006
+}
4007
+
4008
static int files_fsck(struct ref_store *ref_store,
4009
struct fsck_options *o,
4010
struct worktree *wt)
4011
{
4012
struct files_ref_store *refs =
4013
files_downcast(ref_store, REF_STORE_READ, "fsck");
4014
+ struct files_fsck_root_ref_data data = {
4015
+ .refs = refs,
4016
+ .o = o,
4017
+ .wt = wt,
4018
+ .refname = STRBUF_INIT,
4019
+ .path = STRBUF_INIT,
4020
+ };
4021
int ret = 0;
4022
4023
if (files_fsck_refs_dir(ref_store, o, wt) < 0)
4024
ret = -1;
4025
+
4026
+ if (for_each_root_ref(refs, files_fsck_root_ref, &data) < 0)
4027
+ ret = -1;
4028
+
4029
if (refs->packed_ref_store->be->fsck(refs->packed_ref_store, o, wt) < 0)
4030
ret = -1;
4031
4032
+ strbuf_release(&data.refname);
4033
+ strbuf_release(&data.path);
4034
return ret;
4035
}
4036
t/t0602-reffiles-fsck.sh
+30
@@ -905,4 +905,34 @@ test_expect_success '--[no-]references option should apply to fsck' '
905
)
906
'
907
908
+test_expect_success 'complains about broken root ref' '
909
+ test_when_finished "rm -rf repo" &&
910
+ git init repo &&
911
+ (
912
+ cd repo &&
913
+ echo "ref: refs/../HEAD" >.git/HEAD &&
914
+ test_must_fail git refs verify 2>err &&
915
+ cat >expect <<-EOF &&
916
+ error: HEAD: badReferentName: points to invalid refname ${SQ}refs/../HEAD${SQ}
917
+ EOF
918
+ test_cmp expect err
919
+ )
920
+'
921
+
922
+test_expect_success 'complains about broken root ref in worktree' '
923
+ test_when_finished "rm -rf repo worktree" &&
924
+ git init repo &&
925
+ (
926
+ cd repo &&
927
+ test_commit initial &&
928
+ git worktree add ../worktree &&
929
+ echo "ref: refs/../HEAD" >.git/worktrees/worktree/HEAD &&
930
+ test_must_fail git refs verify 2>err &&
931
+ cat >expect <<-EOF &&
932
+ error: worktrees/worktree/HEAD: badReferentName: points to invalid refname ${SQ}refs/../HEAD${SQ}
933
+ EOF
934
+ test_cmp expect err
935
+ )
936
+'
937
+
938
test_done