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?
To revert a file to a specific changeset, use hg revert -r CHANGESET FILENAME . This will revert the file without committing it.
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.
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With