builtin/fsck: move generic HEAD check into `refs_fsck()`

Move the check that detects "HEAD" refs that do not point at a branch into `refs_fsck()`. This follows the same motivation as the preceding commit. 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:03 UTC 9727336b31c055e4507248703b8a4a8ed039dc06
6 files changed +21 -14
Documentation/fsck-msgids.adoc
+3
@@ -13,6 +13,9 @@
13 `badGpgsig`::
14 (ERROR) A tag contains a bad (truncated) signature (e.g., `gpgsig`) header.
15
16 +`badHeadTarget`::
17 + (ERROR) The `HEAD` ref is a symref that does not refer to a branch.
18 +
19 `badHeaderContinuation`::
20 (ERROR) A continuation header (such as for `gpgsig`) is unexpectedly truncated.
21
builtin/fsck.c
-7
@@ -728,13 +728,6 @@ static void fsck_head_link(const char *head_ref_name,
728 error(_("invalid %s"), head_ref_name);
729 return;
730 }
731 - if (strcmp(*head_points_at, head_ref_name) &&
732 - !starts_with(*head_points_at, "refs/heads/")) {
733 - errors_found |= ERROR_REFS;
734 - error(_("%s points to something strange (%s)"),
735 - head_ref_name, *head_points_at);
736 - return;
737 - }
731
732 return;
733 }
fsck.h
+1
@@ -30,6 +30,7 @@ enum fsck_msg_type {
30 FUNC(BAD_DATE_OVERFLOW, ERROR) \
31 FUNC(BAD_EMAIL, ERROR) \
32 FUNC(BAD_GPGSIG, ERROR) \
33 + FUNC(BAD_HEAD_TARGET, ERROR) \
34 FUNC(BAD_NAME, ERROR) \
35 FUNC(BAD_OBJECT_SHA1, ERROR) \
36 FUNC(BAD_PACKED_REF_ENTRY, ERROR) \
refs.c
+11 -1
@@ -334,8 +334,18 @@ int refs_fsck_ref(struct ref_store *refs UNUSED, struct fsck_options *o,
334
335 int refs_fsck_symref(struct ref_store *refs UNUSED, struct fsck_options *o,
336 struct fsck_ref_report *report,
337 - const char *refname UNUSED, const char *target)
337 + const char *refname, const char *target)
338 {
339 + const char *stripped_refname;
340 +
341 + parse_worktree_ref(refname, NULL, NULL, &stripped_refname);
342 +
343 + if (!strcmp(stripped_refname, "HEAD") &&
344 + !starts_with(target, "refs/heads/") &&
345 + fsck_report_ref(o, report, FSCK_MSG_BAD_HEAD_TARGET,
346 + "HEAD points to non-branch '%s'", target))
347 + return -1;
348 +
349 if (is_root_ref(target))
350 return 0;
351
t/t0602-reffiles-fsck.sh
+4 -4
@@ -910,10 +910,10 @@ test_expect_success 'complains about broken root ref' '
910 git init repo &&
911 (
912 cd repo &&
913 - echo "ref: refs/../HEAD" >.git/HEAD &&
913 + echo "ref: refs/heads/../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}
916 + error: HEAD: badReferentName: points to invalid refname ${SQ}refs/heads/../HEAD${SQ}
917 EOF
918 test_cmp expect err
919 )
@@ -926,10 +926,10 @@ test_expect_success 'complains about broken root ref in worktree' '
926 cd repo &&
927 test_commit initial &&
928 git worktree add ../worktree &&
929 - echo "ref: refs/../HEAD" >.git/worktrees/worktree/HEAD &&
929 + echo "ref: refs/heads/../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}
932 + error: worktrees/worktree/HEAD: badReferentName: points to invalid refname ${SQ}refs/heads/../HEAD${SQ}
933 EOF
934 test_cmp expect err
935 )
t/t1450-fsck.sh
+2 -2
@@ -113,7 +113,7 @@ test_expect_success 'HEAD link pointing at a funny place' '
113 test-tool ref-store main create-symref HEAD refs/funny/place &&
114 # avoid corrupt/broken HEAD from interfering with repo discovery
115 test_must_fail env GIT_DIR=.git git fsck 2>out &&
116 - test_grep "HEAD points to something strange" out
116 + test_grep "HEAD: badHeadTarget: HEAD points to non-branch ${SQ}refs/funny/place${SQ}" out
117 '
118
119 test_expect_success REFFILES 'HEAD link pointing at a funny object (from different wt)' '
@@ -148,7 +148,7 @@ test_expect_success 'other worktree HEAD link pointing at a funny place' '
148 git worktree add other &&
149 git -C other symbolic-ref HEAD refs/funny/place &&
150 test_must_fail git fsck 2>out &&
151 - test_grep "worktrees/other/HEAD points to something strange" out
151 + test_grep "worktrees/other/HEAD: badHeadTarget: HEAD points to non-branch ${SQ}refs/funny/place${SQ}" out
152 '
153
154 test_expect_success 'commit with multiple signatures is okay' '