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

From: Sean Whitton <[email-masked]>
Date: Thu, 11 Sep 2025 11:22:35 +0100

Hello,

On Tue 09 Sep 2025 at 11:07am -04, Spencer Baugh wrote:

> No.  It would be format-patch followed by either apply-patch or
> checkin-patch.
>
> format-patch would be "git format-patch"
> apply-patch would be "git apply"
> (a new version of) checkin-patch would be "git am"
> [...]
> The VCS would still be (basically) handling the whole thing.  I'm
> suggesting that we basically just run:
>
> git format-patch | git am
>
> or:
>
> hg import | hg export
>
> Which (I think) is how cherry-picking works under the hood historically
> in git anyway.

Ah, got it.  Nice!  I think this is a better API indeed.

(It would also allow me to reimplement some other useful things from
mailscripts.el in VC, such as applying patches attached to an e-mail, if
we assume those are in a VCS-specific format, as they tend to be these
days.)

> Maybe we could prompt with Log Edit for each commit, even when
> cherry-picking multiple commits?  I guess that would make cherry-picking
> multiple commits quite annoying...
>
> Oh, what if before opening any Log Edit buffers, we prompt the user
> whether they want to edit the commit messages for the commits being
> cherry-picked?  We could give them several options:
>
> - don't manually edit messages but add cherry-pick message to each of them
> - don't manually edit messages and don't add cherry-pick message
> - manually edit all the messages
>
> This would give the user the ability to choose to edit commit messages
> even when cherry-picking multiple commits, which might be nice.
>
> Or... an even more radical idea would be to let them pick and choose
> which commit messages they want to edit, and even allow them to stop and
> edit individual commits in a series.  Similar to git rebase -i.
>
> Actually, don't we need to be able to stop in the middle of
> cherry-picking a series of commits anyway, since we need to be able to
> resolve conflicts?  I think that implies a substantially more rich UI
> then we've been talking about so far...

I've been thinking that if there are conflicts we go into a merge
conflict state for the failed cherry-pick, and abandon all subsequent
cherry-picks.  After the user has resolved that conflict they can
execute another cherry-pick operation to grab the remaining commits.
(We could unmark the commits that were successfully cherry-picked.)

That means we can implement a useful multiple cherry-pick without
blocking on doing a large amount of new UI design, and indeed UI
implementation, up front.

But yeah, certainly, the eventual desiderata would be for some way to
edit commit messages for multiple commits.  Regarding invoking Log Edit
multiple times, that's natural to us as experienced Git users, for sure,
and I thought about it too.  It's fairly clunky though -- for example,
there isn't a natural way to go back a few steps a edit a previous
message again -- and I wonder if we can come up with something nicer.

ISTM that a single buffer in which all the commit messages were
available to edit, somehow, would be more useful, and also minimise UI
confusion, because it would be just like our existing commit UI for VC
where there is a single *vc-log* buffer and then the operation is
atomic.

I guess we would want some sort of major mode that could separate the
buffer into portions?  Or do we want custom.el-style text fields?  WDYT?

>> We already have vc-allow-rewriting-published-history which we can use to
>> protect the user from getting themselves into an inconsistent state by
>> means of these operations.
>
> Hm, I guess you're saying we would allow resetting commits which haven't
> been pushed, but not (with nil vc-allow-rewriting-published-history)
> resetting commits which have been pushed?  That seems reasonable.

Right.

>> So I think we could call this something like
>>
>> - vc-delete-back-to-revision
>> - vc-undo-checkins
>> - vc-undo-checkins-back-to
>> - vc-strip-revisions-back-to
>>
>> ?
>
> vc-undo-checkins might be confusing because actually this command can
> also be used on revisions which weren't created locally by vc-checkin.
>
> The "back-to" names feel a bit verbose/clumsy to me.

Fair.

> What about mentioning tip in the name? For example:
>
> - vc-delete-tip-revisions
> - vc-strip-tip-revisions
> - vc-reset-tip-revisions
>
> Or maybe just vc-reset-revisions on its own would work as a name?  "git
> reset" already only operates on tip, so there's prior art.
>
> I guess if we're going with the "vc-revision-cherry-pick" scheme, we
> might want to match that convention, with e.g. "vc-revision-reset".

I would like to see if we can avoid "reset" because even in Git it means
several different things (most fundamentally, clearing the staging area,
which isn't a thing we recognise in VC anyway).

I think "strip" is the right verb to use.  Also it kind of implies that
you can only strip from the end of the branch, to me, at least.

I'm a bit hesitant about "tip" because it actually appears in the VC UI
with Mercurial, but doesn't always mean the commit that's checked out,
and from which we would strip.  For example if you fetch without
updating your working tree, the tip label will be beyond what you have
and can delete commits from.

In the recent new Info nodes I wrote I talked about the "end" of the
branch, so I would suggest one of these:

- vc-strip-revisions
- vc-strip-end-revisions
- vc-strip-branch-end-revisions
- vc-strip-revisions-at-end
- vc-strip-revisions-from-end

I think I like vc-strip-revisions-from-end most.

-- 
Sean Whitton