How to revert last commits and keep changes in mercurial? - mercurial

I have three commits 1, 2 and 3. How can I rollback 2 and 3 and still keep the changed files of them??
1---2---3
=> 1 and changed files of 2 and 3

You use the strip command:
strip changesets and all their descendants from the repository
with the --keep option:
-k --keep do not modify working copy during strip
And since strip is destructive of history it's not enabled by default. You enable it by adding these lines to your ~/.hgrc file:
[extensions]
strip =
So in this case you'd do hg strip --keep 2
Note: requires Mercurial 2.8 or later. Before that you need to put mq = in the .hgrc instead.

If you use TortoiseHg, you can achieve this like that:
Enable strip extension from Settings -> Extensions
Give Strip... command from -> 'Modify History' -> 'Strip'.
Check Do not modify working copy during strip (-k/--keep) option.
Click Strip button.

Related

Mercurial: Move a modified file between commits

Let's say I have the following commit history:
A - newest
B
C - oldest
I have changed a file foo in B, but I want to move the change from B to A.
How can I do that with hg?
There are several different ways that I can think of. Both have some moderate user requirements (please make sure you have backed up or pushed to a non-publishing repository first).
1 ) Use histedit and amend (requires that each extensions be enabled).
- copy file you wish to move to a safe location
- run hg histedit and edit changeset b and restore file to its original state
- run hg histedit --continue to commit changes.
- copy file from safe location to repository
- run hg amend to append file to changeset A
2 ) Use split and histedit.
- run hg split -r b
- split out all but the file you wish to move into a new changeset
- create a new changeset onto of that containing the fie (give it a temporary description)
- run hg histedit
- move the temp change above A
- roll the temp change into A
3 ) Use hg-evolve uncommit / amend. While this is a somewhat advanced method, I much prefer this one myself.
- run hg update B
- run hg uncommit and select the file you wish to move.
- run hg evolve to correct the stack
- run hg update A
Note: if you get a warning about needing to use --clean use hg shelve before
running the update followed by hg unshelve afterwords.
- run hg amend to add file to change A
4 ) Use hg uncommit all contents of changesets A and B and then recommit using hg commit -i to reassemble the changesets with the desired content.
There are likely a number of other ways, but this is what came to me.
Here's a simplistic but functional approach, maybe for people not very experienced with some of the more advanced HG commands:
Make sure your working directory is clean (no changes).
hg update -r C
hg revert -r B
hg commit ... as needed, but leave out the change destined for A. This creates B'.
hg shelve ... store away the uncommitted changes
hg revert -r A
hg unshelve ... restore uncommitted changes, merging them into the workding directory
hg commit ... creates C'.
hg strip -r B ... (optional!)
(where it says -r A that means use the revision # corresponding to A)
Explanation: we just create two (or more) entirely new changesets and then delete the originals (which is optional).
We're using revert basically to mean "copy from some changeset to the working directory" which I find is very handy in many circumstances.
After these operations -- but prior to using strip -- the history would look like:
*
|
A A'
| |
B B'
|/
C
and strip will just delete A, B.

how to backout to an older version ignoring all versions after that

I have 3 commits which I pushed to the public repository accidentally. I want to revert to an older version (a version before these 3 commits happened) and make it the current code in our public repository.
I am using TortoiseHg,version 2.11.1
Option 1
You can use the strip option as mentioned in the command
hg strip is the command
This extension has to be enabled
Enable the extension by adding the following lines to your .hgrc or Mercurial.ini:
[extensions]
strip =
This option is only suitable if you have access to the central repository where your code is hosted and you have a small group in which you would know if someone have already pulled your changes.
Option 2
Another option would be to backout these 3 commits, Since you are using UI,I will attach a screen shot
Step 1: Right click the unwanted commit and you will see a backout option click that and the wizard wll guide you.
if its a merge that you are trying to backout then you have to select which branch to backout to.
Do the same for the 3 unwanted commits
Option 3
if you have many commits and if its in a named branch following these steps will provide a solution
1) Close the branch and update to the last good commit you want.
2) Reopen the barch from there by new commit (Named branch can have multiple heads)
3) use hg revert -r and commit
This will make the working directory exactly as the last good commit you need and ignore the inwanted commits. This will only work if the commits are in a named branch.
You can do it like this:
hg backout -r <rev>
hg push
This will backout to the <rev> revision (which should be the last correct commit). In other words, it will set your working directory into the same state as it was on the last correct commit and create a new commit with an explanatory message. Then you'll push it to the public repository so it's the current code again.

How to delete a branch in bitbucket with mercurial hg?

I opened a second branch (branch2) locally in hg and pushed it to bitbucket. After that i merged the two branches locally and pushed it again...I have branch2 still living on bitbucket. How do i delete branch2 on bitbucket?
Have you tried closing it? From hg help branch:
Use "hg commit --close-branch" to mark this branch as closed.
Closing doesn't exactly delete a branch (remove all trace).
If you want to delete it, you need to hg strip it.
In Bitbucket, find the revision where the branch was created, and go to Settings > Strip changesets > <Enter "Revision to strip">.
Confirm the deletion of all the revisions attached to the revision you entered, then delete.
NOTE: This approach may not be so straight forward if you have merged. This approach is more for "I have created a branch incorrectly, I want to delete it, and recreate it again using the same branch name."
Using hg workbench, I lookup up the commit that started the new branch, right clicked and selected ## Copy Hash.
Then I enabled the strip extension by adding the following to my mercurial.ini (located at %USERPROFILE%\mercurial.ini)
[extensions]
strip =
Finally I executed the strip command using the hash from my clipboard to remove the local branch:
hg strip 36012047aee7c08cdc4ede51293392c106a3d0b7

Can I revert a range of lines in a file with mercurial?

I often notice a few unwanted changes when I review my working copy (with hg status and hg diff) right before a commit. For example, I might have temporarily added or remove some code just for the duration of a debugging session.
I know I can use hg revert to remove unwanted changes, but this removes all the changes in the entire file. Is there a way to revert just a part of a file?
I'm not sure if you can revert individual lines explicitly, but what I do in situation like yours is to commit the good code and revert the rest (the bad code). This workflow is easy using Mercurial's record or crecord extension (I recommend the latter one).
I've been doing this with the interactive ncurses style ui hg revert -i that lets you walk around and select the parts you want to destroy, either file, diff chunk or line by line, as you please, depending on how deep you unfold your changes.
I am not sure if this is a standard hg feature or not, you can verify easily enough if yours has it:
> hg revert --help --verbose | grep -- -interactive
-i --interactive interactively select the changes (EXPERIMENTAL)
Just remember that the changes you mark (X) will be what gets nuked, not what you retain.
Assuming you have the record and shelve extensions enabled, you can do as follows:
hg record -m "garbage" # pick out and commit the change you want to revert
hg shelve --all # temporarily hide other changes
hg strip tip # remove the garbage changeset
hg unshelve # restore the changes you want to keep
One way is using a graphical diff tool like kdiff3. If you feed it the diff and choose "merge current file" you can go line by line and pick what you want.
The better way is to commit more often. If you make a habit to commit right before adding debugging code, then either commit or revert your debug code before adding your "real" code, it makes it very easy to remove your debug code because it has its own revision. Alternately, you can put your debugging code in a separate branch altogether.
The TortoiseHg GUI's "Commit" window has a "Hunk Selection" tab that allows selection of specific sections of a file's changes to be committed.
I've got a different answer for your problem, which is the same problem I have. This is a great use case for mercurial queues!
When I am about to start adding debugging code to a change that I think is ready, I do the following:
hg qnew -m "fix for bug #123" fix.patch # basically a local-only commit
hg qnew -m "debugging" dbg.patch # prepare the next changeset at the tip
[add my debugging]
hg qrefresh # update the changeset at the tip
[...]
hg qpop # pop the debugging off the repo history
It takes a little bit of getting used to -- you end up having to reorder your patches to then fold whatever fixes you made into the original work patch.
Also, check out Bill Barry's attic extension. This page talks about how to use it for a few different workflows and how that compares to using mq. https://www.mercurial-scm.org/wiki/AtticExtension
If the commit where you want the change is e.g. ba1c841aaff4,
the easiest is to use:
hg meld -r ba1c841aaff4^ <filename>
Now click on a right arrow (pointing to the right) in the middle to revert your lines, save the file and close meld. kdiff3 (old and unintuitive) can be an alternative.
Side note: in order to use meld you need to configure it in our ~/.hgrc file:
[extdiff]
cmd.meld =
[merge-tools]
meld.args=$base $local $other
Download and install meld https://meldmerge.org/
(You should have Mercurial installed locally or TortoiseHg)
Launch Meld and select Version Control View and then select you will be asked to choose a parent directory of the file you want to modify.
Select the file which has the uncommitted changes
Choose which lines you want to revert to the last commit by selecting the arrow. The document on the left is from the last commit and the right document is the file with the uncommitted changes.

Is there any way to delete local commits in Mercurial?

So I keep making a silly mistake in Mercurial. Often times, I'll start work without doing an "hg pull" and an "hg update." When I try to push my changes, I get an error.
Is there any way to delete my local commits so I can avoid creating multiple heads, branches, etc? I just want to delete my local commits, merge my changes with the tip, and then re-commit. Sounds simple, right? I can't seem to find any way to easily delete local commits so I can cleanly merge with the tip.
Again, I'm only trying to delete local commits made with "hg ci". I don't want to modify files, revert, etc.
Enable the "strip" extension and type the following:
hg strip #changeset# --keep
Where #changeset# is the hash for the changeset you want to remove. This will remove the said changeset including changesets that descend from it and will leave your working directory untouched. If you wish to also revert your committed code changes remove the --keep option.
For more information, check the Strip Extension.
If you get "unkown command 'strip'" you may need to enable it. To do so find the .hgrc or Mercurial.ini file and add the following to it:
[extensions]
strip =
Note that (as Juozas mentioned in his comment) having multiple heads is normal workflow in Mercurial. You should not use the strip command to battle that. Instead, you should merge your head with the incoming head, resolve any conflicts, test, and then push.
The strip command is useful when you really want to get rid of changesets that pollute the branch. In fact, if you're in this question's situation and you want to completely remove all "draft" change sets permanently, check out the top answer, which basically suggests doing:
hg strip 'roots(outgoing())'
If you are using Hg Tortoise just activate the extension "strip" in:
File/Settings/Extensions/
Select strip
Then select the bottom revision from where you want to start striping, by doing right click on it, and selecting:
Modify history
Strip
Just like this:
In this example it will erase from the 19th revision to the last one commited(22).
Modern answer (only relevant after Mercurial 2.1):
Use Phases and mark the revision(s) that you don't want to share as secret (private). That way when you push they won't get sent.
In TortoiseHG you can right click on a commit to change its phase.
Also: You can also use the extension "rebase" to move your local commits to the head of the shared repository after you pull.
As everyone else is pointing out you should probably just pull and then merge the heads, but if you really want to get rid of your commits without any of the EditingHistory tools then you can just hg clone -r your repo to get all but those changes.
This doesn't delete them from the original repository, but it creates a new clone that doesn't have them. Then you can delete the repo you modified (if you'd like).
I came across this problem too. I made 2 commit and wanted to rollback and delete both commits.
$ hg rollback
But hg rollback just rolls back to the last commit, not the 2 commits. At that time I did not realize this and I changed the code.
When I found hg rollback had just rolled back one commit, I found I could use hg strip #changeset#. So, I used hg log -l 10 to find the latest 10 commits and get the right changeset I wanted to strip.
$ hg log -l 10
changeset: 2499:81a7a8f7a5cd
branch: component_engine
tag: tip
user: myname<myname#email.com>
date: Fri Aug 14 12:22:02 2015 +0800
summary: get runs from sandbox
changeset: 2498:9e3e1de76127
branch: component_engine
user: other_user_name<name#email.com>
date: Mon Aug 03 09:50:18 2015 +0800
summary: Set current destination to a copy incoming exchange
......
$ hg strip 2499
abort: local changes found
What does abort: local changes found mean? It means that hg found changes to the code that haven't been committed yet. So, to solve this, you should hg diff to save the code you have changed and hg revert and hg strip #changeset#. Just like this:
$ hg diff > /PATH/TO/SAVE/YOUR/DIFF/FILE/my.diff
$ hg revert file_you_have_changed
$ hg strip #changeset#
After you have done the above, you can patch the diff file and your code can be added back to your project.
$ patch -p1 < /PATH/TO/SAVE/YOUR/DIFF/FILE/my.diff
You can get around this even more easily with the Rebase extension, just use hg pull --rebase and your commits are automatically re-comitted to the pulled revision, avoiding the branching issue.
hg strip is what you are looking for. It's analogous of git reset if you familiar with git.
Use console:
You need to know the revision number. hg log -l 10. This command shows the last 10 commits. Find commit you are looking for. You need 4 digit number from changeset line changeset: 5888:ba6205914681
Then hg strip -r 5888 --keep. This removes the record of the commit but keeps all files modified and then you could recommit them.
(if you want to delete files to just remove --keep hg strip -r 5888
If you are familiar with git you'll be happy to use histedit that works like git rebase -i.
[Hg Tortoise 4.6.1]
If it's recent action, you can use "Rollback/Undo" action (Ctrl+U).
In addition to Samaursa's excelent answer, you can use the evolve extension's prune as a safe and recoverable version of strip that will allow you to go back in case you do anything wrong.
I have these alias on my .hgrc:
# Prunes all draft changesets on the current repository
reset-tree = prune -r "outgoing() and not obsolete()"
# *STRIPS* all draft changesets on current repository. This deletes history.
force-reset-tree = strip 'roots(outgoing())'
Note that prune also has --keep, just like strip, to keep the working directory intact allowing you to recommit the files.