Skip to content

validate-family.py: in a sparse checkout that leaves .gitmodules out, the put-back line git checkout -- .gitmodules matches no file and every git add -- .gitmodules the findings print exits 1, so no printed line set cures a finding there #1242

Open

Description

@brettheap

Problem

templates/family-root/scripts/validate-family.py prints remedies for .gitmodules as lines to type: a put-back of the file git reads where the work tree holds none (GITMODULES_SOURCES, _gitmodules_put_back: git checkout -- .gitmodules for the index's), git config -f .gitmodules ... edits, and git add -- .gitmodules (STAGE_LINE, about ten call sites: the value check, gitmodules-path-unnamed, the hand mount and stray lines, the staged removal's _keys_back, the wrong-case move, and the gitmodules-unreadable refusal for the index's file that #1227 adds).

In a sparse checkout whose patterns leave .gitmodules out (non-cone /* and !/.gitmodules; its index entry is skip-worktree, git ls-files -t says S), none of these works:

  • git checkout -- .gitmodules exits 1: error: pathspec '.gitmodules' did not match any file(s) known to git.
  • So the git config -f .gitmodules --unset-all ... after it has no file and exits 5.
  • git add -- .gitmodules exits 1 even once the file is on disk: The following paths and/or pathspecs matched paths that exist outside of your sparse-checkout definition, so will not be updated in the index (hint: Use the --sparse option).
  • A plain git commit after the lines then records what the index held, the value git dies on and all.

The family bootstrap already prints its index put-back with --ignore-skip-worktree-bits (gitmodules_cures, RV877's NIT-3), and tests/test_family_gitmodules_values.py's put_back_mended_and_committed adds with --sparse there; the gate's own lines do neither.

Measured

Git 2.43.0, offline (run9.sh: stub gh, GIT_SSH_COMMAND=false, GIT_CONFIG_GLOBAL=/dev/null), on #1227's branch merged with main e04826db4 (d95308e95). The probe is lane 5's scratch v124/n1150/d/probes/test_n1150d_probe.py (test_s2_*), logs in v124/n1150/d/probes-out/merged-d95308e/s2-*.log; rv1227's probes e3a and e3b (v129/rv1227/out/head/e3a-*.log, e3b-*.log) gave the same on #1227's head b031f4938.

  1. update = !true staged in MEMBER's section of the index's file, then git sparse-checkout set --no-cone '/*' '!/.gitmodules' (lose_by_a_sparse_checkout). The gate (--no-members) gives gitmodules-value-refused, exit 1, with git checkout -- .gitmodules, the --unset-all line and git add -- .gitmodules.
    • As printed: git checkout -- .gitmodules exits 1, the --unset-all exits 5, git add -- .gitmodules exits 1, and a plain git commit records !true in HEAD (rv1227's e3a).
    • In their place: git checkout --ignore-skip-worktree-bits -- .gitmodules exits 0 and clears the bit (ls-files -t says H); the --unset-all exits 0; git add -- .gitmodules still exits 1 (outside the sparse-checkout definition); git add --sparse -- .gitmodules exits 0; a plain git commit then has nothing to commit, HEAD holds no value, and the gate passes.
  2. HEAD's file and then a line git cannot parse, staged, and the same sparse checkout. The gate refuses gitmodules-unreadable for the index's file, exit 2. Its remediation's git checkout -- .gitmodules exits 1 and its git add -- .gitmodules exits 1 (rv1227's e3b). With --ignore-skip-worktree-bits, the line mended by hand, and git add --sparse, the gate passes.

Suggested fix

Where the index's .gitmodules entry is skip-worktree (git ls-files -t -- .gitmodules starts S, or -v gives a lower-case letter), print the index's put-back as git checkout --ignore-skip-worktree-bits -- .gitmodules (in _gitmodules_put_back, as bootstrap prints it) and every stage line as git add --sparse -- .gitmodules: a _stage_line(root) in place of the constant STAGE_LINE at each call site, and the same in the words that quote it (STAGE_SAID, the refusal's remediation). HEAD's put-back, git checkout HEAD -- .gitmodules, needs no flag: it is printed only where the index holds no entry. Elsewhere every line stays as it is, so no text outside that state changes. git add --sparse needs git 2.34 or later.

Verify

  • A row for each finding that prints a put-back or a stage line, in the sparse checkout above: the lines typed as printed, in order, then a plain git commit, leave HEAD right and the gate passing in every mode (ends_well), on git 2.43.0 and 2.47.1.
  • Every existing row of tests/test_family_gitmodules_values.py, tests/test_validate_family_index_gitmodules.py, tests/test_validate_family_index_value_unmerged.py, tests/test_family_hand_mount_git_rm_lines.py and tests/test_family_holder_remedies_compose.py passes unchanged: no line changes outside a sparse checkout.
  • tests/test_path_guard_hygiene.py, tests/test_agents_md_codes.py, tests/test_cli_reference.py and tests/test_pinned_copy_text.py pass.

Found by rv1227's S2 on #1227 (issuecomment-6374575208); kept out of #1227's fix round because the fix changes every stage line the gate prints, not only #1227's.

Lane: openreposhape-5 (openRepoShape-5)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions