[PATCH b4 0/6] review-tui: worktree-aware takes, resolve take->merge conflicts in place

Christian Brauner <[email protected]> Tue, 23 Jun 2026 18:01:28 +0200
Newsgroups org.kernel.linux.tools
Message-ID <20260623-20260623-review-tui-take-am-worktree-v1-0-e8a2140a287e@kernel.org>
b4 review's "take" action applies a reviewed series to a target branch by
one of two methods: a merge (git merge) or a linear/cherry-pick apply (git
am). Review is often driven from a different worktree than the one the
series is applied into, and the target branch may be checked out in yet
another worktree, so a take has to run wherever the target branch lives and
never disturb the current checkout. This series makes both take methods do
that correctly and teaches take->merge to resolve conflicts in place.

Worktree handling (take->am and take->merge):

  - take->am checked the target branch out in the *current* worktree, so
    applying to a branch already checked out elsewhere failed outright
    ("fatal: 'vfs.fixes' is already used by worktree ..."), and otherwise
    clobbered whatever was checked out where review was being driven from.
    It now runs git-am in the worktree that holds the target branch, or a
    throwaway one when it is checked out nowhere.

  - take->merge already picked that worktree, but its "git merge --abort"
    (and the non-interactive merge used by the tests) still ran in b4's own
    cwd. On a conflict that left the markers in the target worktree while
    rewriting b4's checkout from the target's index -- silently dirtying one
    worktree and clobbering another. Both calls are now anchored to the
    target worktree.

  - Both methods need the same "find or create the right worktree, then
    clean up after" dance, so it is factored into one _take_worktree()
    context manager shared by merge and am.

In-place conflict resolution:

  A conflicting take->merge used to abort the merge and discard the take,
  forcing the user to start over. take->am already drops the user into a
  shell to finish (or abort) the conflict by hand; take->merge now does the
  same, matching "b4 shazam". Finishing the conflicted merge in place keeps
  the merged-in side fully reachable, so no commit is silently dropped --
  unlike "b4 shazam --resolve", which replays patches with "git apply
  --3way" + "git add -u" and so omits a patch that only adds a new file. The
  shared "drop to a shell, then check what the user did" logic is factored
  into _resolve_worktree_take_conflict() and used by both methods.

Concretely, a conflicting take->merge reports the conflict and drops you
into a shell (prompt marked "(b4 conflict)") in the target worktree; you
finish the merge and Ctrl-d back to the review UI:

    CONFLICT (content): Merge conflict in fs/namei.c
    Merge conflict:
    You can resolve the conflict now.
    ... When done, Ctrl-d to return to review UI.
    (b4 conflict) $ git add -A
    (b4 conflict) $ git merge --continue
    (b4 conflict) $ exit
    Conflict resolved, series merged.
    Merged b4/review/vfs-fixes into vfs.fixes
    Press Enter to continue...

Exiting with the merge unfinished -- or "git merge --abort" -- drops the
take instead of recording it.

Signed-off-by: Christian Brauner (Amutable) <[email protected]>
---
Christian Brauner (6):
      review-tui: factor cross-worktree take setup into _take_worktree
      review-tui: run take->am in the target branch's worktree
      review-tui: test cross-worktree takes
      review-tui: run take->merge abort in the target branch's worktree
      review-tui: resolve take->merge conflicts in place
      review-tui: test take->merge conflict resolution

 src/b4/review_tui/_tracking_app.py | 353 +++++++++++++++++++-----------
 src/tests/test_tui_tracking.py     | 426 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 653 insertions(+), 126 deletions(-)
---
base-commit: 42c0c1e6eccec7b067aa8072bf3a77c43f9fc0bd
change-id: 20260623-20260623-review-tui-take-am-worktree-98ca83e85e06