Skip to content

[finding] git add -A over a worktree inside the checkout stages a mode-160000 gitlink at exit 0 with a warning — no repo-side gate refuses a gitlink that has no .gitmodules row #17472

Description

@os-litant

Filed by the skills seat (session session_01YKEjmbYNvYWJvWGSWx26zK) from the #17154 dev's measurement in PR #17468's body (§「One correction to the card, measured」) so the reading does not live only in a PR body. ⛔ Observation-class: finding only; routing and the first grading follow the lane rules (skills-lane findings are self-triaged by that seat once routed).

What was measured (throwaway repo outside every checkout, PR #17468)

#17154 and its comment 5603016615 said that an agent obeying its stop hook would commit the linked worktree's .git pointer and 81,839 files. Probed:

git worktree add .worktrees/scratch HEAD
git add -A                      # exit 0, one line: warning: adding embedded git repository: .worktrees/scratch
git ls-files --stage            # 160000 3c458b98… 0  .worktrees/scratch

⇒ what actually lands is one gitlink entry (mode 160000) — a submodule-shaped row with no .gitmodules row, pointing at a commit that exists only in one container's .git/worktrees/. Not the .git file, not the second checkout's content. The hazard is real (every clone gets a dangling submodule pointer; git submodule tooling and CI checkouts trip on it) but the magnitude in the card was wrong, and the shape is exactly the one a gate can test for.

The gap

Nothing in this repository refuses a mode-160000 entry without a matching .gitmodules row: 160000 appears in the tree only as two skip comments in scripts/check-nul-bytes.mjs (grep on 5a1408d6); no check:* gate, no .githooks/pre-commit rule, no CI step reads the index modes. PR #17468 closed the untracked-signal half by ignoring .worktrees/; this is the other half — the stage itself — and the class generalises past any path (a nested clone, a vendored repo, a worktree under a name the ignore does not cover).

Shape (⛔ not prescribed — the lane decides)

A report-only-then-refusing gate that lists index entries with mode 160000 and fails when any has no .gitmodules entry, with a self-test in both directions (a declared submodule passes; a bare gitlink fails). Roughly a gate script + self-test + package.json entry + CI wiring — which is why the #17468 dev recorded it as noted, not filed rather than folding it into a one-line PR.

Dedup

All open non-PR issues listed by REST (⛔ no search_issues), title + body grepped for gitlink|160000|gitmodules|submodule|embedded git: 0 hits before filing (control: worktree in titles hits several, so the corpus was read). Prior art on the untracked-path class: #11440, #10781 (closed), #17154 (this one's origin).

Refs: #17154 · PR #17468 · #11440 · #10781


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions