Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In mercurial, how do I apply a reverse-patch to a particular file?

Tags:

Related to Mercurial: Merging one file between branches in one repo , I'm trying to perform a backout operation on a single file, even though that file was one of many participants in the revision being backed out.

HG being the changeset-oriented tool that it is, it doesn't want to operate on files.

Closest I could find was to use hg export to create a diff, hand-edit the diff, and then hg import to patch the file in reverse order.

..but then I hit this annoying situation where http://hgbook.red-bean.com/read/finding-and-fixing-mistakes.html claims that there is a --reverse option to hg patch when there is not.

So the closest thing I can think of is to generate a hand-edited patch as above, and then using vanilla patch -R to apply a reverse patch.

The hg backout command would seem to be useful here, but is actually a red herring.

There has GOT to be a better way, no?

like image 417
djsadinoff Avatar asked Jul 06 '09 09:07

djsadinoff


People also ask

How do I revert a file in Mercurial?

To revert a file to a specific changeset, use hg revert -r CHANGESET FILENAME . This will revert the file without committing it.

What does hg backout do?

Revert/undo the effect of an earlier changeset. Backout works by applying a changeset that's the opposite of the changeset to be backed out. That new changeset is committed to the repository, and eventually merged.

How do you revert the last push in Heartgold?

hg rollback reverts the last transaction, so you'd be left with unfinished merge, which you have to use hg update -C to get out. If you don't want *b (you have it in another clone), then enable the built-in MQ extension and run hg strip -r <*b> . It will get rid of *b and *merge.


2 Answers

You can do it using just the -I (include names matching the given patterns) argument for backout with a single line:

hg backout --merge -I thefiletorevert -m 'message' OFFENDINGREVISIONID

Example Script:

hg init testrepo
cd testrepo
echo -e "line1\n\nline3" > file1
echo -e "line1\n\nline3" > file2
hg commit -A -m 'changes to two files'
perl -pi -e 's/line1/line 1/' file1
perl -pi -e 's/line1/line 1/' file2
hg commit -m 'put spaces in line1'
perl -pi -e 's/line3/line 3/' file1
perl -pi -e 's/line3/line 3/' file2
hg commit -m 'put spaces in line3'
hg backout --merge -I file1 -m 'remove spaces from line1' 1

Sample output:

adding file1
adding file2
reverting file1
created new head
changeset 3:6d354f1ad4c5 backs out changeset 1:906bbeaca6a3
merging with changeset 3:6d354f1ad4c5
merging file1
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

Resulting File Contents:

file1:line1
file1:line 3
file2:line 1
file2:line 3

notice that file1 is missing it's space in line one after the backout of the middle changeset, and the verbose log shows only one file changed in the backout:

$ hg log -v -r tip
changeset:   3:6d354f1ad4c5
tag:         tip
parent:      1:906bbeaca6a3
user:        Ry4an Brase <ry4an@mini>
date:        Mon Sep 14 12:17:23 2009 -0500
files:       file1
description:
remove spaces from line1
like image 181
Ry4an Brase Avatar answered Oct 09 '22 14:10

Ry4an Brase


Here's what I would do: Use a fresh clone of the tip revision.

hg backout --merge -r revision_where_the_change_happened

to merge the reversed changes into the working copy.

Now copy the file in question to your regular working copy and commit

hg commit -m "Reversed the changes to file.h made in revision bla"

and throw away the clone you created above.

This way, mercurial doesn't know that there is a connection between revision_where_the_change_happened and this commit. If you want mercurial to remember this, instead do a

hg revert {all files except the one in question}

after merging the backout commit into the working copy and before commiting. For the second way, you don't need to work on a clone, because you want to keep the backout commit.

I would guess that the choice of which way you use depends on how big a part of the changeset the particular file change was.

like image 40
balpha Avatar answered Oct 09 '22 16:10

balpha