Thread (3 messages) flat view 3 messages, 1 author, 22d ago
COLD22d

[PATCH 0/2] branch: fix --recurse-submodules with a nameless start point

From: Volodymyr Vriukalo <hidden>
Date: 2026-08-21 23:02:19

vv/branch-recurse-no-start-ref

"git branch" with submodule.propagateBranches enabled mishandled a
start point that names no ref, such as a raw object id.  In a
repository with no submodules it aborted with a BUG after having
already moved the branch; with submodules it failed earlier, when the
helper it invokes rejected a truncated argument list.  Both are the
same missing tracking name, which has been corrected.

I hit the first of these while scripting a branch rewrite -- the sort
that moves a branch to a commit no ref points at yet, which for such a
script is the ordinary case rather than the exception:

    BUG: refspec.c:442: refspec_find_match: need either src or dst
    Aborted (core dumped)

The ref had already been updated.  So the abort is loud and the damage
is quiet, which is the wrong way round: an exit status of 134 on an
operation that in fact completed will fool any caller that checks it,
and one whose error path rolls back will helpfully undo a successful
update.

The exposure is bounded.  submodule.propagateBranches is documented as
experimental, and reproducing it needs all four of that setting,
submodule.recurse, a configured remote, and a start point that is not a
ref name; drop any one and the command succeeds.  Within those bounds
it is not exotic -- a script that moves a branch by object id hits it
on the first attempt, the commit it wants having no ref on it yet,
which is rather the point of moving a branch.  It reproduces
identically on 2.54.0, 2.55.0 and master, which is why this is based on
maint.

Both patches guard at the call site rather than inside the callee.
That follows create_branch(), which already declines the same value
with "if (real_ref && track)", and it leaves setup_tracking()'s own
convention intact: it opens by BUG()ing on a caller that should not
have called it, so absorbing a NULL quietly would contradict that four
lines later.  Neither patch changes anything for a start point that
does name a ref.

This series was written with LLM assistance, recorded as an
"Assisted-by: An LLM." trailer on both patches.  I used it for the
whole change rather than as step-by-step guidance, because at this
size the distinction is irrelevant: two guards and two tests, short
enough to read in full.  I have read the surrounding code and checked
every claim in the commit messages against the source myself.

Two things I would welcome direction on.

dwim_and_setup_tracking() carries the same unguarded call.  It survives
only because its single caller passes BRANCH_TRACK_OVERRIDE, under
which dwim_branch_start() dies rather than returning NULL -- safe by an
argument its caller happens to pass, not by anything in the function
itself.  Nothing enforces that, so a future caller could reintroduce
the same abort.  I left it alone to keep the series to the bug I
actually hit, but I am happy to add a third patch.

The first test uses no submodule, because the bug does not need one.  I
put it in t3207 since create_branches_recursively() is only reached
under submodule.propagateBranches, but t3200 is a perfectly defensible
home and I will move it on request.

The series merges cleanly into next and seen; both merge results build
and pass t3200 and t3207, and the full suite passes on the topic
itself.

---
Volodymyr Vriukalo (2):
      branch: do not track a start point with no ref
      branch: allow recursion with no tracking name

 branch.c                    | 12 ++++++++++--
 builtin/submodule--helper.c |  7 ++++---
 t/t3207-branch-submodule.sh | 30 ++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 5 deletions(-)
---
base-commit: e9019fcafe0040228b8631c30f97ae1adb61bcdc
change-id: 20260822-vv-branch-recurse-no-start-ref-31fac1e34eab

Best regards,
--  
Volodymyr Vriukalo [off-list ref]
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help