Skip to content

Resolve a branch = . declaration before it reaches a refspec - #804

Merged
alexander-yevsyukov merged 2 commits into
masterfrom
pull-resolve-dot-branch
Oct 16, 2026
Merged

alexander-yevsyukov merged 2 commits into
masterfrom
pull-resolve-dot-branch

Conversation

@alexander-yevsyukov

Copy link
Copy Markdown
Contributor

./config/pull floats each config-managed submodule — config itself plus
every submodule declaring a tracked branch in .gitmodules — with
git fetch origin <branch>, git checkout <branch>,
git merge --ff-only origin/<branch>, taking <branch> straight from the
.gitmodules entry.

gitmodules(5) gives . a special meaning: the branch in the submodule should
carry the same name as the current branch in the current repository. It is a
sentinel, not a ref. Reproduced against the pre-fix script:

Floating 'shared' -> origin/.
fatal: invalid refspec '.'
  WARNING: could not float 'shared' to origin/.; left as-is.

The value is now resolved to the current branch name before anything is
printed or touched, so the message names the real branch. This mirrors, step
for step, the fix init-submodules received in #802, where a Codex review
spotted this same gap in pull. Keeping the two scripts in step about how a
tracked branch is read is the point — it was left out of #802 only because it
is pre-existing, affects already-checked-out submodules that #802 does not
touch, and would have widened a reviewed three-file diff.

The detached-superproject path

A detached superproject has no branch name to inherit, and pull — unlike
init-submodules, which floats only a submodule it has just cloned — acts on
submodules that are already checked out and in use. Guessing a branch could
move one off the commit it is on, so the entry is skipped outright.

Worth a reviewer's eye: skipping outright also skips that entry's
git submodule update --init. That is deliberate — with the default
checkout strategy, the command resets an already-floated submodule to the
superproject's pin, so running it would be the opposite of "left as-is". The
consequence is that a submodule not yet checked out stays that way here;
init-submodules, which initializes before it resolves ., remains what
materializes it. The comment in the diff says so.

Verification

Throwaway superproject + submodule remotes under a temp dir, running the real
./config/pull through a throwaway config submodule:

case result
superproject on feature, branch = . Floating 'shared' -> origin/feature; submodule advanced to the feature tip and landed on the branch, not detached
superproject detached, branch = . warns, submodule left at the exact commit and detached state it was in, exit code unchanged (0)
ordinary branch = master byte-identical to the pre-fix output; a second run is a no-op
. resolving to a branch the submodule remote lacks falls into pull's existing float-failure warning, naming the resolved branch

The detached case, verbatim:

  WARNING: 'shared' tracks the superproject's branch ('.'), which is detached here; left as-is. Re-run from a branch to float it.

bash -n and shellcheck are clean — shellcheck reports only the
pre-existing SC1091 info on source migrate, identical before and after. A
shell-only diff has no Gradle build target, and config has no root
version.gradle.kts, so the version gate does not apply.

Nothing in Spine declares . today (all 20 local checkouts with a tracked
branch use the literal master), so this is latent robustness rather than a
live outage.

🤖 Generated with Claude Code

`./config/pull` floats each config-managed submodule with
`git fetch origin <branch>`, taking `<branch>` straight from the
`.gitmodules` entry. gitmodules(5) gives `.` a special meaning — the branch in
the submodule should carry the same name as the current branch in the current
repository — so it is a sentinel, not a ref. Passed through as-is, it makes
`git fetch origin .` die with `fatal: invalid refspec '.'`, so the float
warned about a nonexistent `origin/.` and left the submodule wherever it was.

The value is now resolved to the current branch name before anything is
printed or touched, so the `Floating ... -> origin/<branch>` message names the
real branch. This mirrors, step for step, the fix `init-submodules` received
in #802, keeping the two scripts in agreement about how a tracked branch is
read.

A detached superproject has no branch name to inherit. Unlike
`init-submodules`, which floats only a submodule it has just cloned, this loop
acts on submodules that are already checked out and in use, so guessing a
branch could move one off the commit it is on. Such an entry is therefore
skipped outright, which also skips its `git submodule update --init` — the
point of skipping, since with the default `checkout` strategy that command
resets an already-floated submodule to the superproject's pin. A submodule not
yet checked out consequently stays that way here, and `init-submodules`, which
initializes before it resolves `.`, remains what materializes it. The warning
says that re-running from a branch is what makes the entry float.

Everything else about the loop, including its structure and its non-fatal exit
behavior, is unchanged; a declaration naming an ordinary branch produces
byte-identical output.

Nothing in Spine declares `.` today, so this is latent robustness rather than
a live outage. Found by a Codex review of #802.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@alexander-yevsyukov alexander-yevsyukov self-assigned this Oct 16, 2026
@alexander-yevsyukov alexander-yevsyukov moved this to In Review in v2.0 Oct 16, 2026
@alexander-yevsyukov
alexander-yevsyukov requested a balanced review from Copilot October 16, 2026 21:52

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f1423f5e0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pull
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T21:53:45.738564Z f1423f5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

The localized change resolves inherited branches before mutation and safely skips detached states, with no unresolved findings.

No open issues 🎉

What changed in this PR

Updates config/pull to resolve Git’s branch = . sentinel before floating tracked submodules.

Changes:

  • Resolves . to the superproject’s current branch.
  • Warns and skips the entry when detached, leaving the submodule untouched.
  • Documents the implementation and verification.
File Description
pull Resolves inherited branches before submodule operations.
.agents/​tasks/​pull-resolve-dot-branch.md Records rationale, implementation plan, and verification results.

Review effort: Balanced

@alexander-yevsyukov
alexander-yevsyukov merged commit 6356d50 into master Oct 16, 2026
2 checks passed
@alexander-yevsyukov
alexander-yevsyukov deleted the pull-resolve-dot-branch branch October 16, 2026 21:54
@github-project-automation github-project-automation Bot moved this from In Review to ✅ Done in v2.0 Oct 16, 2026
alexander-yevsyukov added a commit that referenced this pull request Oct 19, 2026
`git rev-parse --abbrev-ref HEAD` shortens a ref to a *non-ambiguous* name, so
a superproject that carries both a branch and a tag called `foo` resolves `.`
to `heads/foo`. That is not a no-op: the fetch of `heads/foo` succeeds, the
following `git checkout heads/foo` then fails in the submodule, and the float
leaves the submodule stale and detached at the superproject's pin while
warning about `origin/heads/foo`.

`git branch --show-current` prints the branch name exactly and prints nothing
when `HEAD` is detached, so it both fixes the ambiguity and keeps signalling
detachment. `git symbolic-ref --short` is no alternative — it applies the same
shortening and returns `heads/foo` too, which the throwaway repo confirmed.
The `[ "$branch" = "HEAD" ]` half of the detachment guard is dropped along
with the old command, since `--show-current` never prints that.

`init-submodules` resolves `.` the same way on the unmerged branch of #802 and
needs the identical change; the two scripts are kept in step deliberately.

Reported by the Codex review of #804.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
alexander-yevsyukov added a commit that referenced this pull request Oct 19, 2026
`#804` merged without the review fix it had just taken: config's auto-merge
fired about two minutes before `6a39f556` was pushed, so the merge commit's
branch-side parent sits one commit below it. The PR reads "merged" with green
checks while `master` still ships the bug the review reported.

The task's `status` is `in-review`, not `done`, so the plan file is kept rather
than deleted: `.agents/tasks/README.md` ties deletion to the work having landed
on `master`, and half of it did not. The remaining step is the re-land, and it
is checked with `git merge-base --is-ancestor` rather than the PR's merged
state, which was true for `#804` while the fix was absent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

2 participants