Repository navigation
adopt-project.py: a source whose .git/refs/heads this user cannot read is refused source-default-branch-not-local with (its branches: none), a false list, where the refusal should name the directory git could not list #1219
Description
Goal: a source whose .git/refs/heads this user cannot read is refused by name, source-unreadable naming that directory with the chmod cure, and never source-default-branch-not-local over a list of branches that is empty only because git could not list the directory.
Filed by lane openRepoShape-3, from RV1186's independent review of #1186 (#1151) at 07486a49 (#1186 issuecomment-6354299332), its follow-up under "An issue": .git/refs/heads at mode 000 (cloned: true) gives source-default-branch-not-local "(its branches: none)" "on main and at this head alike", "a false answer, outside #1151". It did not hold the landing: #1186 is READY and open at 07486a49, on milestone v1.2.1. RV1186's probe was uid 1000, git 2.43.0 and Python 3.12.3, with a stub gh and local remotes. Line numbers are main's at ef619c74. The defect is on main now, and #1186 does not touch it.
The branch list is asked once, and an empty answer is believed
State.
_branch_names(adopt-project.py:3091) runsgit for-each-ref --format=%(refname) <prefix>and returns what it prints._default_branch(:2943) asks it forBRANCH_REFS(refs/heads/,:9673) at:2996, andSource._at(:2779) calls_default_branch(:2781) for every mode that opens a source.- Where neither the default branch nor
insteadis in the list,_no_branch_of_its_own(:3007) raisessource-default-branch-not-local, whose detail ends(its branches: <list>)through_branches_named(:4909, "nonewhere there are none"). - Other callers ask git the same way and are as blind:
_from_the_remote(:3044,_branch_namesoverORIGIN_BRANCHES,refs/remotes/origin/, at:3053: where the branch is not there it says to askoriginagain),_cloned_branch(:10316) and_branches_of(:4891, its ownfor-each-refover both prefixes, behind_tracking_branch_problem,:4918). - Nothing asks whether the directory could be listed. adopt-project.py: a
--source, or a plan'ssource.local_path, with a part of its repository git reads at mode 000 (the.git, itsHEAD,objects,refsorconfig, the git directory agitdir:line names, or a directory above it) is refusedsource-unreadablenaming that part, nevergit-failedand never cloned again (#1151) #1186's_refused_git_path, by its body (it is not on main), asksobjectsandrefs, each searched, and no directory belowrefs.
What happens. RV1186, measured on main and at #1186's head: with .git/refs/heads at mode 000 and cloned: true, the run is source-default-branch-not-local with "(its branches: none)". The source has branches; the list is empty because git could not list the directory, which is the system's refusal and not the source's. The refusal's own advice, to check out a branch or to run plan with --tracking-branch naming one "the source has", then points away from the cure, a chmod. Read from the code (not measured), the same empty answer follows for refs/remotes/origin at mode 000 (_from_the_remote then says origin has no such branch either) and for a nested directory under refs/heads (a branch feature/x lives in refs/heads/feature).
Direction. Ask before believing an empty list, and refuse source-unreadable (the code at :1959 and _source_unreadable at :2045, both existing, with the permission cure), naming the directory this user cannot list. No new command and no flag.
-
Ask by LISTING the directory, as git does, and not by a search (
access(X_OK)), which is how adopt-project.py: a--source, or a plan'ssource.local_path, with a part of its repository git reads at mode 000 (the.git, itsHEAD,objects,refsorconfig, the git directory agitdir:line names, or a directory above it) is refusedsource-unreadablenaming that part, nevergit-failedand never cloned again (#1151) #1186 asksobjectsandrefs: a directory at mode--xcan be searched and not listed. The writer measures mode 000 and--xfirst, and whatfor-each-refdoes for each. -
Cover each directory git descends under
refs/heads(a nested branch name) andrefs/remotes/originfor_from_the_remote, or say in the PR why not. -
If adopt-project.py: a
--source, or a plan'ssource.local_path, with a part of its repository git reads at mode 000 (the.git, itsHEAD,objects,refsorconfig, the git directory agitdir:line names, or a directory above it) is refusedsource-unreadablenaming that part, nevergit-failedand never cloned again (#1151) #1186 has landed, the natural place is beside its_refused_git_path; if not, in_branch_names. -
The tests go in
tests/test_adopt_tracking_branch.py, which already pins this refusal (NOT_LOCAL,:303, and its rows from:410), or in adopt-project.py: a--source, or a plan'ssource.local_path, with a part of its repository git reads at mode 000 (the.git, itsHEAD,objects,refsorconfig, the git directory agitdir:line names, or a directory above it) is refusedsource-unreadablenaming that part, nevergit-failedand never cloned again (#1151) #1186'stests/test_adopt_unreadable_git_parts.pyonce that lands. -
A plan recording
cloned: trueover a source whose.git/refs/headsis at mode 000 (RV1186's case), undercheckandexecute:REFUSED source-unreadable, exit 2, naming that directory, with thechmodcure, and notsource-default-branch-not-local. The row fails before and passes after. -
plan --sourceover the same source: the same refusal. -
A nested directory under
refs/headsat mode 000: the same, naming it. -
refs/remotes/originat mode 000 whereorigin/HEADnames the branch: the same, and not "askoriginfor its default branch again". -
A source that really has no branch of its own is still
source-default-branch-not-localwith(its branches: none): the file's existing rows pass unchanged. -
A readable source costs nothing new.
Related: #1186 and #1151 (the parts of a source's .git at mode 000), #1141 (the recorded source's .git itself), and #457 (the tracker for adopt-project.py, converting an existing repository in place).
Size: S.
Lane: openreposhape-3 (openRepoShape-3)
Activity
brettheap commentedon Oct 23, 2026
CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-23T18:40:21Z, for #1219
Logged in
lanes/log/openRepoShape-3.mdat3a9e46d3131ffb379a752c531feef2d2afec69ce.The three reads (lane-collision-protocol Rule 1):