Get a bugfix from default to a feature branch in Mercurial - mercurial

How do I get a bugfix I made on the default branch into a named branch in mercurial?
I recently started work on a new feature so thought I'd do this work in a branch (which I've not really done before) so I could keep the changes out of the main default branch until I've finished working on them and the feature is ready to deploy. The idea being that I could update to the default branch and apply any bugfixes as needed.
Now I want to get the bugfix into my named branch. The tip (rev 739) has the change I want to incorporate into the BoardSummary branch. I know I could merge but I don't want to bring my BoardSummary changes into the default branch.
I looked at the mercurial: apply a bugfix change from stable named branch to dev branch answer but it didn't make sense to me.
Edit: I'm with it up to "Then you discover that changeset 2 introduced a bug", in my case I went back to 732 fixed the bug and committed (onto the default). The idea being that the fix is in place before I branched. But now how do I get that fix into 738 without merging the 2 branches together? It looks like the bug is actually fixed in 739 - so isn't in the BoardSummary branch yet. This seems to be what the 2nd tree shows in the answer but the 3rd diagram is explained with "you would instead do this" - I don't understand that bit

Evidently, your default branch contains only one changeset not present in the BoardSummary branch. You should merge default into BoardSummary, and not the other way round. This way, BoardSummary will have the fix, and none of the BoardSummary will be in default.
To summarize:
$ hg up BoardSummary
$ hg merge default
$ hg commit -m "Merge the fix for #247"
An explanation
There are a number of kinds of branches which can be employed. The most common are:
stable (production) branches for maintaining the released versions,
default (master, trunk) branch, which contains more or less stable development activity,
feature branches, which are not mature enough to be merged into trunk.
The main idea here is that it is always safe to merge from stable to default, and from default to feature. This means that in terms of changesets, any stable branch is a subset of default, and default is a subset of feature branches.
For instance, you're reworking your data access level in a feature branch new-dal (major feature). At the same time, you've added a couple of new reports in default (minor features), and found and fixed a bug in a 1.0-stable. Well, just merge the branches going from the oldest to the newest (1.0-stable -> default -> new-dal), and that's all.
This is explained very well on the Mercurial wiki: Standard Branching: Release branches.
Your case
In your case, BoardSummary is clearly a feature branch, so you can merge default into it without any hesitation. The opposite should only be done if you're ready to integrate the new feature into default.

At first you should rollback/remove the commit 739 (which is your fix) from the history. Then you commit the fix on r732. This will create a new head and should be the new r739. Your history should look like this:
r329
|
--r232-----default branch
\
\
feature branch
Now you merge your new head (r329) into the default and the feature branch. Now the history should look like the last tree in the linked answer.

Related

Splitting out multiple intermediate changes in Mercurial

We have a very unfortunate situation where a new feature branch was made from a second, unrelated feature branch that had been put on hold rather than from default. There's multiple changesets within both feature branches and while most changed files are unrelated several high level project files that have edits on both branches. Default has also had several updates and merges during this time too. Thankfully the intermediate feature hasn't been updated concurrently with the new feature. I've looked into various commands and options available and lost how to best fix this situation. The tree currently looks roughly like:
Default -- Various edits and merges -- tip
\
\-- Named Branch 1 (15 changes) -- Named Branch 2 (30 edits)
I want to get to a point where default has the changes from Named Branch 2 but none from Named Branch 1. I also want a branch that has the changes from Named Branch 1 available for when we return to this feature.
I suspect there's no nice easy way to do this, and there's going to be some messy parts in the history, however I am at a loss at how to start going about this task.
hg graft can cherry-pick changesets from one branch to another. Update to the destination branch, then graft the revisions you want to copy by running, for example:
hg graft 8 9 10
Conflicts will be handled using the normal merge process.
If you use TortoiseHg, select the changesets to graft to the current selected changeset, then right-click and select Graft Selected to local...:
Result:
Since you want to move the entire branch 2, you could consider using rebase. Make a clone of the repository and try this:
hg rebase --source <first branch2 rev> --dest <new parent in default> --keepbranches
This will in principle transform the history to what it should have been. However:
You may have to resolve conflicts arising when <first branch2 ver> gets moved to a new parent.
Since rebase rewrites history, you'll have to get everyone to cooperate in synchronizing their repositories. Whether that's feasible or worth the trouble in your case I can't say, but it's not that difficult: Assuming everyone has pushed any changes in branch 2, they can pull the new history and then get rid of the obsolete version of branch 2 with hg strip:
hg strip <first branch2 rev>

Overwriting branch with default in Mercurial

Let say I had a feature branch called feature_x that was worked on, then changesets cherry-picked and transplanted to default, then the branch was closed. Not the best flow, but it's Mercurial, so there is no way of changing the history.
Now I'm going to work again on the feature X, and I feel reusing feature_x branch would be least confusing. However, if I reopen that branch and merge default to it, I've got two problems. First merge conflicts, second changes that were modified in that branch, but never merged into default. So what I'd like to have is clean slate, branch feature_x, but with exact copy of what's currently in the default. Is there a cleaner way of doing that, than creating new branch which will shadow the name?
I think your best bet is to start a new branch off of the current tip of default called feature_x2 or feature_y and leave the past in the past.
But here are some other options:
Is the old feature_x branch confined locally to your repo only or was it pushed? If the former, you could hg strip it and start the branch again at the current default.
If the feature_x name is really, really important, you could do the merge default into it using the internal merge tools and force it to reflect the default branch exactly by doing
hg merge -r default --tool internal:other
Or you could just commit a (file system) copy of default on top of the tip of branch_x. Then you could continue on that branch along your merry way.
I don't know if 2. or 3. will cause strange merge issues down the road. I would test to see if the merge back over to default (or another graft?) could cause issues later.

HG: How to push some (but not all) changes to 'stable' branch?

Say I do my new feature development either in default, or an entirely new branch made just for the feature for a web site project. When it comes time to push the feature out to the live website, I want to move it to the live branch, which I then hg archive to my apache directory.
Throughout everything, I want to be absolutely sure not to push other, unrelated changes that are not yet ready to be published to the live branch.
Is this even a good idea? Or should I be doing something entirely different?
If the code is in default, how do I push only the one thing I need and not everything to live? If I push just the latest changeset, is it smart enough to send the latest version of those files, or will it only do the changesets?
If the code is in an entirely new branch, do I merge the whole branch into live? How do I get those changes back to my default branch so I see them there too?
I was reading the "Task Based Management" section of the Mercurial Kick Start guide and it mentions merging default into your branch. I found this very confusing and was wondering why you'd ever do this.
Thanks for any help you guys can provide.
[edit]
I'm using TortoiseHG BTW
[/edit]
HG now has Phases. Change a phase of a changeset to secret and it will not be pushed when you use push. You can do it using TortoiseHG GUI.
In addition to that, be aware that just pushing or pulling something does not automatically change any files in the working directory. It only makes some additional changesets available. Only by using update do you actually change any files in your working dir. (unless you configure hg to update automatically).
In the example you linked, there is a bug fix in the default branch. Bob wants to have this fix in his branch too, so he merges default branch with his branch. This is just an example to see how branching works. You do not have to use it in exactly the same way. If you just begin your Mercurial adventure, then you should better use just one branch until you have a good reason to use more.
For example: 3 developers work on the same project and all of them use just one branch (default). 1 of the developers wants to do a major refactoring of the code. He wants to commit several very unstable changesets (many "in the middle of work"). Doing so in the default branch might upset other developers. That is a good reason to create a branch. After his version is stable enough he will merge his branch into default. While he is doing development in his branch, he wants to be up-to-date with other developers, so he frequently merges default into his branch. Staying in a separate branch for too long might result in difficult merges. Luckily merging is very quick in HG, so merge often.

How do I update a branch to be the state of a tag on a different branch in Mercurial?

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.

mercurial team repository / picking and choosing

I have a small team and I would like to do the following:
I have my trunk, I'll just call it TRUNK
Now, TRUNK is a project that's already in production and running. Now, the inevitable defects come in, but into bugzilla and are assigned to users.
Each user clones TRUNK to their local repositories and makes changes and pushes them to a directory TRUNK/projects (projects is not a clone of TRUNK, just a regular directory)
Now, the day comes where I want to create a new build called RELEASE and I want to merge some of the bug fixes (not all, just some) into RELEASE.
Notice, I am not committed to the idea of having TRUNK/projects/[bugfixes list], but that's what I currently have now and am more than open to any / all suggestions.
What are some ideas? Is there something I can do / should do differently? Again, I am open to any / all suggestions, including completely changing the above procedure (except for using Mercurial as that's what the company makes us use)
There are two ways to do this and they diverge not at release time, but when you do the bug fixes depending on what parent you give the bugfix changesets. The "good" way uses only push, pull, and merge. The less good way (it's not entirely bad, but it's certainly sub-optimal) is called cherry picking and it has drawbacks. The tricky part is that whether or not you're going to be able to move bugfixes into RELEASE via merge without moving everything from TRUNK into RELEASE is something you have to decide before you make that change.
Here's a really complete answer for a similar question that explains what's going on: Some help with merging legacy branch in Mercurial
The key concept though, is that you can merge a changeset into any branch you want but it brings with it all of its ancestor changesets. So you want your bug fixed to have minimal ancestry. That means fixing a bug not in a new changeset in TRUNK that happens to be the latest feature you added, but instead, first, hg updateing to a changeset that already exists in both your TRUNK and your RELEASE, and there are two great candidates for that. Either:
the changeset where RELEASE and TRUNK diverged
or
the changeset where the bug was introduced
My preference is for the later. If a bug was introduced in changeset 666 then every clone, branch, and build that has changeset 666 will want your fix. So when fixing it just do:
hg update 666
.. fix the bug ..
hg commit -m "fixed bug 55" # creats changeset 999 which a new head
Then you can do this:
hg update TRUNK
hg merge 999
and you'll know you're only pulling in a single changeset. Later when you're ready to release you can do:
hg update RELEASE
hg merge 999
and you're again only getting the single changeset you want.
The advantage of this mode of working over cherrypicking (using export/import or transplant) is that your fix exists only once in your repo. If you have 99 different vendor branches for various finicky customers and you want to see if they have the fix for bug 55 you can just do:
hg log -r 'descendants(999) and heads(FUSSYCUSTOMERBRANCHNAME)'
and if there are no results then that customer doesn't have 999 and thus doesn't have the fix for bug 55 in changeset 666. When you re-do the same work with multiple changesets (which is the result of export/import and transplant) that's harder to verify.
Common practice is to create topic branches.
Each new issue/ticket/enhancement is commited into separate branch.
Anytime maintainer wants to make new release he can merge all (or only some) that branches into "default" or even new branch called e.g. "release_1_x".
To be more precise. Developer working on code can still clone repository, then create local branch and finally, after one or more commits to that branch, pushes local changes to one centralized clone (from which every other developer in team can pull/clone again).