Subject: bug#79408: 31.0.50; VC commands for cherry-picking

From: Spencer Baugh <[email-masked]>
Date: Mon, 08 Sep 2025 14:56:34 -0400

Sean Whitton <[email-masked]> writes:

> X-debbugs-cc: [email-masked], [email-masked], [email-masked], [email-masked]
>
> Hello,
>
> I'd like to add VC commands to cherry-pick changes.

Exciting!

> These are my proposed additions to the VC API:
>
> ;; - cherry-pick (files comment rev reverse)
> ;;
> ;;   Copy a REV's changes, log message, author and author timestamp as a
> ;;   new commit on the current branch.  If REVERSE, reverse REV's changes.
> ;;   FILES is for forward-compatibility; existing implementations aren't
> ;;   able to limit the changes copied from REV to those made to FILES.
>
> ;; - cherry-apply (files rev reverse)
> ;;
> ;;   Copy REV's changes to FILES to this working directory.  If REVERSE,
> ;;   reverse REV's changes.  (When REVERSE is nil, typically REV will be
> ;;   a revision from another branch.)

This reminded me of how we don't have a way to do format-patch using vc;
that's somewhat related, and would be nice to support.

In fact, I wonder if perhaps:

- a new format-patch backend function

- a new apply-patch backend function (to take advantage of better
  backend-specific merging)

- maybe a fancier checkin-patch backend function

Could replace the need for these specialized backend functions?

(I think git-cherry-pick used to be implemented as format-patch + apply
under the hood, years ago)

> ;; - cherry-pick-comment (files rev reverse)
> ;;
> ;;   Return a string to be appended to the log message when
> ;;   cherry-picking REV onto another branch.  This is Git's "(cherry
> ;;   picked from commit ...)" and Mercurial's "(grafted from ...)",
> ;;   or if REVERSE, Git's "This reverts commit ...".
> ;;   FILES is for forward-compatibility; existing implementations care
> ;;   only about REV.
>
> These are my proposed commands:
>
> vc-cherry-pick:
>  - Gets the log message for REV with get-change-comment API function.
>  - Gets the string to append with cherry-pick-comment API function.
>  - Puts these together, starts a Log Edit session for the user to amend
>    the message (e.g. for Git, doing C-c C-s to add a sign-off).
>  - On C-c C-c, calls the cherry-pick API function for the backend to do
>    the cherry-pick.
>    Examples: vc-git-cherry-pick would invoke 'git cherry-pick' or
>    'git revert' depending on whether REVERT.
>    vc-hg-cherry-pick would invoke 'hg graft' or 'hg backout'.
>
>  Will have vc-checkin's COMMENT, INITIAL-CONTENTS arguments so calling
>  from Lisp can skip the Log Edit session.
>
>  A prefix argument might toggle whether to append the cherry-pick
>  comment.

That sounds like a bit of a waste of the prefix argument, since the user
could always just delete that comment.  I think we'd be better off just
not having the prefix argument do anything for now, and maybe we'll find
a better use in the future.

>  We'll be expecting the user to invoke this from Log View mode.  If
>  multiple commits are marked, then I think we have to skip the Log Edit
>  session, for now, because we don't have a nice way to prompt for
>  multiple messages.

This sounds reasonable.

I personally rarely care about editing the commit message, but it's not
hard for me to just hit C-c C-c.

> vc-undo-revision (vc-revert is taken):
>  Same as vc-cherry-pick, except passes REVERSE non-nil at the
>  appropriate points.  No prefix argument.

Maybe we could name it vc-revert-revision?

Actually maybe we should name the commands something like:

vc-revision-cherry-pick
vc-revision-cherry-pick-apply
vc-revision-revert
vc-revision-revert-apply

To display more directly how they're closely related and symmetric.

> vc-cherry-apply:
>  The advantage of having a backend API function for this is that the
>  backend can use its full merging logic.
>  A generic vc-default-cherry-apply can be implementated similarly to
>  vc-apply-to-other-working-tree.

Right.  I assume that generic implementation would use the 'diff backend
function.  And the sole disadvantage of such a generic implementation is
that it would have less smart merging.

I wonder, could we enhance diff-mode's ability to do conflict
resolution?  Maybe it can talk to vc for this, maybe using an
apply-patch backend function like I suggested above?

> vc-undo-apply:
>  Like vc-cherry-apply except passes REVERSE non-nil at the appropriate
>  point.  Similarly there can be a vc-default-reverse-cherry-apply.

That sounds good, but...

I wonder if we even need to support vc-cherry-apply and vc-undo-apply?
At least right now.

Two very different reasons why we might not want those:

- Those seem primarily useful when you want to actually edit the diff
  before committing.  But, it seems to me that using diff-mode for such
  an operation is already pretty natural, and should be encouraged.

  The way I do those two operations today in hg is:
  - Open up vc-print-log starting at some revision
  - Find the revision I want to revert or cherry-apply
  - Hit d or D to open up the diff
  - Use diff-mode to do the editing

  Perhaps that is sufficient?

- In a completely different direction: what if we only supported
  cherry-pick, but also added support for git reset --soft?  In git, I
  often do cherry-apply by just cherry-picking and then resetting.  This
  is a bit weird, but it might save us some complexity if we want to
  support git reset --soft anyway?