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.
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.
So, I have an Hg repo that looks like this:
O [default] [tip] Current repo
|
O Merging changes from named branch
|\
|O Something from a named branch
||
O| [prod-v1.2] Okay, version 1.2 is done
Now I've come across a problem in version 1.2. I can update to the tag prod-v1.2 and commit it, but when pushing, it warns me about multiple heads. Is there a way I can make my new "bugfix" branch the default temporarily? How can I manage this?
The best way to do this, is to create a new branch for your bugfix and then commit in it. The next time you will have to do changes on the version actually in production, you can just update to your branch and commit your change there.
If needed, you can easily merge the content of the branch to your development branch.
An example of this kind of workflow is described here : http://stevelosh.com/blog/2010/05/mercurial-workflows-stable-default/ but you can also find many more way to do this.
In your specific case, you can do something like this if you made only one commit :
hg rollback # rollbacking last commit to allow for branch creation
hg branch bugfix-v1.2
hg commit
hg push
You can now switch back to your default branch and continue to work on the next version... Next time you have a bugfix to do, just switch to your branch with hg update bugfix-v1.2 and commit here.
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.
We converted everything to Mercurial coming from CVS and so far so good. An issue we encountered today though is this situation.
Before the move to Mercurial I had a few pending changes from a while back, features that were started and later postponed for various reason. Odds are that someone else will finish those features months from now picking up from where I left off.
After cloning the new Mercurial repository I created separate branches to isolate those features.
It left me with something like this (made up rev. number)
hg update default
hg branch feature1
hg commit -m "Description of what I was doing in feature1"
hg update default
hg branch feature2
hg commit -m "Description of what I was doing feature2" (my tip is now here)
hg update default
hg push -f (to force the creation of my new branches, w/o affecting default, I haven't merged them)
During this the team have been working and pushing to our central repository so the default branch is say rev 40 (tip)
Now my push -f worked fine but positioned (tip) to my latest change -> 50:feature3 (tip). I was expecting the tip to stay at default on the central repository and just have my branches in there for someone to pick them up whenever. The graph also looks pretty funny when I use hgwebdir so I am pretty sure that's the wrong approach.
How would I do this? Should I close the branch first? Is tip actually important or just meta-data.
tip is always the most recent changeset added to the repository. From hg help revs:
The reserved name "tip" is a special tag that always identifies the most recent revision.
So long as the head of the default branch is what you expect, you'll be OK. No need to close the branch (but it's better to use hg push --new-branch if your version of Mercurial is new enough to support it).
tip is just an automatically-applied label referring to (I think) the most recent commit. Not a big deal; it's just there for convenience.
The tip label is pure meta-data and always points to the changeset with the highest revision number -- there is no more logic than that.
However, the fact that tip now points to a changeset on the feature branch wont cause you any trouble. When people make a clone, they will automatically be updated to the tip-most changeset on the default branch. So they can begin working right away after a clone. Furthermore, people who already have a clone will stay on their named branch when they run hg update. Here hg update takes you to the tip-most changeset on that named branch, e.g., on default if that is where you started.
People may think that hg update tip is the same as hg update, but that is only when there are no named branches at play. With named branches, giving an explicit revision name such as tip can changeset your named branch -- a plain hg update cannot.
Is there a way to associate a bunch of Mercurial changesets with a named branch after they have been committed, i.e. retroactively ?
I just wanted to do this, and here’s the solution I found.
A year has passed since the question was originally asked, this might explain why I can now find a solution.
It has the disadvantage that you create an extra revision in the process, but this wasn’t too bad for me.
First, you go back to where you want to create the branch.
In my case, I actually wanted to start a new root (because I wasn’t very sensible when I started the repository, but anyways), so I’m updating to null. You probably want to start somewhere else, it depends on your situation.
$ hg update null
Then, create the branch.
$ hg branch blah
$ hg commit -m "Created blah branch."
Then, we rebase all the commits we made onto our new branch:
$ hg rebase -s SOURCE -d DEST
The SOURCE here should be the first commit you made in the commits you want to create the branch from, and the DEST should be the commit where the branch was created (the one we committed above).
No, branch names are part of the changeset (it's really like a label you add to the commit), it means the changeset hash depens on the branch name.
So the only way to change it retroactively is by rewriting history (which doesn't play well if you pushed your changes elsewhere, since you'll have to rewrite every repo which has the changes).
To rewrite history, you could use for example mq.
Not a complete solution but, without re-writing history; you could tag the last change set in the unnamed branch. If you never rebranch from this the tag should surfice. If you do need to rebranch you can move on to a named branch after the tagged changeset.