Consider I have the following situation:
I have a branch br_foo from revision 4. After that there are 3 more changes made on default branch: 6, 7 and 8. I'd like to only merge changes 7 and 8 to br_foo. Is there a way to achieve this in mercurial?
Graft v Transplant
Depending on which version of Mercurial you are using, you will probably use either the new Graft functionality in Mercurial 2.x or the older Transplant Extension for earlier versions of Mercurial.
The Graft command
This was announced recently (Nov 2011) so I haven't had a chance to work with it myself.
This command uses Mercurial's merge logic to copy individual changes
from other branches without merging branches in the history graph.
This is sometimes known as 'backporting' or 'cherry-picking'. By
default, graft will copy user, date, and description from the source
changesets.
The Transplant Extension
I've used it for just this scenario. A little snippet from the description ...
This extension allows you to transplant patches from another branch or
repository.
It records the original changeset ID in the transplanted changeset,
and avoids transplanting previously-transplanted patches.
It can also be used to rebase a branch against upstream changes
(including dropping changesets that have been adopted upstream), to
rewrite changesets and to cherrypick some changesets.
Since mercurial 2.0 (released on November 1st 2011) this is handled by the new core command graft:
This command uses Mercurial's merge logic to copy individual changes from other branches without merging branches in the history graph. This is sometimes known as 'backporting' or 'cherry-picking'.
See also this other question.
Related
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>
I know Rebase is a (bundled) extension, while Graft is a core feature (that replaced the Transplant (bundled) extension).
graft is documented as:
copy changes from other branches onto the current branch
This command uses Mercurial's merge logic to copy individual changes from other branches without merging branches in the history graph. This is sometimes known as 'backporting' or 'cherry-picking'.
rebase is documented as:
Rebase allows moving commits around in Mercurial's history (using a series of internal merges). This has many uses:
moving changesets between branches
"linearizing" history
reordering changesets
collapsing multiple changes into one changeset
Both seem to use merging to move or copy changesets between branches.
Graft copies. Rebase moves. But rebase --keep copies.
So often it seems I can accomplish my goal of copying a changeset either way.
Does it matter which one I use? When should I prefer one over the other?
E.g. should graft only be used when copying to a different named branch? Or only when there's just a single changeset?
Edit: Could it be that rebase is a potentially unsafe superset of graft, but can only be used with draft changesets during development for editing local history, while graft is a safe subset of rebase that can be used with public changesets during maintenance for backporting?
hg graft allows "cherry-picking," as you noted in your question. For example, you can run hg graft -D "2085::2093 and not 2091" to copy only some changes from another revision. By comparison, hg rebase (with or without --keep) will grab whatever changeset you specify and all of its decendant changes.
Also, rebase allows you to collapse changesets (with --collapse). As far as I can tell, graft does not.
One more difference I have noticed: hg graft --edit 123 lets you graft revision 123 to the working directory and edit the commit message. I can't find an hg rebase equivalent. I should point out, though, that hg histedit also allows for editing the commit message while rebasing.
There are probably other differences that I am not thinking of. SO community: feel free to point those out in the comments, and I will happily revise this answer to make it more complete.
See the graft documentation and the Rebase Extension documentation for more details.
I am currently using Mercurial for sub-version control in my project. Now I am suppose to work on a new branch 2.7 but I confuse to work with branch 2.6, I have developed the new feature which the feature on 2.7 but I build on 2.6. And now I want to move this feature to branch 2.7 properly but I don't know how can I move it properly. Is there any way?
I would recommend using hg graft, which copies changes from one branch to another and unlike hg rebase is not destructive (relevant if you're doing this for the first time and may be making mistakes or if you need the feature to be present on both branches).
To copy changes to a branch dest-branch, do the following. First update to the branch you want to copy the changes to:
hg update dest-branch
Then, use graft to copy the revisions you want from the original branch, e.g.:
hg graft -r start..end
where start is the first revision you want to graft from the source branch and end is the last revision.
You may encounter conflicts if they can't be merged cleanly, which you have to resolve them (as you'd do in a merge), then use hg graft --continue to graft the remaining revisions.
The magic word is RTFM - hg help rebase
We have recently moved from Perforce to Mercurial, and we are struggeling a bit to find out how to merge only certain changes to our stable releases.
We have a central repository that all developers clone from.
In Perforce, we have been using branches to maintain releases, and then merging only bug fixes per change lists from branches into trunk, or the other way around into branches that needed that fix.
In Mercurial, we have implemented this by cloning, where each stable release is a cloned repository of trunk.
Our structure looks a bit like this:
Trunk
|- Release 1
|- Release 2
|- Release 3
My question is, how can we merge only specific change sets from trunk into a branch? I hope there is an easy way to do it, preferably using TortoiseHg, since we have a lot of developers with different experience level that will be doing this.
I might not understand fully what you want to do.. but yes you can take changes from one branch into another branch (e.g., from the trunk, called default in Mercurial, to a release branch). In modern Mercurials, this can be done using the graft command (or before the transplant extension). To use it on a branch type: hg graft REVISION (see hg help graft for more details).
Now what I don't understand is that it seems that you do not have several branches but only one (default) and several clones (?), in which case everything becomes a bit more complicated.. You could pull only one changeset but then you need to pull also its ancestors and it is difficult to know what you actually get into your clones working directories! So I would really advice to create the release branches!
Hope it'll help.
I am new to Mercurial and still somehow in the evaluation process, so these four concepts are kind of confusing for me. Some are mentioned to be an equivalent to Git's Staging/Index concept, or some even a better one than Git's Staging.
How do the four commands hg graft, hg record, hg qrecord and hg shelve (and hg transplant, but this is explained in Graft vs. Transplant already) compare to each other, and how the concepts of queues and the dirstate? In which use cases is one choosen over the other?
I know there are help pages for each one, but it still is difficult to figure out what each one does as VCS in general is a new topic for me.
The design of Mercurial simply does not include the concept of a staging area. That is, there is no intermediate state between local modification and commit.
Here is an overview of each of the concepts you mentioned:
hg graft is the equivalent of git cherry-pick. It copies a commit from one branch to another. A typical use case for this feature is to copy a bug fix from one release branch to another. This command replaces the older (and now obsolete) hg transplant extension.
hg record and hg qrecord are similar to git add --patch. They allow you to interactively select hunks for commit. So if you modified several different areas of one file, you could select which areas (i.e. hunks) you actually want to commit and which you want to leave as local modifications.
qrecord is only available if you have mq enabled. It commits to an mq patch rather than a standard commit.
hg shelve is similar to git stash. It allows you to temporarily set aside local modifications to your files (or hunks of a file). These modifications can then be unshelved when you are ready for them.
dirstate is an internal class of of the Mercurial source code. It is not exposed to the user.
Mercurial Queues (also know as mq) are probably the closest you will get to a staging area in Mercurial. Here is a description from the Mercurial wiki:
Changes are maintained as patches which are committed into Mercurial.
Commits can be removed or reordered, and the underlying patch can be
refreshed based on changes made in the working directory. The patch
directory can also be placed under revision control, so you can have a
separate history of changes made to your patches.
mq is often used to polish/rework commits that you are testing locally, but have not pushed to a public location. Some people also use it to maintain a set of modifications to 3rd party code.