How do I cherry-pick a single revision in Mercurial?

35,394

Solution 1

Tonfa is right. What you're describing isn't 'merging' (or 'pushing' or 'pulling'); it's 'cherry-picking'. A push or a pull moves all the changesets from one repo to another that aren't already in that repo. A 'merge' takes two 'heads' and merges them down to a new changeset that's the combination of both.

If you really need to move G over but can't possibly abide having D,E,F there you should 'hg export' G from repo A, and then 'hg import' it in repo A. The Transplant extension is a wrapper around export/import with some niceties to help avoid moving the same changeset over multiple times.

However, the drawback to using import/export, transplant, and cherry-picking in general is that you can't really move over G without its ancestors, because in Mercurial a changeset's name is its 'hashid' which includes the hashids of its parents. Different parents (G's new parent would be C and not F) means a different hashid, so it's not G anymore -- it's the work of G but a new changeset by name.

Moving over G as something new, let's call it G' (Gee prime), isn't a big deal for some uses, but for others it's a big pita. When soon repo B get's a new changeset, H, and you want to move it over its parent will be changing from G to G', which have different hashes. That means H will move over as H' -- 100 changesets down the line and you'll have different hashids for everything all because you couldn't stand having D,E,F in repo A.

Things will get even more out of whack if/when you want to move stuff from Repo A into Repo B (the opposite direction of your earlier move). If you try to do a simple 'hg push' from A to B you'll get G' (and H' and by subsequent descendants) which will be duplicates of the changesets you already have in Repo B.

What then, are your options?

  1. Don't care. Your data is still there you just end up with the same changesets with different names and more work on future exchanges between the two repos. It's not wrong, it's just a little clumsy maybe, and some folks don't care.
  2. Move all of D,E, and F over to Repo A. You can move all the changesets over if they're harmless and avoid all the hassle. If they're not so harmless you can move them over and then do a 'hg backout' to undo the effects of D,E and F in a new changeset H.
  3. Give G better parentage to begin with. It's mean for me to mention this because it's too late to go this route (without editing history). What you should have done before working on changeset G was to hg update C. If G doesn't rely on or require changesets D,E, and F then it shouldn't be their kid.

If instead you update to C first you'll have a graph like this:

A - B - C - D - E - F
          \
            G

then, the whole answer to this question would just be hg push -r G ../repoA and G would move over cleanly, keeping its same hashid, and D, E, and F wouldn't go with it.

UPDATE:

As pointed out in the comments. With modern Mercurials the hg graft command is the perfect way to do this.

Solution 2

Refering to the title, which addresses cherry picking in general, I give the example of working in one repo, as internet search engines might bring people here for cherry picking in general. Working in one repository, it would be done with hg graft:

hg update C
hg graft G

The result is:

            G'
          / 
A - B - C - D - E - F - G

Extra warning: The two changesets will be treated as independent, parallel commits on the same files and might make you run into merge conflicts, which is why cherry picking should be avoided in general for branch management. For example, if G is a bug fix applied to a stable version branch bookmarked as 1.0.1, you should rather merge the freeze branch with it, and from time to time merge the master branch with the freeze branch's bugfixes.

Share:
35,394
Tom Hubbard
Author by

Tom Hubbard

Updated on February 23, 2020

Comments

  • Tom Hubbard
    Tom Hubbard about 4 years

    In Mercurial/TortoiseHg, given the following example, what is the easiest way to merge revision "G" into repo A without taking D,E and F (Assume that G has no dependency on D,E or F).

    Repo A: A - B - C
    
    Repo B (Clone of A) A - B - C - D - E - F - G
    

    Is a patch the best bet?

  • Ry4an Brase
    Ry4an Brase over 14 years
    Using rebase is a form of 'editing history'. It does change the hashids, which if you've not yet pushed them out to the world is perfectly cool. If you have done so then everyone will see the same changesets twice and etc.
  • Helgi
    Helgi almost 12 years
    I'd like to note that since Mercurial 2.0, graft should be used instead of transplant whenever possible, as it uses the internal merge machinery instead of rejecting conflicts. See also stackoverflow.com/a/8010738/67988.
  • Sophie McCarrell
    Sophie McCarrell about 10 years
    Am I the only one who think the tone of this answer is suggesting Cherry-picking is something that should never be done? What are you supposed to do if you make 2 commits on the wrong branch and need to move those commits over. Cherry-picking is exactly designed for this. It's not wrong.
  • Ry4an Brase
    Ry4an Brase about 10 years
    The tone is saying "cherry picking shouldn't be part of your normal workflow". In your example you're fixing a mistake ("on the wrong branch") so by all means cherry pick. But people who build complex workflows where the plan is "and then we cherry-pick the bug fixes from default to the stable release branch" are doing things the hard way and will make their future merges harder yet. There's value in an answer pointing out "what you're asking how to do is usually a bad idea" before it tells you how to do it.
  • crazyGuy
    crazyGuy over 6 years
    there you should 'hg export' G from repo A - @Ry4anBrase do you mean from repo B?
  • LovesTha
    LovesTha about 6 years
    I've been trying to use graft this way with mercurial, it doesn't do what one expects. Export patch, import patch does what one would expect graft to do.
  • LovesTha
    LovesTha about 6 years
    Except 'hg graft G' brings in many of the changes in D, E, & F. Export patch, import patch works as one would expect graft to work.
  • Iodnas
    Iodnas about 6 years
    'hg graft G' on C creates a new head/branch. Why do you think it can bring any changes in the D ... G branch?
  • LovesTha
    LovesTha about 6 years
    Because I've tried it several times and it does. I really want it not to, but it does.
  • borievka
    borievka almost 4 years
    @Ry4anBrase And what is the easy way for back-porting fixes to the frozen/stable release, which can't have new features from the next versions? I stumbled upon this thread when dealing with this situation, so I'd like to find my other possibilities.
  • Antony Gibbs
    Antony Gibbs almost 3 years
    @LovesTha seems you must have missed out that before cherry picking you should create a different branch (all the point of cherry picking is that when merging two branches that commit only applies once). Applying cherry pick in same branch doesn't make sense :) - I found this cheat sheet helpful gist.github.com/cortesben/016cd401faae5a8dae59 and using hg graft -r 1234 worked as expected, applying only rev 1234 into my current branch.
  • LovesTha
    LovesTha almost 3 years
    @AntonyGibbs That may have been useful, Iodnas believes it creates a new branch, so I can see how Mercurial's perpetration was opaque to me. Luckily Atlassian dropping Mercurial solved my need to worry about how mercurial works.
  • Iodnas
    Iodnas almost 3 years
    @LovesTha "hg graft" does create a new head in the case shown above, not a new branch. But the new head can be bookmarked, and bookmarks are a lightway method of doing branch management in Mercurial. Apart from that, I'd like to emphazise that I cannot find a use case that would actually justify cherry picking via "hg graft". Good version- and branch management avoids the need of cherry picking in my opinion.
  • LovesTha
    LovesTha almost 3 years
    @Iodnas sure, it would be great if it did. But it doesn't. Or at least it didn't in 2018.
  • Iodnas
    Iodnas almost 3 years
    I've testet it now again and it does create a new head as I mentioned, and also you are right it does not only take the changes of the grafted changeset and puts them on top of the changeset "C", but asks you in a merge to consider the changes of D-F in between, by default adding only the changes of "G". I guess this is what you are referring to when stating in the original message that it brings in the changes between the changesets. In my test I can just accept the changes of the grafted one, but the merge might become more complicated when doing on a normal project.