views:

1028

answers:

2

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?

+12  A: 

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 repo 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 their 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.

Ry4an
Thank you very much.
Tom Hubbard
Actually, I guess the `rebase` extension would work.
Matthieu M.
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.
Ry4an
A: 
hg init A
cd A
echo A > A
hg ci -Am A
echo B > B
hg ci -Am B
echo C > C
hg ci -Am C
hg clone ../A ../B
cd ../B
echo D > D
hg ci -Am D
echo E > E 
hg ci -Am E
echo F > F
hg ci -Am F
echo G > G
hg ci -Am G
# cherrypick  
hg update -C 5         #G-1
hg revert -a -r 2      #C
hg ci -m tmp
hg merge 6             #G
hg debugsetparents 2   #C
hg ci -m GNEW
hg strip 7             #tmp
hg push -r tip ../A
Vitali Filon
Could you describe whats going on here a bit?
Tom Hubbard