How to commit only certain revisions to a cloned repository - mercurial

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.

Related

How to graft from other repository?

I have two repositories with tho different mercurual named branches, say V1 and V2. The branches are divergent since about one-two years. I'd like to graft some changesets from one repo into the other, without pulling the changes.
I don't want to pull the changes for multiple reasons.
I don't want to conflict developers with history of multiple branches, because there will be enough local branches to care about.
I want to have single branch central repos and developers could accidently push the second branch. The central branches would interact with SVN and should have only one branch per repo. I know I could use central hooks, to prevent such a push, but I don't want questions like, can't push, or how can I do that.
The size of the repo would grow to multiple gigabytes (before pull about 700MB). As I understand, it's because of deficites of current mercurial storage format.
I know, the transplant extension can do the work. I tried it, but I can't force other developers to handle rejects instead of simply use a merge tool. Is there an other way?
In fact there are more then two repos with each a branch, but for the example simplicity two should be enough.
You might be able to do the work in an intermediate repo:
Pull in the changes
Do whatever grafting/rebasing/transplanting you need
Strip out the things you pulled in step 1. or if that doesn't work:
Pull only the changes from the branch you want into the actual repo
You'd end up with a repository that includes your desired change sets, but not all the history from the unwanted branch.
Follow-up to #DanMan
Pull needed branch into intermediate repo
Strip unwanted changesets in clone
hg pull CLONE in real target
Write a tool, a hg-extension or extend the graft command so it can graft from a second repository, similar to the transplant extension.
Yes, the implementation is not so easy as adding the second-repo-functionality in the transplant command. The transplant extension simply uses a patch from an other repo instead of one from own repo. But I think also for graft there is no technical reason, not to do that.
If I understand right, grafting of a single file change is not more than calling the merge tool with the files:
(base) the parent of the to-graft changeset
(my changes) the target revision, on which to graft
(theirs) the to-graft refision
So in order to graft a file change from an other repo, the whole file from other repo is needed before the to-graft changeset was applied (base) and after it was applied (theirs). Technically it should be no problem.
Additionally the implementation
need to determine, which files are affected by the changeset to graft
need to handle deletions correctly
need to handle file renamings (not sure, how complicated it is)
All that should be possible, I see no real technical problems.

Mercurial: graft vs. record vs. qrecord vs. shelve vs. transplant vs. dirstate vs. queue

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.

Mercurial different heads

we are a team of 3 developers using Mercurial as a SCM tool, and I recently noticed the current heads (revision numbers) are different between the 3 of us, after everybody has pulled the latest changeset from the central repository. I'm at 2483 and the others are at 2482 (numbers are arbitrary, but mine is +1 compared to the others'). Is this something normal? Because it looks to me as a problem.
We've recently worked on a branch, then switched back to the default branch and merged with the branch. The only thing I can think of is that 2 of us did the merge and pushed the merge to the central repository, instead of only one doing the merge, pushing, and the others pulling the merge. Can someone help with an idea, maybe this is normal after all?
Things to look at:
12455:8b908304cb1c is the revision number of my current head. 12455 is a local number, it's only valid for my local repository, it's not global identifier portable between my own repos, or between my repos and my coworkers. 8b908304cb1c on the other hand is a globally usable identifier. 8b908304cb1c locally can be used to refer to the exactly same revision in every repository that contains that commit
hg outgoing will show you what needs to be pushed. hg incoming will show you what you've forgotten to pull.
hg heads --topo will show you the topological, unclosed, heads. This will quickly show you if you've got unmerged changes in a branch, or multiple heads in a single branch.

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).

Can I branch in Mercurial without cloning the repository?

Recently, I've started experimenting with Mercurial, due to the fact that it always attracted it because of its simplicity and "just works" principle. Or at least, that's how others always described it.
They also usually described it as "practically the same as git with just a few minor changes you won't notice" - only for me to discover it isn't quite so.
I'm having problem with Hg branches. Pardon me if this is an overly simple question, but in git one has a working directory and a repo (.git). In the repo one has revisions, and branches, and can jump from one to another.
I'm having trouble finding a similar model in Hg. As far as I can see, for Hg to have a "branch" one needs to clone a repo to another directory? Is there a way Hg could work just like git does - i.e. one working dir., and one repo, in which you can do things as regard to branching and revs?
Mercurial supports a very rich set of ways to branch. See http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
In brief, you can create a named branch by running
hg branch NewBranch
and switch to that branch using
hg up NewBranch
or switch back to trunk using
hg up default
In Mercurial, if you go to any particular revision, you can always edit your working copy and commit, thereby making another "head." Merging works on head revisions by default. You can use hg head to see what heads are in your repository. This seems to be the most "idiomatic" way I have found branching to work in Mercurial.
Take a look at section about branches in my answer to "Git and Mercurial - Compare and Contrast" here on StackOverflow.
The information about various options available for branching in Mercurial (anonymous heads, not-propagated (I think yet still) bookmarks, and global (world-wide) commit labels aka named branches) was taken from http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/, and expanded using feedback on #mercurial IRC channel on FreeNode.