What to do when a patch for Mercurial import fails?

greatwolf picture greatwolf · Jan 4, 2011 · Viewed 7.4k times · Source

I exported a bunch of changesets from my local working repo after doing a pull from the server repository. To make sure the patches work, I cloned a fresh repo from the server and I tried to apply the changeset. Unfortunately, the import fails with this:

applying G:\OSS\premake-dev\premake-dev_rev493.patch
unable to find 'src/host/scripts.c' for patching
3 out of 3 hunks FAILED -- saving rejects to file src/host/scripts.c.rej
patching file src/base/api.lua
patching file src/host/scripts.c
patching file src/tools/bcc.lua
file tests/test_bcc.lua already exists
1 out of 1 hunks FAILED -- saving rejects to file tests/test_bcc.lua.rej
patching file tests/premake4.lua
patching file tests/test_bcc.lua
abort: patch failed to apply

[command interrupted]

I know the reason for the failure, it's due to a removed source file that no longer exist in the latest changeset. But I'm not sure how to fix up my patch so that it will apply cleanly with the current server repository.

I'm fairly new to Mercurial so some of the terms used I'm not going to be familiar with. Also note that I don't have write access to the Hg server repository. So in order to get my changeset in, I have to export it as a patch and submit that to the maintainers.

Answer

Lasse V. Karlsen picture Lasse V. Karlsen · Jan 4, 2011

I must confess to not having used patches a lot, so this might not be the right workflow, but what I would try, if I was in that situation was to apply the patch to the changeset it was originally based on.

In other words, it sounds like you have the following case:

                    +-- you're here
                    |
                    v
1---2---3---4---5---6
     \
      \
       X <-- patch was built to change 2 to X

What I would do, provided I know the changeset the patch was originally based on, would be to update back to that changeset, apply the patch, this would add another head, then merge this into the tip of your repository.

After those actions, the repository should look like this:

                        +-- you're here
                        |
                        v
1---2---3---4---5---6---8
     \                 /
      \               /
       7-------------/
       ^
       |
       +-- this is the changeset you committed after applying the patch

Now, for a different way.

Is using a patch the only way? One common way when using Mercurial is that you set up your own repository, a fork, containing originally a full clone of the central repository, but you have commit access.

Thus you can commit your new changesets into your own clone.

If the central repository have new changesets added after you clone, at some point you pull from it into your clone, and merge.

Then when you're satisfied, you issue a pull request to the maintainers of the central repository, telling them that "Hey, I have some changes for you, you can pull them from my clone here: http://...".

This way, it is really easy for those maintainers to get everything in, since you've done all the hard work for them.

This would mean that you have the two repositories like this:

central: 1--2

clone:   1--2

You add your work:

central: 1--2

clone:   1--2--3

They add some changesets:

central: 1--2--3--4--5--6

clone:   1--2--3

Then you pull:

central: 1--2--3--4--5--6

clone:   1--2--4--5--6--7
             \
              \
               3  <-- this is your changeset

Then you merge:

central: 1--2--3--4--5--6

clone:   1--2--4--5--6--7--8
             \            /
              \          /
               3--------/

If the maintainers now pull from you, they get the exact same history into their repository.

There's also some support for rebasing, which would mean that you didn't have to pull and merge, but the maintainers would issue a "pull with rebase" command, in effect relocating your changeset from its current position into a new position in their repository, this would look like this:

central: 1--2--3--4--5--6---7
                            ^
clone:   1--2--3            |  relocated here
               |            |
               +------------+

This would only work if there are no merge conflicts. The method where you pull and merge is the best for them, since you do all the hard work, they only have to verify that the code is what they want.

For more information on forking, check out Tekpub's video on CodePlex and Mercurial, here: Tekpub: 7 - Mercurial With CodePlex, seek to around 21:15 for the forking part to start.

Note that a "fork" is basically just a clone, the way forking works in CodePlex is that it automates setting up a clone on your own account, and sending the original maintainers the pull request, but if you create your own account on Bitbucket or CodePlex or whatever, publish your clone there, and just send the maintainers an email with your repository URL, that's all there is to it.