Im reading Mercurial, the definitive guide, and it mentions that in large projects, its useful to have your project split up into feature branches. Ive drawn a quick picture of what i think is happening when you want to merge the Feature Branch with the Master Branch.
Is my diagram correct + does the Feature Branch continue to exist? Im assuming yes.
The active named branch can be explicitly closed using:
hg commit --close-branch
This tends to be done if a line of work was not going anywhere. If you want to re-open a branch of the same name on top of a closed branch, you need to force that branch open again using:
hg branch <name> --force
However, they implicitly become inactive if you merge from your feature branch into another branch and the feature branch has no un-merged change-sets (as in, the last thing on that branch is the merge into another branch). The destination of this merge does not have to be the "mainline" in order to deactivate the branch, inactivity is purely based on any un-merged change-sets.
They become active again if you subsequently create change-sets on them at a later date. This tends to be the common situation, if you are working on features off-mainline and merging in frequently.
Do note that a closed branch is not the same as an inactive branch.
I'm sorry, but I couldn't really understand your diagram so I hope the above sentences make sense.
Also, do not confuse named branches with anonymous branches, which are when a single branch has multiple "heads".
Related
This question already has answers here:
Mercurial: Merging one file between branches in one repo
(5 answers)
Closed 2 years ago.
Reading up on Mercurial, it seems to always branch and merge the complete repositories.
Is it possible to just merge some files from one branch to another? (For example I may only wish to merge in the files that fix a given bug.)
Likewise can I cherry pick some change sets, but still have a correct merge record, so if a complete merge is done later it is correct?
I am coming from a perforce “mindset” so may be thinking about this the wrong way.
Yes, Mercurial always branches and merges the whole tree. You don't have the "flexibility" that something like perforce gives you to select individual files for a merge. This is a good thing (trust me). Changesets are atomic (you can't split them) and immutable (you can't change them). Hence this needs a little bit of a mindset change.
Changesets should be targetted at one task, and one task only. If you're fixing a bug, nothing else goes in the changeset apart from the bug fix. You've then got a changeset which documents that bug fix, and you haven't got the problem of wanting to split it. It wouldn't make sense to want to. Half a bug fix is often worse than no bug fix.
When it comes to merging that there's a couple of options:
One school of thought says you should go back to where the bug was introduced. Fix it. Commit (making a small anonymous branch), and merge that forward onto whatever head you want it on (dev, stable, release, whatever). This isn't always practical though.
Another method is fixing the bug in the release branch, and then merging to the development branch. This normally works well.
Alternatively you could fix it at the head of your development branch, but then if you merge it onto your release branch you'll bring over all your development changes. This is where graft (new in 2.0) and the older transplant extension come into play. They allow you to "cherry-pick" a single or range of changesets from another branch and place them on another branch.
Reading up on Mercurial, it seems to always branch and merge the
complete repositories.
Yes
Is it possible to just merge some files from one branch to another? (For example I may only wish to merge in the files that fix a given bug.)
Just touch only "some files" in needed changeset and merge branch with this changeset in head with another branch or transplant in any time
Likewise can I cherry pick some change sets, but still have a correct merge record, so if I complete merge is done later it is correct?
Yes, you can transplant| any changesets to another branch, applied state will be remembered and changes will not be duplicated on final merge
I decide to start an experiment in a branch
[default] $ hg branch experiment
[experiment] $ [... some commits ...]
Aargh! does not work! I want to throw it away.
[experiment] $ hg commit -m "did not work; closing ..." --close-branch
[experiment] $ hg update default
To get the real tip back -
[default] $ [... some commits ...]
[default] $ hg push
Is this a correct workflow to destroy an experimental branch?
You've got two fine answers on how to undo your branch, but the bigger point is don't use named branches for temporary concepts. Named branches are for long lived entities like 'development' and 'stable'. For features, expiriments, etc. you want either clones, bookmarks, or anonymous branches. All three are contrasted with named branches in this excellent article by Steve Losh:
http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
You can see similar advice from the Mercurial project here:
https://www.mercurial-scm.org/wiki/StandardBranching
The Mercurial wiki covers all the options for Pruning Dead Branches. Briefly, these options include:
Closing the branch (as done in your original post)
Create a new clone that does not include the dead branch
Use a no-op merge
Use the strip command that is bundled with the mq extension
Closing a branch will leave it in the repository, and the closed branch will be pushed with other changesets next time you do a push.
If you don't want this to happen, and your branch is local, just strip it.
On the other hand, if you have already pushed the experimental branch, stripping it won't help, so you can either close it or do a dummy merge (or both).
In my opinion, you should just close the branch and forget about it.
In the long run, there's no harm in a "dead" branch being present in the repository. Any given branch is almost certainly tiny in comparison to the contents of your repository and any additional "noise" created by the additional changesets is going to fade into the past relatively quickly.
However, by not worrying about cleaning up the branch, you achieve two things:
You don't have to deal with any of the potential issues associated with altering history in a DVCS.
(More importantly) You have a permanent record of your attempt.
That second point is key -- you can actually make use of what you learned if the branch is still around: any fellow developers can learn from it; you can go back and try again if you learn something else; you can prevent trying the same thing again by seeing this branch in history.
A lot of developers have a hard time with keeping history that isn't "pristine" in their DVCS, especially when they recently came from a centralized VCS.* Over time, I've come to realize that there's nothing bad or wrong about that "other" history and in fact it can turn out to be remarkably useful if kept around.
*I'm not necessarily implying that you fall into either of these camps, just making an observation.
I have a repository with a master and a develop branch.
I want to create a third named branch, say it's called bugfixes.
I want to be able to update to bugfixes and then have the tip of bugfixes be the same as a previous tag on master. (Say that tag is called Release5.1).
I've tried updating to the branch, and then updating to the tag, but that switches the branch back to master (where the tag is). I've also tried merging
hg merge -r Release5.1
but that only brought in the changes and didn't cause the branch to "go back in time".
How do I get that tag to the the tip of the named branch?
I'm asking this question because my CruiseControl.net guy tells me that we can only do builds off of the tips of branches and not off of specific revisions. (Maybe that is another question....)
First some basics:
Merges are directional:
When you merge bugfixes into master, then master gets the changesets that were committed on the bugfixes branch.
When you merge master into bugfixes, then the reverse happens.
If you want two branches to mirror each other, then you must do the merge in both directions.
I would argue that you don't need the bugfixes branch at all. Instead, I would set a policy that says:
master should always be in a state that may be released
Bug fixes are committed to master
All releases are tags on master
New features are committed to develop
When it is time to release, develop is merged into master
After every release, master is merged into develop to insure that new features are based on the latest release.
This would result in something like this:
If you must have a bugfixes branch, then I set a policy like this:
master should always be in a state that may be released
All releases are tags on master
Bug fixes are committed to bugfixes
New features are committed to develop
When it is time to for a bug fix release:
Merge bugfixes into master
Tag master
Merge master into bugfixes to make them match
Merge master into develop to make sure new features are based on the latest release.
When it is time for a major release:
Merge bugfixes into master
Merge develop into master
Tag master
Merge master into bugfixes to make them match
Merge master into develop to make sure new features are based on the latest
This will result in something that looks like this:
To fix a bug in an old revision, you should:
hg update <TAG>
hg branch Release1.x
<fix the bug>
hg commit -m "Bug fix to older version"
hg tag Release1.2
...if the bug is present in master, then you should also:
hg update master
hg merge Release1.x
hg commit -m "merged bug fix in Release1.x to master"
This would result in something like this:
NOTE 1: At this point, master has commits which should never be part of a Release1.x release. Due to this, you should never merge master into Release1.x.
NOTE 2: If you must support multiple releases of a product in the field, it is common to have a named branch for each major release. These long-running named branches are then used only for bug fixes. If you are very careful, you can merge bug fixes from one release branch to another, but in my experience it is more common to use hg transplant to copy the changes between branches.
I would suggest that you keep the bugfixes branch essentially a mirror of the master branch except for when you are fixing a bug, and once the bug is fixed, merge bugfix back into master to again sync them up.
If you need to maintain multiple old versions of master, you will probably need to have a bugfix named branch for each old version you need to maintain.
Ideally, you wouldn't need a named branch dedicated to bug fixes. Much of Mercurial's power comes from how easy it is to branch from a previous revision (un-named branch). I am not too familiar with CruiseControl.net, but if you can build off of unnamed branches, then all you would have to do is:
Update to the tag you want to base the fix on
Make the changes
Commit (this will make an unnamed branch)
Build / test the tip of the new, unnamed branch
Tag the new version
Merge as needed to make sure all code lines get the bug fix
Due to how Mercurial's internal hash structure works, unwinding changes off of the "stack" (or inserting new changesets into the stack, depending on how you look at it) is a really, really hard thing to do and is likely to break any repositories that were clones of the one you are working on.
I love the flexibility of named branches but I have some concerns about the prolifieration of heads.
Even when the branch is closed, it still shows up in the heads. I have an idea for how to clean up the output from "hg heads"
My question to the gurus: "What am I missing?"
First off you may ask, Why might I want to totally hide the head of a named branch? For various reasons:
the feature is a bad idea
the feature is a good idea that is not ready for merging to tip, but maybe in a few months
the branch is a patch release to an older tagged version
edit: It turns out the prolifiration of heads is a symptom of the older version of mercurial I was using. Closing the branch hides the head of the branch it on newer Mercurial versions.
My idea is to have a "dead" head branch onto which all these closed branch heads will be merged.
The dead head would be parented by changeset 0 and serve the sole purpose of bundling up the stray heads that are not needed right now.
The deadhead has only other deadhead children, which never get merged back into the default branch.
You can use hg commit --close-branch to mark a branch as closed:
http://www.selenic.com/mercurial/hg.1.html#commit
Closed branches will not show up in hg branches or hg heads by default (only if the -c/--closed option is specified), so I'm not sure how you're seeing "clutter"?
What exactly would you gain by merging things?
There seems to be a downside to leaving dead heads which is not solved by later versions of Mercurial.
Suppose you have a lot of closed branch heads and only a single non-closed active branch. Suppose further that at some later point you make a bad commit (rev bad) on top of the non-closed head (rev good). Before you push you'd like to clone your repository dropping that bad commit. That is usually a simple thing to do -
hg clone --rev good BadRepo FixedRepo
This unfortunately does not pull the closed branch heads since they are not ancestors of rev good. All those branches which were closed will not be closed in the cloned repository. I tested this with Mercurial 2.3.1.
Thoughts?
p.s. The hgflow extension does close feature and release branches before merging. This avoids the closed heads problem.
Regarding the clone being an ugly approach, it has worked quite well and easily for me. The clone replaces the repository with the bad commit. The clone is a local effort. That bad repository is just discarded. I usually realize I've made a bad commit very soon after.
The -b option is just a way to rephrase the --rev by using a branch name instead of a change set identifier. Using the --rev option does pull the entire topological tree under the revision. If the revision is the head of the branch then the --rev clone is the same as the -b clone. -b leaves the same problem that I described with the --rev option. Branches which were closed in the original repository get reopened if they were left as heads.
If the pattern is to leave closed heads then they will soon greatly outnumber relevant heads. Getting those closures into a clone is quite an effort unless you do a full clone.
I feel I've muddied the waters with why I might do a partial clone. I'll restate my concern about closure heads more carefully.
For any partial clone from repository X to repository Y, if there exists a branch B in repository X with a closure head and that branch is included in the clone for purely topological reasons, then branch B will not be closed in repository Y. Further if the merging pattern is to generally leave closure heads then the number of closure heads is of order development time.
This is a concern to me so I close my branches before I merge. I use hgflow (http://nvie.com/posts/a-successful-git-branching-model). A possible partial clone would be to clone the development branch and follow that with a pull of the master branch (e.g. if you wish to eliminate dead ends). If feature and release branches had been closed after their final merges then those branches would be reopened in the clone.
So I have a mercurial repository that is the "blessed" repository that I will have open release cycle branches, for example Release1, Release2 etc.
When a dev is working on a release cycle they will pull down Release1, then on their local machine branch for Bug1, Bug2 and fix those.
What command sequence needs to happen for the devs to correctly close their Bug branches, merge the changes into the Release1 branch so that when the changes are pushed to the server no branch information about Bug1, Bug2 etc will be pushed to the server?
If you're using named branches the branch information about bug1 will always be pushed to the server. Named branch names are parts of their changesets and never go away or get changed. You can cause them to not show up in default branch lists by using the --close-branch option to commit, but they're still there and listable.
If you want a branching model where the branch names don't escape Mercurial provides some other branch options that may suit your needs better:
http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
If someone suggests using the 'TransplantExtension' to merge the branches in and hide the branch information, don't listen -- it's a terrible idea.