I'm new to collaborating with Mercurial. My situation:
Another programmer changed rev 1 of a file to replace 4-space indents with 2-space indent. (I.e. changed every line.) Call that rev 2, pushed to the remote repo.
I've committed substantive changes rev 1 with various code changes in my local workspace. Call that rev 3.
I've hg pulled and hg merged without a clear idea of what was going on.
The conflicts are myriad and not really substantive.
So I really wish I'd changed my local repo to 2-space indents before merging; then the merge will be trivial (i'm supposing). But I can't seem to back up. I think I need to hg update -r 3 but it says abort: outstanding uncommitted merges.
How can I undo the merge, changes spacing in my local repo, and remerge?
BTW: if you just revert the merge you did and 3 is not your revision number you can do this:
hg update -C -r .
You can discard uncommitted changes with the -C (or --clean) flag:
hg update -C -r 3
BEWARE: Everything that was not committed will be gone!
After that you should probably use some kind of code formatter tool to do the entire operation, or at least some find and replace with regular expressions. Something as simple as replacing what matches ^____ (use 4 spaces instead of underscores) with __ (2 spaces), repeated a few times (unless you have insanely some nested code) should work.
To undo an uncommitted merge, use
hg update --clean
which will check out a clean copy of the original merge parent, losing all changes.
I apparently just needed to hg update -C -r 3, which overwrites my local files with the rev in mind (which is what I thought hg update would do; but I was wrong.) Thanks for my help!
Related
If I have a bunch of uncommitted changes and want to set it aside while working on something else instead, and then later (f.i. after several days) come back to it and proceed working. What would be the easiest workflow to accomplish this? (So far I have only experience with Mercurial's basic functionality). My usual method was to create a new branch using clone, but there might be better ways.
You have a handful options:
Shelve the items. This saves the changes and removes them from the working directory so the branch can continue. It doesn't create a change-set.
hg shelve --all --name "UnfinishedChanges"
hg unshelve --name "UnfinishedChanges"
Update/Edit: Newer versions of mercurial may need to use
hg shelve -n "UnfinishedChanges"
hg unshelve "UnfinishedChanges"
You can still use --name as an alternative to -n, but mercurial doesn't seem to like --name anymore. Additionally, the --all is no longer required and mercurial will in fact freak out over it.
Patch queue the items using mq. This isn't too dissimilar to shelve in some respects, but behaves differently. The end result is the same, changes are removed and can be optionally re-applied later. When pushed, the patches are logical change-sets, when popped they are saved elsewhere and are not part of change-set history.
hg qnew "UnfinishedWork"
hg qrefresh
hg qpop
hg qpush "UnfinishedWork"
Commit them locally, update to the previous change-set and continue working and make use of anonymous branches (or multiple heads). If you then want the changes, you can merge heads. If you don't want the changes, you can strip the change-set.
hg commit -m"Commiting unfinished work in-line."
hg update -r<previous revision>
hg strip -r<revision of temporary commit>
Commit them to a named branch. The workflow then becomes the same as option 3 - merge or strip when you are ready.
hg branch "NewBranch"
hg commit -m"Commiting unfinished work to temporary named branch."
hg update <previous branch name>
Personally I use option 3 or 4 as I don't mind stripping change-sets or checking-in partial code (so long as that doesn't eventually get pushed). This can be used in conjunction with the new Phase stuff to hide your local change-sets from other users if need-be.
I also use the rebase command to move change-sets around to avoid merges where a merge wouldn't add anything to the history of the code. Merges I tend to save for activity between important branches (such as release branches), or activity from a longer-lived feature branch. There is also the histedit command I use for compressing change-sets where the "chattiness" of them reduces the value.
Patch queues are also a common mechanism for doing this, but they have stack semantics. You push and pop patches, but a patch that is "underneath" another patch in the stack requires that the one on top of it be pushed also.
Warning, as with all these options, if the files have more changes since the temporary changes that you've shelved / queued / branched, there will be merge resolution required when un-shelving / pushing / merging.
Personally, I don't like any of the answers posted so far:
I don't like clone branching because I like each project to have only one directory. Working on different directories at the same time completly messes the history of recent files of my editors. I always end up changing the wrong file. So I don't do that anymore.
I use shelve for quick fixes (just to move my uncommited changes to another branch, if I realize I'm at the wrong one). You are talking about days, no way I'd shelve something for days.
I think mq is too complicated for such an ordinary sittuation
I think the best way is to simply commit your changes, than you go back to the changeset before you start these changes and work from there. There are some minor issues, let me illustrate:
Let's say you have the changeset A. Than you start your changes. At this point you want set it aside for a while. First of all, commit your work:
hg ci -m "Working on new stuff"
If you want, you can add a bookmark to make it easier to come back later. I always create bookmarks to my anonymous branches.
hg bookmark new-stuff
Go back to the changeset before these modifications
hg update A
From here, you work and generate the changeset C. Now you have 2 heads (B and C), you'll be warned when you try to push. You can push only one branch by specifying the head of that branch:
hg push -r C
Or you can change the phase of the new-stuff branch to secret. Secret changesets won't be pushed.
hg phase -r new-stuff --secret --force
To keep local uncommited changes, easiest way for me is just to save them as a patch file.
hg diff > /tmp/`hg id -i`.patch
and when you need to return to previous state:
hg up <REV_WHERE_SAVED>
hg patch --no-commit /tmp/<REV_WHERE_SAVED>.patch
You can just clone your repo multiple times. I tend to have a root clone, then multiple childs from there. Example:
MyProject.Root
MyProject.BugFix1
MyProject.BugFix2
MyProject.FeatureChange1
MyProject.FeatureChange2
The 4 childs are all cloned from the root and push/pull to/from the root. The root then push/pulls from the master repo on the network/internet somewhere. The root acts as your sort of personal staging area.
So in your case, you'd just clone up a new repo and start working. Leave your 'shelved' work alone in the other repo. It's that simple.
The only downside is disk space usage, but if that were a concern you'd not be using DVCS at all anyway ;) Oh and it does kind of pollute your Visual Studio "recent projects" list, but what the hey.
[Edit following comments] :-
To conclude then... what you're doing is completely fine and normal. I would argue it is the best possible way to work when the following are true: 1) it is short-lived 2) you don't need to collaborate with other developers 3) the changes don't need to leave your PC until commit/push time.
Is there a simple way to check if a merge/rebase will yield file conflicts, without actually performing the merge/rebase?
I want to be able to decide whether to:
rebase if the touched file set (mine vs. theirs) are different
merge if we've been messing with the same files.
Since a bad merge (caused by resolving conflicts the wrong way by human error) is easier to detect and reverse if I do a merge of two heads, rather than having done rebase. Especially if I push my changes and than later realized that something was messed up.
(It's not possible to always check everything beforehand, as we don't have a totally comprehensive test-suite.).
And.. I'm running Windows. :)
So, with some aid from Martin's answer, I've come up with the rebaseif extension, which does what I want.
Essentially, it tries to rebase using the internal merge tool, if that fails (which it does for any conflict), it aborts and does a merge with the user's preferred tool.
See https://bitbucket.org/marcusl/ml-hgext/src/tip/rebaseif.py for details.
Update
In recent months, I've gone back to just do a merge, since it's inherently safe. A non-conflict rebase might still muck things up since dependent files can affect the change. (i.e. a rebase loses information of how the code looked before merge).
As the rebaseif author, I recommend to use plain old merge instead. :)
There is no reason to use hg merge if the changes overlap and hg rebase otherwise since hg rebase make a merge internally and will let you resolve it using the same tools as hg merge.
As for testing if a merge or rebase will cause conflicts, then you can use
$ hg merge --tool internal:merge
in Mercurial 1.7 to override your normal merge tool configuration. (The --tool internal:merge part is new, use --config ui.merge=internal:merge in earlier versions of Mercurial.)
Following the merge,
$ hg resolve --list
will tell you the results and you will get back to where you started with
$ hg update --clean .
You can see if two changesets, REV1 and REV2, affect any of the same files doing something like:
(hg status --change REV1 --no-status ; hg status --change REV2 --no-status) | sort | uniq --repeated
If that has any output then the same file is touched in both revisions.
That could easily be made a shell script like:
#!/bin/sh
(hg status --change $1 --no-status ; hg status --change $2 --no-status) | sort | uniq --repeated
which could be run as any of these:
./find_overlaps c8f7e56536ab d9e2268e20b9
./find_overlaps 1 33
If you really wanted to get fancy you could tweak the script to automatically run merge or rebase depending on whether or not any lines were found.
If you're on windows my god help you. :)
I want to know what changes I made, without looking at the 30 other files that other team members modified.
So when I hg out, it said the first changeset to push was 4821, so since then I have pulled, merged, and pushed a couple times. Now I want to make sure all the debugging code is removed. Is there a way to diff the current revision (4873) against revision 4821 but only for my changes?
If your changes are in different files than those of your coworkers, which is how it sounds, you can use something like this:
hg diff -r 4821 -r 4863 -I path/to/file1 -I path/to/file2
If they're mixed in the same files as other people's changes then you would have needed to keep your changes in a separate branch (which doesn't require the branch command, anonymous branching is commonly used for this sort of thing).
The following command should do the trick:
hg diff -r "4821:4873 and user(your_username)"
I don't know if you can upgrade to the recently release Mercurial 1.6 or not, but this functional query language feature they just put in is what you might be looking for.
Try this approach:
First clone your local repo to another folder
In the new clone, rebase your last changeset so that it immediately follows your the other changeset (this should create a new head from it)
Do the diff
I've been using Mercurial for a few weeks now and don't understand why when Mercurial comes to merge committed changes from two repositories it does it in the working copy?
Surely the merge could happen without the use of the working copy removing the need to shelf changes etc.
It just doesn't seem necessary to involve the working copy. Am I missing something?
There is only one working copy per repository, by definition:
The working directory is the top-level directory in a repository, in which
the plain versions of files are available to read, edit and build.
Unless your file system descends from Schrödinger's cat, you cannot have two versions of the same file at the same time, thus you cannot have two working copies.
Nevertheless, it's indeed theoretically possible to use something like a ephemeral clone (per #Ry4an) to act as the working copy of a merge, resolve conflicts there, commit, then make it disappear. You'd get a beautiful merge changeset and your intact working copy.
I can think of several ways to achieve this:
Petition hg team to do it in core
Write an extension to implement the ephemeral clone or some other way
Shelve with a temporary changeset
Shelve with MQ
I would strongly recommend #4, as I would for almost all workflow scenarios. It took me a few good days to grok MQ, but once I did I've never had to turn back.
In an MQ workflow, your working copy is always the current patch. So for the merge situation you would do:
hg qrefresh
hg qpop -a
hg update -r<merge first parent>
hg merge [-r<merge second parent>]
hg commit
hg update qparent
hg qgo <working copy patch>
You don't have to pop all patches in #2. I always do that whenever I need to deal with real changesets to avoid mixing them up with patches.
Solution #3 is really the same as #4, since a patch is a temporary changeset by definition (this is really the only thing you need for understanding MQ). It's just different commands:
hg commit -A
hg update -r<merge first parent>
hg merge [-r<merge second parent>]
hg commit
hg update -r<working copy changeset parent>
hg revert -a -r<working copy changeset>
hg strip <working copy changeset>
If you want to keep the working copy changeset and continue to commit, simply update to it in #5.
From your question it seems like you already know #4 but don't like shelving. I think shelving is good because merging is a fundamentally different task than coding (changing working copy), and shelving makes the context switch explicit and safe.
I didn't write Mercurial, so I can't say why they did it that way, but here are some of the positive results of that decision:
you can look over the results of the merge before you commit it
you can edit the results of the merge before you commit it
you're encouraged to commit frequently
If you really want to do a merge and have stuff in your working dir that you can't bear to commit don't bother with shelve just do:
cd ..
hg clone myrepo myrepo-mergeclone
hg -R myrepo-mergeclone merge
hg -R myrepo-mergeclone push myrepo
On the same file system clone is near instantaneous and uses hardlinks under the covers so it takes up almost no space past that of the temporary working copy.
As mentioned in the chapter "Merge" of HgInit:
The merge command, hg merge, took the two heads and combined them.
Then it left the result in my working directory.
It did not commit it. That gives me a chance to check that the merge is correct.
Such check can include conflicts in merge, that the user has to review:
In KDiff3, you see four panes
The top left is the original file.
Top center shows Rose her version.
Top right shows Rose my version.
The bottom pane is an editor where Rose constructs a merged file with the conflicts resolved.
So you need a working directory (a view for the merge) in order to resolve fully a merge.
I typed in hg add and I am brand new to mercurial and the result of this was a bunch of dll's exe's pdb's etc all got added
Nothing's been committed yet and I basically want to undo the add.
the documentation for hg forget is not very clear not sure if that is want I want
How do I undo the add before the next commit
I do have some real files that need adding so after I can undo the add I will use add with the exclude flag
Thanks
Check out this mercurial tip. To cite the link - if you have accidentally added a file, the way to undo that (changing its status from A back to ?, or unknown) is hg revert. For example, if you just ran hg add and realized that you do not want files foo or bar to be tracked by Mercurial:
hg revert foo bar
Either revert or remove can be used to un-add not yet commited stuff. However, they both have other uses too, so for clarity hg forget was (re-)added in 1.3, and despite its name it might be easier to remember.
If you are using a Unix like system i believe the best option is to run
hg status -an0 | xargs -0 hg revert
Two tips for these sorts of situations:
If nothing has been commited at all, just delete .hg and start over with hg init.
If you do something terrible to your repository and can't seem to figure out how to undo it, (and hg update -C or revert all won't fix), consider cloning the repository at the last good spot.