I have just been asked by a fellow developer whether they need to do anything when that merge window appears. Apparently their default course of action has been to simply close the window immediately.
Anyway, we're now in a situation where they have made minor changes to a number of files where another developer made a large number of changes. They then 'merged' them, essentially backing out all remote changes to the files, committed the code, and pushed to the central repository.
So we're in the situation that there is revision x with changes we want, revision y with changes we want, and revision z that is a merge of x+y, but actually just contains the code from y.
Is there a way now to retrospectively get back into the merge tool?
I'd like to run a command and get a meld window up to let me merge back in the changes from y into the current revision.
First, clone your repository somewhere, and test these instructions in there. I tested them on a very small repository made for the purpose, so I may have overlooked something.
hg clone yourrepo testrepo
cd testrepo
You can check out the code as of revision x, and repeat the merge. That will give you a new head. Then, if you have not made changes since, you can use hg strip to get rid of the bad one. If you don't want to risk the strip, then merge the two heads, telling hg to keep the version of the code in the good version. If you have it checked out, as you will immediately after making it, then give the argument -t internal:local to throw away the changes from the other, bad, head. It's a lot simpler to do than to explain:
hg update x
hg merge -r y
hg commit -m 'Redo the merge.'
Then either:
hg strip z
or:
hg merge -t internal:local -r z
hg commit -m 'Get rid of the bad merge.'
You can look at the state of the graph with the very useful hg view extension.
Once again, I tested this on a toy repository. Back it up first!
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.
My coworker accidentally made two commits in the default branch instead of creating new his own development branch.
How can I change this situation and moves these two commits to a new branch?
Imagine the following scenario:
D
|
C
| "I want to move C and D here"
B/
|
A
Steps:
hg update B
hg branch "mybranch"
hg commit --message "Create my branch"
hg update mybranch
hg graft -r C
hg graft -r D
hg strip -r C (this should be the revision C had originally)
The strip command is provided by an extension that you need to enable. You can follow a guide on how to enable it on the Mercurial Wiki.
hg update default
A major question
Have the accidental commits reached other repositories or is it just in his own? If so, you can skip to the section below 'Maybe the cat is still in the bag' otherwise you may have a fair bit of work to do.
You are not alone
See here for more discussion on how to correct the problem elsewhere on Stack Overflow. What is described is the 'proper' way to to it
export a patch
create the branch
import the patch
delete the earlier commits.
Maybe the cat is still in the bag
If the changes are only in the local copy, then a simpler solution is to
create the new branch
switch to it
merge the changes onto that either with your fav merge tool (go Meld) or with hg graft
use the hg strip command to delete the changes on the old brach
push the changes to the world
pretend like nothing ever happened, whistle a happy tune ...
The two answers above are both correct but, assuming one has not yet pushed the commits, there's a third way.
I just successfully used the rebase command to move a string of commits to a topic branch I had forgotten to create in the first place.
I first updated to the revision from which I wanted to create the branch on which my commmits were supposed to be, then I rebased the earliest of my commits from the wrong branch on this new one and ta-da, done.
Takes more time to explain it than to do it with TortoiseHg or even the command line, really.
In my repo, I have the revisions 1 to 10. I've pushed up to 5 (so the next hg push would publish revisions 6-10).
But I have to interrupt my work now and the result isn't 100% complete. So I'd like to move the revisions 6-10 into a new "experimental" branch to allow someone else to complete the work without disrupting the sources for everyone.
How can I add a branch to a non-tip revision (in my case: Starting with revision 6)? Or should I use a completely different approach?
You cannot apply a branch name after the fact without modifying your history.
The most simple approach is to ask the other users to use revision 5 as the parent for any changes they create. For example, the other users would:
hg clone <your repo> or even hg clone --rev 5
hg update -r 5
work, work, work
hg commit
When they commit a change, it will create a second head on the default branch, but that should not create any problems. You will simply need to merge the two heads together once your experimental changes are complete.
That being said, moving your changesets onto a branch can be accomplished using Mercurial Queues (MQ). The following sequence shows how it be done:
hg qinit (Create a new patch queue)
hg qimport --rev 6:10 (import r6-10 into a new patch queue)
hg qpop -a (remove all patches from your working copy)
hg branch <branch name> (create your new experimental branch)
hg qpush -a (apply all the patches to your branch)
hg qfinish -a (convert all patches to permanent changesets)
Tim already has good suggestions. Additionally you could push your experimental changes into a distinct experimental clone on your central server (I guess you use one). This clone could also be used by other developers to push their not-yet-finished work in order to let others review or continue it. It is also clear that this clone's code is not ready to be used. Once some task is finished, the corresponding changesets can be pushed to the stable repository.
Actually named branches are a good idea for your case, but the fact that their names are burned into history mostly is more a problem than a feature. IMHO Git's branch names are more practically. However, to some extend you could also handle your case with bookmarks, which are pushable since Mercurial 1.7 (not sure here). That is you bookmark revision 5 with something like stable (or whatever you agree on in your team) and revision 10 gets bookmarked with something like Aarons-not-finished-work. The other developers would then just pull stable, except your colleague who is supposed to continue your work, who would pull the other bookmark. However, personally I did not use a such workflow yet, so I cannot say if it performs well in practice.
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.
Say, I made many changes to my code and only need to commit a few of those changes. Is there a way to do it in mercurial? I know that darcs has a feature like this one.
I know hg transplant can do this between branches, but I need something like this for committing code in the present branch and not when adding change sets from some other branch.
If you are using TortoiseHg 1.x for Windows, this feature is implemented beautifully right out of the box (no extensions required).
Run the TortoiseHg Commit Tool.
Choose a file for which you only
want to commit a subset of its
changes.
Click on the Hunk
Selection tab in the preview pane.
Double-click or use the spacebar to
toggle which change hunks should be
included in the commit.
For TortoiseHg 2.x, the Hunk Selection tab is now gone. In its place, is the Shelve tool. It has a few more features than the old hunk selection. Those new features come at the cost of some added complexity.
Note that there is no need to explicitly enable the Mercurial Shelve extension when using this feature. According to Steve Borho (lead TortoiseHg developer) in response to a different TortoiseHg question: "We have a local copy of the shelve extension and call into it directly."
For TortoiseHg 2.7+, this functionality has been improved and re-introduced. It is now built directly into the Commit tool:
Notice in the file list on the left that the top file is checked to indicate it will be included, the second file is unchecked because it will not be included, and the third file, Sample.txt, is filled (the Null checkbox indicator) because only select changes from that file will be included in the commit.
The change to Sample.txt that will be included is checked in the lower-right change selection portion of the image. The change that will be excluded is unchecked and the diff view is grayed out. Also notice that the icon for the shelve tool is still readily available.
MQ as Chad mentioned are one way. There's also more lightweight solutions:
Record extension which works roughly the same way as darcs record. It's distributed with mercurial.
Shelve extension which allows you to "shelve" certain changes, allowing you to commit only a subset of your changes (the ones that are not shelved)
I feel like I'm missing something because nobody has suggested this already.
The normal "hg commit" command can be used to selectively choose what to commit (you don't have to commit all pending changes in the local working directory).
If you have a set of changes like so:
M ext-web/docroot/WEB-INF/liferay-display.xml
M ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
M ext-web/docroot/WEB-INF/portlet-ext.xml
You can commit just two of those changes with...
hg commit -m "partial commit of working dir changes" ext-web/docroot/WEB-INF/liferay-display.xml ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
Not super convenient from the command line because you have to hand-type the files to selectively commit (vs a GUI check-box process like tortoise) but it's about as straightforward as it gets and requires no extensions. And file-globbing can probably help reduce typing (as it would above, both committed files uniquely share "liferay" in their pathnames.
The Mercurial Queues tutorial is terrible for this use case. All the examples I have seen assume you have yet to make a commit and you are refreshing a single patch. Most of the time this is not the case, and you have 2 or 3 commits that you want to squash together or change in some other way.
Lets say you have this sort of history:
---O---O---A---B---C
The first example is to squash commits A, B, and C. First init mq:
$ hg qinit
Now we need to "import" the commits A, B and C into the patch queue. Lets assume they are the last 3 commits. We can use the "-N" revision syntax to import them like so:
$ hg qimport -r -3:-1
That means import as patches from 3 patches back up to the last commit. You can check the status of these patches with hg qseries. It should show something like this:
$ hg qseries
101.diff
102.diff
103.diff
Where the numbers 101, 102 and 103 correspond to the local revision numbers of the commits A, B and C. Now these patches are applied, which means the changes that they describe are already in the working copy. You can get rid of the changes the working copy and remove them from the history of commits, saving them in patch form only, by using hg qpop. You can either say hg qpop; hg qpop to pop changes C and B off the stack, or specify a patch to "pop to". In this case, it would be something like this:
$ hg qpop 101.diff
now at: 101.diff
You now have the patches for commits B and C in the patch queue, but they are not applied (their changes have been "lost" - they only exist in the patch queue area). Now you can fold these patches into the last one, i.e. we create a new commit that is the equivalent of the sum of the changes A+B+C.
$ hg qfold -e 102.diff 103.diff
This will show your editor so you can change the commit message. By default the message will be the concatenation of the commit messages for the changes A, B and C, separated by asterisks. The nice thing here is that hg qfold will tab-complete the patches if you are using bash and have the hg-completion script sourced. This leaves the history like this, where A+B+C is a single commit that is the combination of the 3 patches that interest us:
---O---O---A+B+C
Another use case is if we have the same sort of history as before, but we want to drop patch B and merge A+C. This is pretty similar to above actually. When you get to the qfold step, you would simply fold in the last commit rather than the last 2 commits:
$ hg qfold -e 103.diff
This leaves the change for B in the patch queue, but it is not applied to the working copy and its commit is not in the history. You can see this by running:
$ hg qunapplied
102.diff
The history now looks like this, where A+C is a single commit that combines changes A and C:
---O---O---A+C
A final use case might be that you need to apply only commit C. You'd do this by running the qimport as above, and you would pop off all patches you didn't want:
$ hg qpop -a
The -a flag means pop off all patches. Now you can apply just the one you do want:
$ hg qpush 103.diff
This leaves you with this history:
---O---O---C
Once you are done with all this, you need to finish off the queue fiddling. This can be done with:
$ hg qfinish -a
So there we are. You can now run hg push and only commit exactly what you want, or hg email a coherent patch to the mailing list.
Some time has passed. Seems the best option now is hg commit --interactive
You can use the record extension, which is distributed with Mercurial.
You need to enable it in your ~/.hgrc file first, by adding it to the [extensions] section:
[extensions]
record=
Then, just type hg record instead of hg commit, and you will be able to select which changes to which files you want to commit.
You can also use the crecord extension which provides a nicer interface to review and select the changes. (It is not distributed with Mercurial, though, and I've seen it occasionally mess up a commit so it's not completely bug-free.)
I believe Mercurial Queues fills this role for Mercurial. There's a pretty good tutorial linked there.
Try qct (Qt Commit Tool). It has a "select changes" feature that starts up a 3-way merge tool for you to undo individual changes. After you commit, those changes you "undid" come back.
I use commit-patch. It's a script that lets you edit the diff before committing. It's really nice with Emacs's diff-mode and vc-mode.
In the past I used crecord, but it has bugs related to unicode (actually the record extension has the bugs, which crecord depends on).
First you must forget everything you ever knew about GUI's and return to the commandline. Next from the commandline do this:
hg stat > filelist.txt
This pipes all your modified files into a text file called filelist.txt
Next edit your filelist to include only the files you wish to commit.
Finally commit using the fileset sytnax:
hg commit "set: 'listfile:test.txt'"