My use case is this:
I am working on a new feature and I have several commits on that feature.
Since it was a minor feature, I didn't even consider doing the feature in a feature branch.
However. Now my boss comes along and tells me to fix a bug on the same branch that I am working on (default).
To fix that I'd like to create a feature branch for my feature, push all my existing (unpushed) commits into that branch.
So I'd like to create a branch just before my first commit and then somehow move all my commits to that branch.
How can I do this?
There’s two ways to approach this, depending on your preference:
In a new repository.
Make a new clone of your repository, and do the bug fix you need to make there. Then push it to the main repository when you’re done, and continue where you left off in the original repository. Pull and merge to get the new changes as usual.
In the existing repository.
Update to the changeset before your local changes, and just start fixing and committing there. This creates a new anonymous branch. When you’re done, push using push -r ., this will only push the changes that are included in the working copy. After this, merge with your original branch (hg merge) and continue where you left off.
Note that you can bookmark the feature branch with hg bookmark if you do not feel comfortable with leaving your changes unlabeled. Also you can easily find back any heads you left behind using hg heads.
Personally I prefer to work in a new clean clone, as you don’t need to worry about branching and where to leave uncommitted changes. However if your project setup is complicated it may be more convenient to reuse the existing repo.
For this situation you can fix it by rebasing (which may need enabling in your configuration).
On your branch, update to the revision before the change-sets you want to move:
hg up -r<revison>
This assumes contiguous revisions need moving.
Create a new branch:
hg branch "TempWork"
Put a dummy commit onto it in order to get a new revision:
hg commit -m"New Branch"
Then perform the rebase from the first of the change-sets you want to move (it moves descendants automatically) and specify the new branch revision as the destination:
hg rebase -s<base revision> -d<new branch revision>
Then update back onto your main-line branch.
Fourth method: Using mq-patches
You have to have mq extension enabled and initiated for repo
On hotfix moment you
convert feature-commits into set of mq-patches (hg qimport)
Unapply all patches in set (hg qpop -a)
Code hotfix, commit
...
Finish and test hotfix on clean codebase
Apply all patches in set (hg qpush -a), fix possible conflicts
Convert patches back to changeset (hg qfinish)
Related
I forgot to switch my working copy back to the correct branch and made some changes.
How can I commit the current changes (but not all other changes in the current branch) to my original branch?
If I understand correctly, you have uncommitted changes that need to be on top of another branch.
My prefered way is to use the shelf functionality to save all your changes, update to the correct branch, and then un-shelf your changes back on the proper branch.
To do it on the command line, save the result of hg diff in a patch file, then update to the other branch and hg import <patch>.
Finally, just commit your changeset, as you wanted.
Shelve extension allow you to store WIP, get clean working dir, update to needed branch, release shelve
MQ exension (somehow overkill) allow to do the same thing, as shelve
At last, you can commit into wrong branch and rebase this changeset to the correct parent, using Rebase extension
I have a repository called 'Myproject' and within that we have a branch "MyProject-new changes"
I have cloned the "MyProject" repository in my local machine as
c:/MyProject
and similarly cloned "MyProject-new changes" as
c:/MyProject-new changes"
Both the repositories have the latest changes after pull and merge.
Now, I need the changes from "MyProject-new changes"(branch) changes merged into "MyProject" locally.
Once I merge, I don't want to commit these changes..I will revert back the changes as the branch changes are being worked. I just want to integrate the new changes and see the results for time being.
Please let me know the following
How do I merge locally the code from "MyProhect-new changes" to "Myproject"
How do I revert back MyProject once I tested it.
So you need a test site where you can test merge. Usually people create separate clone for experiments. This gives you easy way to revert changes — just delete experimental clone. So lets start from making another clone of MyProject and update on the latest commit in branch default.
Suppose revision 25 is the latest revision in branch default. You can update on it with command hg up -r 25.
Suppose revision 37 is the latest revision in MyProject-new changes. You can merge latest changes from MyProject-new changes into branch default with command hg merge -r 37. After that you'll have merge result in your working directory.
Since you work in the separate clone you can commit without doubt. Commit with hg ci -m 'merge with new changes' and test the result. When you finished your tests you can simply delete experimental clone.
The simplest way is to make a complete clone of your repository, merge and test to your heart's content, and throw out the repository when you're done. #Kirill explains how to do that.
But why do that? Maybe you'll come across problems, or small merge conflicts, that you'll fix in the clone. It will be a pity to throw away this work-- you'll probably need it in the future. You could simply keep the clone around, of course, but I suggest reconsidering your premise: Why don't you want to merge the two branches?
You have a main branch (default) and a feature branch new-changes, and you want to safely see how they work together. Here's two ways you can do this without cloning the repository:
To keep the default branch safe, simply merge from default into new-changes:
hg update new-changes # switch to the branch
hg merge -r default
You can now test new-changes and fix any problems. This is a very common workflow: Changes to default are incorporated into long-running branches to keep them from drifting too far apart. When you're eventually ready to unify the two lines of development, merge new-changes into the default line and everything will work correctly.
If you want to keep both branches pure for the time being, you can create a new branch testing and merge both existing branches into it. You can keep it around and eventually merge it into default, or close it if new-changes turns out to be a failed experiment. (Detail: If testing is rooted at the head of one of the branches, there'll be "nothing to merge" from that branch. You'll only need to merge the other one.)
If you don't want to risk messing up your main repo, you can of course clone it and try one of the above approaches on the clone. Once you're satisfied that it worked correctly, push everything back to the main repo.
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.
I am trying to work out how to use the Branch-per-feature approach in mercurial but having created a branch to work in, and merged it back to default, am unable to push my changes back up to my master repository. What is best to do?
I created a branch "Gauge customisation", did some work in that branch and then merged it back into the default. Carried on with a few more changes in default and now I want to commit this back to my master repository. But when I try I get:
abort: push creates new remote branches: Gauge customisation!
hint: use 'hg push --new-branch' to create new remote branches
I didn't think the branching would show up in the master repo and that by merging it locally I could somehow work in the branch (or potentially branches) and then when I've tested everything, push it up to the master repo.
Should the Gauge customisation branch still show up? Really I thought I'd only see default at this stage? But is that me not understanding the tools properly? Should I be creating the remote branch?
Ideally I'd like to be able to open a branch per feature and have 3 or 4 such branches running at any one time (it's the way my company works) so I'd like to get a solid grasp of things now.
Technically you could just commit the new branch to the master repo using --new-branch. As displayed in your screenshot, there is not really a new branch with a head from a topological view, but from a namespace view, i.e. when hg aborts your push, it just wants your explicit acknowledgement to add a new branch (name) to the remote repo.
However, for tasks like your's -- temporary feature branches -- a more common workflow is to not use named branches but anonymous/bookmarked branches or separate clones. Named branches usually are used for long-living branches like stable, legacy, and so on. If you create an anonymous/bookmarked branch and merge it back when its feature is finished, hg won't complain when pushing.
An often recommended reading in that context is A Guide to Branching in Mercurial.
Merging two branches does not get rid of either of them. You will need to close your feature branch manually by switching to it and doing:
hg commit --close-branch -m 'Closing branch'
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.