Search code examples
mercurialrebasetransplant

Mercurial - Rebase branch of old code on top of new code tip, ignoring branch's merges with old code


I was playing around with the Adium source code and discovered that they had an unreleased branch in the adium-1.4 that fixes the facebook chat integration by using XMPP, called facebook-xmpp. All good there, complied it and it works.

Problem is, if I wanted to have the same functionality in the latest Adium 1.5, whose code got split from the older version's about two years ago (with some changesets from the older version being transplanted over from time to time), I figured I'd have to somehow rebase the entire range of changesets that makes up the facebook-xmpp branch and apply it onto the tip of the newer adium-1.5 branch. I thought this might work since facebook-xmpp looks like it mostly adds new code, so it should be easily integrated with the newest development code.

However, since facebook-xmpp branch merged with adium-1.4 several times, I found that rebasing would pull in the merged changes from adium-1.4 onto adium-1.5 as well, which makes for a lot of merge conflicts.

---------------------------------------  adium-1.4
               |                   \---  facebook-xmpp (created 1 month ago)
               |
               \-----------------------  adium-1.5
               ^ sometime in 2009

Question is, is there a way to transplant onto adium-1.5 only the changesets that added to the facebook-xmpp branch, excluding the ones that merged with adium-1.4 ?


Solution

  • Method 1 (manual patch)

    If you just want the facebook-xmpp functionality to be available in audium-1.5, you could

    1. merge the tip of audium-1.4 into facebook-xmpp, then
    2. create a diff between the tips of audium-1.4 and facebook-xmpp and
    3. try to apply that patch onto the tip of adium-1.5.

    That should work but the new patch is disconnected from the original development history.

    --------o---o    <- tip of audium-1.4
       \     \   \
        \     o---o  <- tip of facebook-xmpp (all audium-1.4 changes merged in)
         \
          o-------o  <- tip of audium-1.5 (apply patch here)
    

    Basically these commands should do it:

    $ hg up facebook-xmpp
    $ hg merge audium-1.4
    $ hg commit -m "Merge audium-1.4 into facebook-xmpp"
    $ hg diff -r audium-1.4 -r facebook-xmpp > fbx.patch # facebook-only changes
    $ hg up audium-1.5
    $ hg import fbx.patch # good luck
    

    Method 2 (selective merge)

    Another solution, which shows more respect to the history graph, would be to directly merge facebook-xmpp into audium-1.5 while using a merge tool configuration that uses internal:local as the default merge tool (to stop your merge tool from popping up 1000 times) but that merges regularly for any facebook-xmpp related files (if your know which files are related to its functionality). Then, before committing the merge, revert all files not related to the facebook thing.

    UPDATE: Here are some example instructions for this second solution. Supposed the facebook-xmpp branch created some new files named fb-<something>.c and changed the existing files foo.c and bar.c (you get these files from a diff between facebook-xmpp and its latest merge with audium-1.4). When merging facebook-xmpp into audium-1.5, use the following merge tool configuration:

    $ hg up audium-1.5
    $ hg --config ui.merge=internal:local \
         --config merge-patterns.fb-*.c=internal:merge \
         --config merge-patterns.foo.c=internal:merge \
         --config merge-patterns.bar.c=internal:merge \
         merge facebook-xmpp
    

    The first merge config ensures that generally audium-1.5 changes are kept on files changed in both audium-1.4 and audium-1.5. The other config options ensure that for any files touched by the facebook-xmpp branch a regular merge is performed, potentially with conflicts which need to be resolved manually. For instance if foo.c raised conflicts, run

    $ hg resolve foo.c
    

    to resolve the conflicts with your favorite manual merge tool. Finally, you have to commit the merge while not committing any new files originating in audium-1.4. Just commit the facebook-xmpp stuff:

    $ hg ci -I "fb-*.c" -I foo.c -I bar.c
    $ hg up -C # get rid of remaining new files from audium-1.4