tags:

views:

58

answers:

2

I have a local mercurial repository with 5 commits that still need to be pushed to the server. However, I accidentally included a line in two specific files since the last 4 commits that I really don't want to have in there (nor in one of the changesets).

Is there any practical way to remove those lines in these two files? (apart from throwing away my local repository, cloning the server's copy, and manually reapplying all changes again)

+6  A: 

You're going to get a lot of different suggestions (mq, histedit, import/export) that all essentially do the same thing. And they're all going to feel really clunky because mercurial is built around the concept of an immutable history -- changing history is supposed to be hard. That said, as you correctly understand if you haven't yet pushed the csets it's possible. Here's the procedure I'd use -- I prefer it because it requires enabling no extensions:

hg export --git -o ../all-five-csets.patch 0:tip
cd .. # exit the repo
vi all-five-csets.patch # delete the line manually each time it appears (probably only once)
hg init newrepo
cd newrepo
hg import ../all-five-csets.patch
cd ..
mv repo was-repo
mv newrepo repo

All that's happening there is you're exporting the csets to text representations of themselves. Creating a new, empty repo, and then re-importing the csets. I did all of them because you only have five. If you were looking at altering the last 5 of 500, I would have created the newrepo by doing a clone -r which clones "up to a point' and then applied the csets I'd left behind in their edited form via import.

Ry4an
Well explained ! One question: the line indeed appears once, but it's prepended with a '+', and the old (good) line is prepended with a '-' to indicate the diff. Do I really remove the '+' line and leave the '-' line in place. Or do I remove both the '+' and '-' line ? (Of course, alternatively, I could just change the '+' line into something that I don't care about)
Rabarberski
It turned out that some bitmap files (.ico) that are included in the repo weren't copied to the changeset patch file (that seemed logical, with hindsight,since it is only a textfile). But I wasn't sure if I could trust it for all my other files. Therefor, I turned to cloning the repo from the correct revision to a new repo (using `hg clone -r 14 repo repo-new`) and I reapplied the changes manually. Still, your explanation was very clear, and gave me better understanding of mercurial.
Rabarberski
Sounds good. I think binaries (and file permissions) would've been included had I thought to add '--git' to the export, which I'll insert above. Many of us have [diff]\ngit=true in our ~/.hgrc files which makes that automatic, and I forget it's not the default.
Ry4an
and you'd remove the - and the + line thus undoing the change.Just to be even more complete, if that line weren't something so horrible that it can't leak at all or you'd already pushed, the normal way to undo this would be 'hg backout -r badcset ; hg merge' which applies the inverse of a changeset. The offending line stays in history but it's gone from 'tip'
Ry4an
+1  A: 

If it's not important for those 5 commits to be be independent change sets, you use hg collapse to collapse them down to a single change set which doesn't contain those lines you want to avoid pushing. I.e.

  • Remove the lines you didn't want to include, then commit that change
  • Use hg collapse to collapse the last 6 change sets (the existing 5 local ones, plus your new one that just removes those lines)

That will leave you with one change set on your local machine, which won't contain those lines you want to avoid pushing.

A word of warning, be careful with using hg collapse - you want to make sure you don't collapse change sets that have already been pushed to another repository.

Wilka