You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
shape-doctor.py and siblings.py: a .gitmodules section git ignores ([submodule ""], a name with a .. component, a url beginning with -) is still read as a member, where git says No url found and exits 128 #733
Goal: the doctor and make siblings read a holder's .gitmodules as git does, and skip what git skips. Then neither one names a mount url, a NEXT line or a clone for a section that git will not mount.
Filed by lane openRepoShape-3 under v1.1.1, on Brett Heap's word of 2026-10-16T13:35:28Z ("yes create v1.1.1"). Lane 3's reviewer RV-c found it while reviewing #700 (#668), as S3. Nothing here regressed: main, #700 and siblings.py all read these sections, and the two tools agree with each other.
What happens. RV-c checked each case against git submodule init -- <path>, in a fresh repository with a real gitlink.
git ignores or refuses these:
[submodule ""]: git ignores it ("ignoring suspicious submodule name"). The doctor and siblings.py read it as the name ''.
A name with a .. component, such as ../evil: git's check_submodule_name refuses it.
A url beginning with -: git's looks_like_command_line_option refuses it.
For each of the three, git says No url found for submodule path … and exits 128.
Two more cases:
A url key with no value: git refuses the whole file (bad config line 3).
A section with a url and no path: both tools key it by its name, but git mounts it nowhere.
What to do:
In the doctor's .gitmodules reading (submodule_config, gitmodules_entry) and in siblings.py's, drop exactly the sections git drops, by git's own tests: an empty name, a name with a .. component, and a url beginning with -.
Read a file that git refuses whole as having no entries.
CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-16T17:29:50Z, for #733
Logged in lanes/log/openRepoShape-3.md at fdc25977739ff191f66048c5c5f3388f9ae6eddb.
The three reads (lane-collision-protocol Rule 1):
1. existing `CLAIMED —` comments on opensoft/openRepoShape#733:
none
2. `gh pr list --repo opensoft/openRepoShape --state all --search "#733"`, kept where the row or its body names `#733`:
none
3. `git ls-remote --heads git@github.com:opensoft/openRepoShape` branches naming `733` as a whole token:
none
(lane openRepoShape-3, 2026-10-16T18:05:42Z) Three more cases for #733, from RV-c's re-verification of #700 at fca40dfc (issuecomment-6221703634). Each was measured against git submodule init -- <path>.
An unmerged .gitmodules. git's repo_read_gitmodules reads no copy while .gitmodules is unmerged (is_gitmodules_unmerged), so git submodule init exits 128 with No url found.
The doctor gives the working-tree copy's url (('p', '/r/resolved.git')). Once that file is deleted, it gives HEAD's (('p', '/r/main.git')).
Fix: if git ls-files -u -- .gitmodules is non-empty, gitmodules_entry returns (None, None) before choosing a copy. Add the case to INDEX_COPIES.
The last section giving a path has no url. git says No url found. gitmodules_entry gives ('new', None), so the member is url-less, but mounted_from gives the earlier section's /r/old.git, as siblings.py does.
mounted_from names the remote make siblings clones from, so agreeing with siblings is its contract. Any change moves both tools together.
Activity
brettheap commentedon Oct 16, 2026
CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-16T17:29:50Z, for #733
Logged in
lanes/log/openRepoShape-3.mdatfdc25977739ff191f66048c5c5f3388f9ae6eddb.The three reads (lane-collision-protocol Rule 1):
brettheap commentedon Oct 16, 2026
(lane openRepoShape-3, 2026-10-16T18:05:42Z) Three more cases for #733, from RV-c's re-verification of #700 at
fca40dfc(issuecomment-6221703634). Each was measured againstgit submodule init -- <path>..gitmodules. git'srepo_read_gitmodulesreads no copy while.gitmodulesis unmerged (is_gitmodules_unmerged), sogit submodule initexits 128 withNo url found.('p', '/r/resolved.git')). Once that file is deleted, it gives HEAD's (('p', '/r/main.git')).mergerow (shape-doctor.py answers COMPLIANT, exit 0, for a root in the middle of a merge (UU contracts/spec-pin.yaml,UU spec, a MERGE_HEAD,git commitrefusing), because no row asks git for unmerged paths andrecorded_gitlinkanswers an unmerged gitlink from HEAD, so a root an agent cannot commit is reported compliant, including after thegit checkout --oursthat a conflicted pin's NEXT names #424) already reports the unmerged path first, so this is not urgent.git ls-files -u -- .gitmodulesis non-empty,gitmodules_entryreturns(None, None)before choosing a copy. Add the case toINDEX_COPIES.No url found.gitmodules_entrygives('new', None), so the member is url-less, butmounted_fromgives the earlier section's/r/old.git, assiblings.pydoes.mounted_fromnames the remotemake siblingsclones from, so agreeing withsiblingsis its contract. Any change moves both tools together.validate-family.py's family.py:addnever reads.gitmodules, so a section under ANOTHER name whosepathis alreadymembers/<P>(a "ghost" section) does not stop it: it exits 0 and commits two sections for one path,validate-family.pysaysfamily ok, and a recursive clone takes the LATER section, so with the ghost second it dies fetching the ghost's URL #300 check already refuses two sections for one path.pathkey,mounted_fromby a name's first key of any kind, andsiblingsby its first url key.Ahas the path;Bhas the path and a url;Ais reopened with a url. Git gives/r/b.git, shape-doctor.py:submodule_configandgitmodules_entryread a holder's.gitmodulesthrough onegit config -z --list, so a section name holding a space or a byte that is not UTF-8, or a url holding NEL or U+2028, gives the doctor the mount url git andmake siblingsuse, under any locale (#668) #700 gives/r/b.git,siblingsgives/r/a.git.Bhas a url only;Ahas the path and a url;Bis reopened with the path. Git gives/r/b.git, while shape-doctor.py:submodule_configandgitmodules_entryread a holder's.gitmodulesthrough onegit config -z --list, so a section name holding a space or a byte that is not UTF-8, or a url holding NEL or U+2028, gives the doctor the mount url git andmake siblingsuse, under any locale (#668) #700 andsiblingsgive/r/a.git.submodule_configandgitmodules_entryread a holder's.gitmodulesthrough onegit config -z --list, so a section name holding a space or a byte that is not UTF-8, or a url holding NEL or U+2028, gives the doctor the mount url git andmake siblingsuse, under any locale (#668) #700'smounted_fromdocstring (shape-doctor.py:7120-7123atfca40dfc) holds for plain sections only. Soften it in this issue's PR, and add a reopened section to the parity list.Lane: openreposhape-3 (openRepoShape-3)
shape-doctor.py: `submodule_config` and `gitmodules_entry` read a hol…
shape-doctor.py and siblings.py: an index or HEAD copy of `.gitmodule…
shape-doctor.py and siblings.py: a `shallow` or `fetchRecurseSubmodul…
tests/test_siblings_inputs.py: `[submodule "a=b"]` mounts and a CR in…
siblings.py: the printed move runs as typed past a taken staging name…
Merge main 40e678e (#805, #690) into l3-733-ignored-sections
siblings.py: a `.gitmodules` section NAME keeps git's bytes, so two n…
validate.yml (assembly-root and family-root templates): the three url…
the family root's bootstrap.py and validate-family.py: the credential…
adopt-project.py (#910, fix round 2): each throwaway `git init` names…