Recover from "hg update" with uncommitted changes
Asked Answered
J

4

9

I run into the following issue all the time with Mercurial, and it's very annoying:

  • I'm at some revision A.
  • I have local changes, which I meant to commit or amend on top of A, but haven't yet.
  • I want to go to some revision B, but I forgot that I had local changes!
  • I do hg update B. Mercurial "helpfully" tries to rebase my local changes to apply on top of B. This typically results in conflicts, and it now asks me to fix the conflicts.

However, I don't want to fix the conflicts! I don't want my local changes to apply on top of B at all. I want them to stay at A, either as a new commit just after A, or amended into A, as the case may be.

Is there a way I can recover from this state? The only way I know how is to

  1. fix the merge conflicts at B
  2. go back to A, getting merge conflicts again
  3. fix the merge conflicts again at A
  4. commit my changes at A and go back to B

This is a lot of work, and it's pointless. I shouldn't have to rebase my local changes to apply on top of B, only to rebase them again to apply on top of A.

If there's no better way to recover from this mistake, is there a way to get hg to refuse to do an update when you have local changes? I never want to do that - if I wanted that I'd just commit the local changes and rebase them on top of B.

Jiujitsu answered 13/3, 2014 at 22:6 Comment(0)
L
9

Getting the dirty files back after updating somewhere and back is a bit tricky. The "trick" is to make sure that your working copy has the dirty files after the first update.

So after you do

hg update $SOMEWHERE

and discover the mess because Mercurial begins opening merge tools, calmly close the merge tools and then run

hg resolve --unmark --all
hg resolve --all --tool internal:local

All files that were merged because you had changes in them will now look like they did in your dirty working copy. This includes files that were merged cleanly and files you were prompted to merge. Updating back is now possible:

hg update $BACK
hg resolve --unmark --all
hg resolve --all --tool internal:local

You should now be back to where you started. If you modified the files after the first update, then it is the modified version you see after the second resolve. This is why you will want to resolve the files after the first update.

Loom answered 14/3, 2014 at 10:52 Comment(1)
It took me a while to actually run into this problem again, because I aliased hg update to do hg update -c to avoid this. However, I ran into it today, and this approach worked perfectly to fix it. Thanks very much!Jiujitsu
A
4

hg update -c will abort the update if you have any uncommitted changes.

Ansermet answered 13/3, 2014 at 23:9 Comment(3)
Uhm, it's not what actually OP asked. It doesn't answer any of 2 questions appear in the original post.Higherup
@zerkms: "is there a way to get hg to refuse to do an update when you have local changes?" is not only there but also bolded...Ansermet
oh, sorry, confused it with -C which I mostly use. Makes sense indeed then.Higherup
G
3

If there's no better way to recover from this mistake, is there a way to get hg to refuse to do an update when you have local changes?

Add this to your ~/.hgrc:

[commands]
update.check = noconflict

This will still allow hg update with uncommitted changes as long as there is not conflict. You can also call hg help config.update.check for other possible options:

"commands.update.check"
  Determines what level of checking 'hg update' will perform before
  moving to a destination revision. Valid values are "abort", "none",
  "linear", and "noconflict". "abort" always fails if the working
  directory has uncommitted changes. "none" performs no checking, and
  may result in a merge with uncommitted changes. "linear" allows any
  update as long as it follows a straight line in the revision history,
  and may trigger a merge with uncommitted changes. "noconflict" will
  allow any update which would not trigger a merge with uncommitted
  changes, if any are present. (default: "linear")
Gemma answered 10/3, 2021 at 10:18 Comment(0)
S
2

Maybe the answer is to avoid updating if the working directory is dirty. Modifying the ~/.hgrc in the following way should help:

[hooks]
preupdate = test -z "$(hg status)"
Sheelagh answered 18/3, 2014 at 16:48 Comment(1)
I accomplished something similar by aliasing update to update -c.Jiujitsu

© 2022 - 2024 — McMap. All rights reserved.