Repository navigation
adopt-project.py and update-shape.py: a revision git is asked about ends its argv in --, so a root file named HEAD no longer stops execute with exit 128 before that leg is pushed, nor blanks what apply --branch says it committed (#1215) - #1294
brettheap wants to merge 3 commits into
Conversation
…nds its argv in `--`, so a root file named `HEAD` no longer stops `execute` with exit 128 before that leg is pushed, nor blanks what `apply --branch` says it committed (#1215) `git rev-list --count HEAD` (`_extract_leg`), `git rev-list --count <tip id>` (`Source.commit_count`), `git diff-tree ... HEAD` (the `committed on` line) and the two `git show <rev>:contracts/shape-pin.yaml` reads read their revision as a path too where the work tree holds an entry of that name, and git refuses it as ambiguous. Each argv now ends in `--`. The rest of the shipped tools were scanned for the same shape; the sites left, and why, are in the pull request. Closes #1215 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reviewer's GuideImplementationSeparate revision arguments from paths in adoption commit counts so revision-like files cannot abort planning or leg extraction before a leg is pushed.
End the shape-update revision queries with
TestsAdd adoption regressions for revision-like filenames in leg extraction and source commit counting, including controls without those files.
Add shape-update regressions for revision-like root entries affecting the committed-path report and pin reads, including controls and Windows skips for colon names.
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Independent review of #1294 (#1215) for lane openRepoShape-5, by rv1294 (opus), at 70747e4: READY Summary. The fix does what #1215 asks. The diff adds exactly five trailing MUST: none. SHOULD
NIT
Evidence, judge by judge
State left. I made no GitHub writes and no commits; the predicted merge is an unreferenced Files are in /workspace/projects/.lane-worktrees/openRepoShape-5/work/rv1294:
Lane: openreposhape-5 (openRepoShape-5) |
…e third row's colon name is skipped on Windows as the second's is, and two comments name any work-tree entry, tracked or not, as what trips the revision (#1215) rv1294's review of the pull request found the third row's colon name (`refs/remotes/origin/<base>:contracts/shape-pin.yaml`) a bare value, where the file's docstring says the second and third names are skipped on Windows: on Windows that row would fail at the `mkdir` in `tracked()` instead of skipping. It is now a `pytest.param` with `NOT_ON_WINDOWS`. The comments at `_land`'s `diff-tree` and `_committed_pin` said git refuses the argument where the root TRACKS a file of that name. Git checks the work tree, so an untracked entry trips it too (probed on git 2.43.0 and 2.47.1); they now say so, as `Source.commit_count`'s docstring does. Comments only. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Re-check of #1294 (#1215) for lane openRepoShape-5, by rv1294b (sonnet), at ce9fbee: READY Summary. The one round commit All folders and paths below are under Nothing else changed (check 1)
SHOULD 1, the mark (check 2)
NIT 5, the comments (check 3)
The body's claims (check 4)
Gates (check 5).
Merge-trees (check 6). Fetched at 00:52Z on git 2.47.1 (
The record (check 7).
State left. I made no GitHub writes and no commits (the predicted merge is an unreferenced Lane: openreposhape-5 (openRepoShape-5) |
|



Goal
adopt-project.py executecounts a leg's kept commits withgit rev-list --count HEADin the leg's work clone, right aftergit filter-repo, and that argv has no--. Where the leg keeps a root file namedHEAD, git reads the argument as a revision and as a path, and refuses (fatal: ambiguous argument 'HEAD': both revision and filename, exit 128).executestopped there, aftergit filter-repoand before that leg was pushed (#1215). The argv now ends in--.The issue asked for the same shape to be looked for elsewhere. It is in four more places that a probe shows, in
adopt-project.pyandupdate-shape.py, and each ends in--now, with its own row. Every other site of the shape in the shipped tools is listed below, with the reason it is left.This PR changes
adopt-project.pyandupdate-shape.py, one--per argv, and adds two test files. No refusal code changes, and no printed sentence changes except where git's own argv is echoed: agit-failedrefusal from the two adopt sites now saysgit rev-list --count HEAD --(or... <id> --). Nothing intests/,README.md,docs/orAGENTS.mdpins the old text (grepped again atce9fbee6e).What held on main (measured)
Probed at main
4552efa6awith git 2.43.0 and git-filter-repo 2.47.0, a stubghfirst on PATH (exit 97),GH_TOKEN=bogus-l5, an emptyGH_CONFIG_DIR,GIT_SSH_COMMAND=false,GIT_CONFIG_GLOBAL=/dev/nulland local remotes only. The realghwas never run.The issue's site. A source with a root file named
HEAD(the plan asks which leg owns it, answeredcode, thenspec):planexit 0 andcheckexit 0: neither warns. (checkprinted only its offlineghnotes.)execute --yes --local-remote-dir ...exit 2,REFUSED extracting the code leg. git-failed: git rev-list --count HEAD in <work>/Northwind-code exited 128: fatal: ambiguous argument 'HEAD': both revision and filename.HEADin the code leg, the spec leg is pushed (refs/heads/main) and the code leg's bare repository is made and empty. WithHEADin the spec leg, both bare repositories are made and neither is pushed. A re-run is then refusedleg-remote-exists, as the refusal's own NOTHING-rolled-back paragraph says.The same shape, probed at the same base (each probe is one of the rows below, run against main's production code):
adopt-project.py_extract_leg:rev-list --count HEADHEADin a leg:executeexit 2 (above)adopt-project.pySource.commit_count:rev-list --count <tip id>in the source, read in placeplanexit 2,REFUSED git-failed: git rev-list --count <id> ... ambiguous argument, no plan writtenupdate-shape.py_land(whichcmd_applycalls):diff-tree --root --no-commit-id -r --name-only --no-renames -z HEADHEAD: git answers nothing,_git_answergoes on without it, and thecommitted on <branch>:line namescontracts/shape-pin.yaml, project.yaml, the paths the run was asked to commit, where the commit holds the pin alone. #674 had fixed exactly that lineupdate-shape.py_committed_pin:show HEAD:contracts/shape-pin.yamlHEAD:contracts/shape-pin.yaml(a directory namedHEAD:contracts): the answer is empty, so theupdate-rerun-uncommittedandupdate-branch-uncommittedsentences lose which commit HEAD's pin namesupdate-shape.py_accepted_in_the_pin:show refs/remotes/origin/<base>:contracts/shape-pin.yaml[], so the pull request body names none of the copies--accept-localkept (#535)What changed
adopt-project.py,_extract_leg:["rev-list", "--count", "HEAD", "--"]. The revision staysHEAD;rev-parse HEADjust above it takes no path and never had the problem.adopt-project.py,Source.commit_count:["rev-list", "--count", self.commit, "--"], with a docstring that says why.update-shape.py:--ends the argv of thediff-treein_land(whichcmd_applycalls), ofshow HEAD:<pin>in_committed_pinand ofshow refs/remotes/origin/<base>:<pin>in_accepted_in_the_pin. Each has a comment that names adopt-project.py:executecounts a leg's commits withgit rev-list --count HEADand no--, so a leg that keeps a root file namedHEADstopsexecutewith exit 128 aftergit filter-repo, before that leg is pushed #1215.tests/test_adopt_rev_list_dashdash.pyandtests/test_update_shape_head_named_entries.py: the rows below.Nothing else moves: every other line of both files is main's.
Rows, and what they do on main
4552efa6atest_execute_pushes_a_leg_that_keeps_a_root_file_named_head(no-such-file,spec-leg,code-leg): plan, answer,check,execute --yeswith local remotes;adoption verified, exit 0, each leg's printed(N commits kept)equalsrev-list --count mainof the leg it pushed, and the leg that kept the file holds itspec-legandcode-legfail (REFUSED extracting the spec leg/the code leg, exit 128 inside);no-such-file, the control, passestest_plan_and_check_read_a_source_holding_a_file_named_as_its_tip(no-such-file,a-file-named-as-the-tip):planexit 0 and3 commits,checksaysplan oka-file-named-as-the-tipfails (planexit 2git-failed); the control passestest_the_committed_line_names_what_git_lists_over_a_file_named_head(no-such-file,a-file-named-head):apply --accept-local ... --branch, the line iscommitted on <branch>: contracts/shape-pin.yamlandgit show --name-onlyagreesa-file-named-headfails (the line names the pin andproject.yaml); the control passestest_the_commit_head_pins_is_read_over_a_file_spelled_as_the_argument(no-such-file,a-file-spelled-as-the-argument):_committed_pinis the pin's commit''); the control passestest_the_copies_a_run_kept_are_read_over_a_file_spelled_as_the_argument(no-such-file,a-file-spelled-as-the-argument):_accepted_in_the_pinis['scripts/bootstrap.py'][]); the control passesOn main: 6 failed, 5 passed over the 11 ids (adopt file: 3 failed, 2 passed,
logs/base-adopt-rows.log; update-shape file: 3 failed, 3 passed,logs/base-us-rows.log): 6 rows fail on main and 5 are controls. The two colon-named rows (thea-file-spelled-as-the-argumentids oftest_the_commit_head_pins_is_read_over_a_file_spelled_as_the_argumentandtest_the_copies_a_run_kept_are_read_over_a_file_spelled_as_the_argument) skip on Windows, which cannot give a file a colon; both carry theskipifmark (the last section shows it read from pytest's own collection). Only theexecuterow needsgit filter-repo, astests/test_adopt_e2e.pydoes, and its 3 ids skip by name without it (git filter-repo is not installed: ...); the plan/check row's 2 ids run without it.Mutants
Each applied alone in a detached tree, run against its own row file, and restored with
git checkout -- <file>, its sha256 checked equal to the head's.M1:_extract_legback torev-list --count HEAD(main's argv)test_execute_pushes_a_leg_that_keeps_a_root_file_named_head[spec-leg];test_execute_pushes_a_leg_that_keeps_a_root_file_named_head[code-leg]M1c:_extract_legwith the--beforeHEAD:rev-list --count -- HEADtest_execute_pushes_a_leg_that_keeps_a_root_file_named_head[no-such-file];test_execute_pushes_a_leg_that_keeps_a_root_file_named_head[spec-leg];test_execute_pushes_a_leg_that_keeps_a_root_file_named_head[code-leg]M1d:_extract_legcountinghead, the tip id, with no--M2:Source.commit_countwithout the--test_plan_and_check_read_a_source_holding_a_file_named_as_its_tip[a-file-named-as-the-tip]M2c:Source.commit_countwith the--before the idtest_execute_pushes_a_leg_that_keeps_a_root_file_named_head[no-such-file];test_execute_pushes_a_leg_that_keeps_a_root_file_named_head[spec-leg];test_execute_pushes_a_leg_that_keeps_a_root_file_named_head[code-leg];test_plan_and_check_read_a_source_holding_a_file_named_as_its_tip[no-such-file];test_plan_and_check_read_a_source_holding_a_file_named_as_its_tip[a-file-named-as-the-tip]M3:_land'sdiff-tree(called bycmd_apply) without the--test_the_committed_line_names_what_git_lists_over_a_file_named_head[a-file-named-head]M3c:_land'sdiff-treewith the--beforeHEADtest_the_committed_line_names_what_git_lists_over_a_file_named_head[no-such-file];test_the_committed_line_names_what_git_lists_over_a_file_named_head[a-file-named-head]M4:_committed_pin'sshowwithout the--test_the_commit_head_pins_is_read_over_a_file_spelled_as_the_argument[a-file-spelled-as-the-argument]M5:_accepted_in_the_pin'sshowwithout the--test_the_copies_a_run_kept_are_read_over_a_file_spelled_as_the_argument[a-file-spelled-as-the-argument]One survivor, M1d, and it is equivalent. Counting
head, the idrev-parsehas just printed, fixes the issue the other way: git can read an id as a path only where the work tree holds an entry named as the leg's own rewritten tip, and no entry can be named for the commit that holds it. No row can tell it fromHEAD --, so the row kills only the argv that is main's (M1) or has the--in the wrong place (M1c). The form kept is--after the revision. Each M-c mutant puts the--first, which makes the revision a path: it fails the controls too.The same shape elsewhere: what was scanned, and what is left
How. An AST scan of every list or tuple literal that holds a git subcommand which takes revisions, in
adopt-project.py,update-shape.py,shape-doctor.py,scaffold-project.py,setup-project.py,scripts/*.py,templates/*/scripts/*.pyandsrc/openreposhape/*.py; a second scan of every argv list that namesHEAD; and a grep ofinstall.sh,setup.sh, the template Makefiles and the workflows forgit log|show|diff|rev-list|reset. The launchersbootstrapandopenRepoShapehold none.Which git commands trip. Raw git, in a repository whose work tree holds entries named
HEAD,mainand the tip's id (probe/amb2.sh, identical results on git 2.43.0 and 2.47.1):rev-list,log,show,diff,diff-tree,diff-index,reset,grep <tree>,bundle,format-patchandshortlogexit 128ambiguous argument;checkout -B,ls-tree,read-tree,merge-base,cat-file,rev-parse,cherry-pick,describe,branch,archive,restore,merge,blameandshow-branchexit 0.rev-list --count HEAD --exits 0. So a revision passed to the second list is not at risk, and only the first list needs the--.Fixed (the five above). Each is shown by a probe and has a row.
Left, and why:
--:adopt-project.py'sLACKING_WALKwalk (rev-list --objects --missing=print --branches --tags <head> --, adopt-project.py:checkandexecuterun withGIT_NO_LAZY_FETCH=1and refuse a partial-clone source that lacks an object its branches, tags or HEAD reach assource-partial-clone, so neither fetches into the source any more (#1145) #1180), thegit log ... <tip> --branches --tags --of_exported_gitlink, thegit grep ... <tip> -- <paths>of the code-path scan;update-shape.py'sdiff --quiet HEAD -- <paths>;shape-doctor.py's tworev-list ... HEAD -- <pin>walks;scripts/bump-leg.py'sreset -q HEAD -- <paths>;scripts/family.py'sdiff --quiet ... HEAD -- <paths>;scripts/repo_shape.py'sls-tree HEAD --.adopt-project.py'sread-tree <tip>, bothls-tree ... <rev>,merge-base --is-ancestor <tip> <commit>,cat-file -e <id>^{commit}, and bothcheckout -q -B <branch> <tip>(the leg's work clone and the assembly's);shape-doctor.py'smerge-base HEAD MERGE_HEAD,cat-file -t HEAD:./<path>and everyrev-parse; therev-parse,symbolic-ref,ls-tree,cat-file,for-each-refandconfigcalls ofscripts/*.py,templates/*/scripts/*.pyandsrc/openreposhape/standard.py.rev-list --count --all(scaffold-project.py,scripts/family.py) names no revision.update-shape.py'supstream_show, which hands a persongit show <target>:<source>quoted for a shell.scaffold-project.py_take_held_seed:reset -q <seed>. The seed is a commit an earlier run pushed, found on the remote and fetched, whose tree is what this run has just written to the work tree; an entry named as the seed's id would have to sit inside the seed's own tree, and no commit's tree holds an entry named for that commit.scripts/bump-leg.py_committed_paths:diff-tree ... <head>, andscripts/family.pytake_back:rev-list --parents --no-walk <made>. Each id is the commit the run has just made.shape-doctor.pyobjects_lacking:rev-list --objects --no-walk --missing=print <commit>, where the commit is the one a project's pin names and the repository is the checkout of the standard. Raw git does refuse it with an entry of that name, but no project's content reaches that checkout, so no row built from a project can show it.Source.commit_count, by contrast, asks the person's own source, in place, which may hold anything, and is fixed above.Runs
Two gates are reported. The first, the full one below, ran at
70747e4ab, this PR's first commit. The second ran after rv1294's review atce9fbee6e(the last section), on the files the round touches.Gate files at
70747e4ab(work/n1215/gate-files.txt, 78 files, 5980 ids in 60 parts of at most 100,-rsalone, at the head70747e4ab): my two test files; every adopt test file that runsexecute(63 files by grep,gate-adopt-exec.txt, my adopt file among them);tests/test_shape_doctor.pyandtests/test_scaffold_leg_path_collisions.py; the hygiene five (test_path_guard_hygiene,test_repo_hygiene,test_agents_md_codes,test_cli_reference,test_pinned_copy_text);tests/test_no_auto_maintenance.py; and sevenupdate-shapefiles for the changed lines (test_update_shape,_apply_lines_and_headers,_landing,_partial_rollback,_pr_base,_messages,_next_quoting, with_merged_awayalready in the adopt list). git 2.43.0 is the system git; git 2.47.1 is a build of kernel.org's tarball. git-filter-repo 2.47.0 on both (L/tools/venv247; its--versionprintsa40bce548d2c), Python 3.12.3.The gate is finished on both gits: every one of the 60 parts has one summary line with exit 0 and no failure, and
work/n1215/gates.summaryholds the START and END lines. The chain ran in three stretches (parts 00-14 from 21:26Z; parts 15-25 from 22:04Z; parts 26-59 from 22:55Z), because it was stopped at LAST STEP and again at the account swap; each START line recordshead=70747e4abcaeanddirty=0, so every part ran at this head, once to its summary line. The per-part logs arework/n1215/logs/g<git>-part-NN.log.My two row files alone (the rows above, 11 ids): git 2.43.0 (
logs/fix-adopt-rows.log,logs/fix-us-rows.log): 5 + 6 passed; git 2.47.1 (logs/rows-2471.log): 11 passed.The 11 rows at the predicted merge. Main moved five landings past this head's base (see Merges), so the head was merged with
origin/main370a23cd2asgit commit-treewould make it (fd3a8972d, treeb6570f985ee8, the treegit merge-tree --write-treewrote; unreferenced, parents70747e4aband370a23cd2). Against370a23cd2it differs in the same four files, +297/-6, and the stable patch-id of that diff (7227aad7ce4c) equals the head's diff against4552efa6a, file by file (adopt-project.pyc4844e230193,update-shape.py3d865b5ea243,tests/test_adopt_rev_list_dashdash.py0d6d249f3721,tests/test_update_shape_head_named_entries.py64afdbb6f354). The two new test files, run there on git 2.43.0 (work/n1215b/logs/pm-rows-243.log): 11 passed, none skipped, none failed.Skips by name (from the
SKIPPEDlines of each part's log,-rsalone;[N]is pytest's count). None is in either new test file:git 2.43.0, 20 skips:
SKIPPED [1] tests/test_adopt_check_throwaway_repos.py:482: needs a disk that ignores case: 'git init' wrote no 'core.ignorecase=true' in the work directory, so that disk keeps case; the rows above write the setting into the throwaway repository by hand insteadSKIPPED [1] tests/test_adopt_eol_block_through_links.py:263: only a root that keeps a link has one to write throughSKIPPED [1] tests/test_adopt_eol_block_through_links.py:284: only a root that keeps a link has one to replaceSKIPPED [1] tests/test_adopt_root_symlinks.py:1960: the reftable backend needs git 2.45 or laterSKIPPED [1] tests/test_adopt_root_symlinks.py:2015: the reftable backend needs git 2.45 or laterSKIPPED [1] tests/test_adopt_root_symlinks.py:2596: the reftable backend needs git 2.45 or laterSKIPPED [1] tests/test_adopt_template_values.py:235: 'git config user.name' here is not read from GIT_CONFIG_GLOBAL: b'\n'SKIPPED [1] tests/test_leg_path_yaml_scalars.py:459: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:472: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:481: the templates read ~, 2026 back (#259 quotes the leg-path lines), so the rule has nothing to refuseSKIPPED [1] tests/test_leg_path_yaml_scalars.py:498: the templates read 2026 back (#259 quotes the leg-path lines), so the rule has nothing to refuseSKIPPED [1] tests/test_leg_path_yaml_scalars.py:538: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:549: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:558: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:581: the templates read 2026 back (#259 quotes the leg-path lines), so the rule has nothing to refuseSKIPPED [2] tests/test_no_auto_maintenance.py:222: the session began with GIT_CONFIG_GLOBAL set, and its file includes that oneSKIPPED [3] tests/test_shape_doctor.py:10516: the PowerShell line is printed, and powershell.exe exists, only on a Windows hostgit 2.47.1, 20 skips:
SKIPPED [1] tests/test_adopt_check_throwaway_repos.py:482: needs a disk that ignores case: 'git init' wrote no 'core.ignorecase=true' in the work directory, so that disk keeps case; the rows above write the setting into the throwaway repository by hand insteadSKIPPED [3] tests/test_adopt_check_throwaway_repos.py:1041: this git's 'git clone' takes 'init.defaultBranch = a..b', as 2.55's does: the split clones thereSKIPPED [1] tests/test_adopt_eol_block_through_links.py:263: only a root that keeps a link has one to write throughSKIPPED [1] tests/test_adopt_eol_block_through_links.py:284: only a root that keeps a link has one to replaceSKIPPED [1] tests/test_adopt_template_values.py:235: 'git config user.name' here is not read from GIT_CONFIG_GLOBAL: b'\n'SKIPPED [1] tests/test_leg_path_yaml_scalars.py:459: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:472: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:481: the templates read ~, 2026 back (#259 quotes the leg-path lines), so the rule has nothing to refuseSKIPPED [1] tests/test_leg_path_yaml_scalars.py:498: the templates read 2026 back (#259 quotes the leg-path lines), so the rule has nothing to refuseSKIPPED [1] tests/test_leg_path_yaml_scalars.py:538: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:549: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:558: got empty parameter set for (value, reading)SKIPPED [1] tests/test_leg_path_yaml_scalars.py:581: the templates read 2026 back (#259 quotes the leg-path lines), so the rule has nothing to refuseSKIPPED [2] tests/test_no_auto_maintenance.py:222: the session began with GIT_CONFIG_GLOBAL set, and its file includes that oneSKIPPED [3] tests/test_shape_doctor.py:10516: the PowerShell line is printed, and powershell.exe exists, only on a Windows hostMerges
Head
ce9fbee6e(this PR's two commits:70747e4ab, then the round after rv1294's review) is on main4552efa6a. Main is370a23cd2, fetched at 00:39Z on 2026-11-10 (no landing since the last body), five landings past the base (#1227, #1189, #1207, #1201, #1164). Fresh at 00:39Z:git merge-tree --write-tree <other> HEADon git 2.47.1, with every other head read fromgh pr list --state open(read only, 40 open PRs, 19 of them touchingadopt-project.py,update-shape.pyor one of the two new test files, this PR among them; heads inwork/n1215c/mt-list.txt):370a23cd2b4bcfb83eb75(the predicted merge in the last section)Every one merges clean. #1237 is now
87325bed2: atb557859fdit conflicted intests/test_adopt_check_throwaway_repos.py, a file this PR does not change, and rv1294 measured it clean at70747e4abtoo. Raw output:work/n1215c/merge-trees.log(the earlier runs:work/n1215b/merge-trees.log, at70747e4ab;work/n1215/merge-trees.log, at4552efa6a).The round after rv1294's review
rv1294 (opus) read this PR at
70747e4aband found it READY: no MUST, two SHOULDs and six NITs (#1294 issuecomment-6755422831). The round is one commit,ce9fbee6e, on top of70747e4ab(two files, +9/-5: a mark intests/test_update_shape_head_named_entries.pyand two comments inupdate-shape.py), and this body.adopt-project.py,tests/test_adopt_rev_list_dashdash.pyand every production code line are as70747e4abhad them. The title is unchanged.In the commit
SHOULD 1, the third update-shape row had no Windows skip. The colon name of
test_the_copies_a_run_kept_are_read_over_a_file_spelled_as_the_argumentis nowpytest.param("refs/remotes/origin/{base}:" + PIN, marks=NOT_ON_WINDOWS), as the second row's is. On Windows it skips instead of failing at themkdirintracked(), which is reasoned, not measured: there is no Windows host here, as rv1294 said. Read from pytest's own collection (--collect-only, a plugin that prints each item's ownskipifmarks;work/n1215c/logs/marks-*.log):70747e4ab:test_the_commit_head_pins_is_read_over_a_file_spelled_as_the_argument[a-file-spelled-as-the-argument]carriesskipif(condition=False, reason='Windows cannot give a file a colon in its name')test_the_copies_a_run_kept_are_read_over_a_file_spelled_as_the_argument[a-file-spelled-as-the-argument]carries no skipif markce9fbee6e:test_the_commit_head_pins_is_read_over_a_file_spelled_as_the_argument[a-file-spelled-as-the-argument]carriesskipif(condition=False, reason='Windows cannot give a file a colon in its name')test_the_copies_a_run_kept_are_read_over_a_file_spelled_as_the_argument[a-file-spelled-as-the-argument]carriesskipif(condition=False, reason='Windows cannot give a file a colon in its name')The condition prints
Falsebecause this host is Linux; both rows use the oneNOT_ON_WINDOWSobject (os.name == "nt"). The module docstring ("THE SECOND AND THIRD FILE NAMES HOLD A COLON ... and are skipped there") and the Rows paragraph above are now true. No effect on CI, as rv1294 noted: thetests-git-bashjob on windows-latest runs onlytest_openreposhape_command.py,test_install_sh.pyandtest_install_sh_filter_repo.py. A mark that only a Windows host reads cannot be killed by a mutant here, so there is none.NIT 5, the update-shape comments. The two comments at
_land'sdiff-treeand at_committed_pinsaid git refuses the argument "where the root tracks a file of that name". They now say that an entry of that name in the work tree, tracked or not, trips it, asSource.commit_count's docstring does. Comments only. Probed again with raw git 2.43.0 and 2.47.1 in a scratch repository, an UNTRACKED file namedHEADand an untrackedHEAD:contracts/shape-pin.yaml(work/n1215c/probes/untracked.sh,logs/untracked.log):diff-tree --root --no-commit-id -r --name-only --no-renames -z HEADandshow HEAD:contracts/shape-pin.yamlexit 128ambiguous argument; each with a trailing--exits 0.In this body only
diff-treesite is in_land, whichcmd_applycalls (the hunk header saysdef _land(); the "What held", "What changed" and Mutants rows say so.git rm -fand writes the twins the root keeps back from the index, so on a disk that ignores caseexecutekeeps a set the plan splits across repositories or drops (#1183) #1237 is87325bed2and merges clean.executerow needsgit filter-repo. With nogit-filter-repoon PATH, git 2.43.0, atce9fbee6e(work/n1215c/logs/nofr-adopt-rows.log):2 passed, 3 skipped in 3.46s, withSKIPPED [3] tests/test_adopt_rev_list_dashdash.py:60: git filter-repo is not installed: 'pip install git-filter-repo'for theexecuterow's 3 ids, and the plan/check row's 2 ids passing.scaffold-project.py_take_held_seedis still left, with the reason corrected: its seed is a commit an earlier run pushed, found on the remote and fetched, whose tree is what this run has just written. The conclusion holds.git-failedrefusal from the two adopt sites now echoesgit rev-list --count HEAD --(and... <id> --), so "no printed sentence changes" is true except there; the Goal says so. Grepped again atce9fbee6e(work/n1215c/logs/pins-grep.log): nothing intests/,README.md,docs/orAGENTS.mdpins the old text. The only hits forrev-list --countin them are in this PR's own adopt test file, which describes main's refusal and asserts none of it.Runs this round, at
ce9fbee6e(each START line recordshead=ce9fbee6ea40anddirty=0;work/n1215c/gates.summary, logswork/n1215c/logs/g<git>-part-NN.log): 827 ids in 9 parts of at most 100,-rsalone, Python 3.12.3, git-filter-repo 2.47.0 on PATH for both (L/tools/venv247,--versionprintsa40bce548d2c), git 2.43.0 the system git and git 2.47.1 the kernel.org build, run namesn1215c-g<git>-part-NN. The files: this PR's two test files;tests/test_update_shape_partial_rollback.py, whose module-scoped fixture the new update-shape file imports, in the same pytest as that file (part 00, withtests/test_update_shape_apply_lines_and_headers.py); the other update-shape files the body names (test_update_shape,_landing,_pr_base,_messages,_next_quoting,_merged_away);tests/test_adopt_e2e.py; the hygiene five (test_path_guard_hygiene,test_repo_hygiene,test_agents_md_codes,test_cli_reference,test_pinned_copy_text); andtests/test_no_auto_maintenance.py.tests/test_shape_doctor.pyandtests/test_scaffold_leg_path_collisions.py, which the full gate ran at70747e4ab, are not run again: the round changes no code inadopt-project.pyorshape-doctor.py.SKIPPED [2] tests/test_no_auto_maintenance.py:222: the session began with GIT_CONFIG_GLOBAL set, and its file includes that oneSKIPPED [2] tests/test_no_auto_maintenance.py:222: the session began with GIT_CONFIG_GLOBAL set, and its file includes that oneThe predicted merge again. Main is still
370a23cd2, so the head merged with it, asgit commit-treewould make it, isbaa7d4e46(treeb4bcfb83eb75, the treegit merge-tree --write-treewrote; unreferenced, parentsce9fbee6eand370a23cd2). Its diff against370a23cd2is the same four files, +301/-6, and the stable patch-id of that diff (6bf5e6631df0) equals the head's diff against4552efa6a, file by file (adopt-project.pyc4844e230193,update-shape.pyd27a158df865,tests/test_adopt_rev_list_dashdash.py0d6d249f3721,tests/test_update_shape_head_named_entries.pyc8885e14ecd5;work/n1215c/logs/pm-make.log). The two new test files, run there: git 2.43.011 passed in 19.05s; git 2.47.111 passed in 18.17s(work/n1215c/logs/pm-rows-*.log).Closes #1215
Lane: openreposhape-5 (openRepoShape-5)
🤖 Generated with Claude Code
Summary by Sourcery
Harden adoption and shape-update Git operations against work-tree entries that conflict with revision arguments.
Bug Fixes:
HEADor a branch tip ID.Enhancements:
Tests:
HEAD, branch tip IDs, and revision-shaped paths.