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

Volodymyr Vriukalo <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <20260822-vv-branch-recurse-no-start-ref-v1-0-46dc140acaa8@zitro.id>
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 <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.