Re: [PATCH b4 0/5] shazam: stop --resolve from silently dropping commits

Christian Brauner <[email protected]> Wed, 24 Jun 2026 10:35:51 +0200
Newsgroups org.kernel.linux.tools
Message-ID <20260624-querulant-herzform-unmodern-faf5463919ef@brauner>
On 2026-06-24 01:41 +0200, Christian Brauner wrote:
> b4 shazam --resolve exists to help land a series that doesn't apply
> cleanly. The problem that motivated this series is that, while resolving,
> it can silently drop whole commits from the merge it produces: you end up
> with a merge that is quietly missing changes, and nothing in the output
> points at what went missing.
> 
> Why they vanish
> 
> When git am can't apply the series, the old --resolve path merged the
> patches that did apply, then replayed each remaining patch with
> "git apply --3way" and staged the result with "git add -u".
> 
> git apply --3way can only do its three-way merge if the blob IDs recorded
> in the patch's "index <old>..<new>" lines are present in your object
> store. For patches that arrived over email those blobs usually aren't
> there -- which is frequently the very reason git am -3 failed to begin
> with. In that case git apply --3way falls back to a plain apply, fails
> with "patch does not apply", and exits non-zero having written nothing at
> all: no conflict markers, no unmerged index entries.
> 
> The replay loop assumed any non-zero exit meant "conflict markers are in
> the tree." It advanced past the patch and asked you to resolve conflicts
> that did not exist, so b4 shazam --continue happily resumed at the next
> patch. The skipped patch's changes never entered the merge -- they were
> simply gone, with no warning. A patch that only adds a new file can
> disappear the same way when it rides along with a change that can't be
> applied.
> 
> How this fixes it
> 
> Stop replaying patches with git apply entirely. On a conflict, b4 already
> leaves the in-progress git am parked in a throwaway worktree; keep it
> there and finish it natively:
> 
>     cd <worktree printed by b4>
>     # resolve the conflicted files
>     git am --continue        # or: git am --skip
> 
> git am drives the whole remaining series through git's own machinery,
> which stops on every patch it cannot apply and never silently skips one.
> Once it is done, b4 shazam --continue fetches the fully-applied series and
> merges it exactly once -- the same merge a clean b4 shazam makes. Because
> every patch now goes through git am, nothing can vanish. This also brings
> --resolve in line with how the review TUI already resolves conflicts.
> 
> Since both now resolve am conflicts the same way, the series starts by
> lifting the worktree plumbing the TUI already had -- detecting an
> in-progress git am, and fetching the finished result out of the worktree
> before dropping it -- into b4 core, and shazam reuses it rather than
> growing its own copy.
> 
> Resolving conflicts in subdirectory files
> 
> One gap hid behind that guarantee. The series is applied in a sparse
> worktree where only root-level files are materialized, and git's 3-way
> merge refuses to touch skip-worktree paths. So a conflict in a
> subdirectory file -- the common case for real series -- still made
> git am -3 abort with a clean index: no markers, nothing to resolve. The
> user was pointed at a conflict that was not there, git am --continue
> dead-ended, and git am --skip silently dropped the patch. Only root-file
> conflicts, which the tests happened to use, ever worked.
> 
> git_fetch_am_into_repo now rebuilds a full worktree on a conflict before
> handing it back -- abort the partial am, disable sparse-checkout, replay --
> so the conflict is recorded with real markers to resolve. b4 shazam
> --resolve and the review TUI both apply through this one function, so both
> are fixed, and a regression test drives a subdirectory conflict end to end.
> 
> The same commit hardens the rest of the flow: b4 shazam --abort no longer
> crashes on a corrupt state file, --continue refuses up front on a dirty
> working tree (keeping its state so it stays re-runnable), a failed
> worktree fetch leaves the resolved am in place to retry, and the docs now
> note that --continue merges with -M and leaves FETCH_HEAD with -H.
> 
> Signed-off-by: Christian Brauner (Amutable) <[email protected]>
> ---

v2 will be coming shortly.