git: 59a4b6c2a065 - main - git-mfc: Cherry-pick all commits in one git command

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Fri, 10 Jul 2026 14:46:44 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=59a4b6c2a06512bc7b62fdfe16df4afed355d2e5

commit 59a4b6c2a06512bc7b62fdfe16df4afed355d2e5
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-07-10 14:44:33 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-07-10 14:46:31 +0000

    git-mfc: Cherry-pick all commits in one git command
    
    This allows one to resume from a conflict with a plain
    `git cherry-pick --continue`, whereas before one would have to re-run
    the original git-mfc command after resolving the conflict and running
    `git cherry-pick --continue`.
    
    Suggested by:   des
    Reviewed by:    des
    Differential Revision:  https://reviews.freebsd.org/D58129
---
 tools/tools/git/git-mfc   | 16 +++++++++-------
 tools/tools/git/git-mfc.1 | 11 +++++++----
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/tools/tools/git/git-mfc b/tools/tools/git/git-mfc
index 513a7f150e3c..42fb4f169412 100755
--- a/tools/tools/git/git-mfc
+++ b/tools/tools/git/git-mfc
@@ -360,17 +360,16 @@ def pending(repo, upstream, author=None, committer=None, baking=False):
     return list(results.values())
 
 
-def cherry_pick(commit, edit=False):
-    """Cherry-pick a single commit with -x.  Abort on failure."""
+def cherry_pick(commits, edit=False):
+    """Cherry-pick a list of commits with -x.  Abort on failure."""
     cmd = ['git', 'cherry-pick', '-x', '-m1']
     if edit:
         cmd.append('-e')
-    cmd.append(commit.hexsha)
+    cmd.extend([c.hexsha for c in commits])
     result = subprocess.run(cmd, capture_output=False)
     if result.returncode != 0:
-        print(f"\nCherry-pick of {commit.hexsha} ({commit.summary}) failed.",
-              file=sys.stderr)
-        print("Resolve the conflict and then re-run git mfc to continue,",
+        print("\nCherry-pick failed.", file=sys.stderr)
+        print("Resolve the conflict and run 'git cherry-pick --continue',",
               file=sys.stderr)
         print("or run 'git cherry-pick --abort' to give up.", file=sys.stderr)
         sys.exit(1)
@@ -521,13 +520,16 @@ def main():
                 print(commit.hexsha, commit.summary)
             return
 
+        topick = []
         for commit in tomfc:
             if commit.hexsha in already_picked:
                 print(f"Skipping {commit.hexsha[:12]} {commit.summary} "
                       f"(already cherry-picked)")
                 continue
             print(f"Cherry-picking {commit.hexsha[:12]} {commit.summary}")
-            cherry_pick(commit, edit=args.edit)
+            topick.append(commit)
+        if topick:
+            cherry_pick(topick, edit=args.edit)
 
 
 if __name__ == '__main__':
diff --git a/tools/tools/git/git-mfc.1 b/tools/tools/git/git-mfc.1
index a730eae7ee6b..2594446201c2 100644
--- a/tools/tools/git/git-mfc.1
+++ b/tools/tools/git/git-mfc.1
@@ -68,13 +68,16 @@ Fixup commits that have been reverted are skipped with a warning.
 .Pp
 Commits that have already been cherry-picked to the current branch are
 automatically skipped.
-This allows the same
-.Nm
-command to be re-run after resolving a conflict without re-applying
-earlier commits.
 Use
 .Fl f
 to override this behavior.
+.Pp
+All commits are cherry-picked using a single
+.Xr git-cherry-pick 1
+invocation.
+If a conflict occurs, resolve it and run
+.Dq git cherry-pick --continue
+to proceed with the remaining commits.
 .It
 In
 .Fl -pending