The scenario is that I arrive at work one morning and pull, update, merge my mercurial tree. From the now latest revision I begin working on todays task. I reach a logical milestone and does a commit. The tree now looks like this:
* <- my first commit for the day
|
* <- merge commit from shared repos by team
Now the boss comes along, something horrible has happened and it needs my immediate attention. He wants the solution pushed asap.
My plan for the day is disrupted. What is the best way to use mercurial to tackle this problem?
I could just write the solution and make another commit followed by a push. But this is bad since that commit would have my own first commit as parent, thus pushing incomplete code.
In a perfect world maybe that new feature Im coding will be in its own branch. But its a small feature and Im lazy, so it currently resides in default. I could try to find a way to move a commit from one branch to another.
I could ignore the panicking boss, do two or three more commits to complete the feature, push that and then start working on the fix, bringing those in as a separate commit and push.
Neither of those feels good. I would like something along the lines of:
Do an update, bringing me back to the merge commit.
Do the fix and commit it.
Push only the fix commit, leaving the incomplete-feature commit still unpushed.
Thus making the history like this:
* <- fix commit (pushed)
|
| * <- my first commit for the day (unpushed)
|/
* <- merge commit from shared repos by team
We've just migrated to mercurial here at the office, and this is one problem I would like to tackle. Any mercurial gurus here that mind sharing some wisdom?
The workflow you're describing looks good (update to merge, commit, push -r the fix). If you feel not comfortable with anonymous branches, you can first clone -r the repo up to the merge, commit and push.
Related
Is it
pull
update
merge
commit
push
? Or can you do the commit first?
I don't like the idea of pulling and merging without having a version of my local code backed up somewhere in case the merge explodes, but presumably you have to do the merge before you can do a push, because you can't have conflicts in the central repo. Not quite understanding this whole process yet; used to my nice simple SVN.
I recommend to always commit before pulling in changes to your working directory, unless you are 100% sure that your changes and the changes to be merged into your working directory will not conflict.
If you do an updating pull (hg pull; hg update, or shorter hg -u pull) and have any outstanding non-committed changes, any changes coming from outside will be combined with your changes. When conflicts happen, it might be difficult to decide how the merge result should look like, because you can't easily distinguish between your changes and the changes merged in.
When you did commit first, it is much easier to decide how the merge result should look like, because you can always look at both parents of the merge.
So, in effect it is:
hg commit
hg pull -u (if no merge necessary, go to 5)
hg merge
hg commit
hg push
Update: As Martin Geisler has pointed out, it is possible to get at the "original" changed version of a file using:
hg resolve --unmark the-file
hg resolve --tool internal:local the-file
or for all files at the same time:
hg resolve --unmark --all
hg resolve --tool internal:local -all
Still, I find the "commit first" system nicer. At the end, it is personal preference...
I don't know as there's a standard per se, but one of the ideas behind Mercurial is that you can commit as often as you like since it goes to your local repository. So you can commit to your heart's content as much as you like before you pull updates.
I tend not to commit very often, saving up for when I'm preparing to push, but that's me. I can see the utility of committing early and often. I do pull updates frequently as I work to cut down on merge fun.
One other thing I do is to keep a parallel clone of my working repo (cloned from the same repository as my working repo, not cloned from my working repo) so that I can check the original state of a file easily, and if need-be check in an out-of-band emergency fix or what-have-you without complicating my current change set.
Do edits
Commit
Goto 1 until satisfied
Pull
Merge & commit
Push if you want to.
Definitely commit before trying to do something complex like a merge. I don't think mercurial will allow you to merge before committing, but even if it did, what if the merge goes wrong. You have no pre-merge revision to go back to.
Commit early, commit often.
If you don't, you are missing out on a huge benefit of a DVCS.
but presumably you have to do the merge before you can do a push, because you can't have conflicts in the central repo
Wrong statement and poor understanding of distributed workflow and parallel development.
You can merge heads before push, but not have or must. Push can put any data to repo, if it needed and intended to be so
By default, push will not allow creation of new heads at the destination,
since multiple heads would make it unclear which head to use. In this
situation, it is recommended to pull and merge before pushing.
(NB: "recommended to pull and merge before" statement)
You can use commit-pull-merge, stash-pull-unstash-merge, perform fetch with modified WC and merge on the fly, don't merge heads at all or sporadically and push --force with +1 heads - there are not common rule for everybody. And any and every such workflow doesn't produce "conflicts in the central repo", but only different DAG.
Each point of divergence, which appear in case of existing your and other changeset from commmon parent in your (or even central) repo is a point of starting anonymous branches in Hg, which (technically) are absolutely legal, applicable and usual way. How they handled is defined by policy and agreement between developers, PM, QA-team and others
I, personally, prefer finish my task (in one or more amount of commits), after it pull and maybe merge, when it approved by development-policy
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 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).
We just changed over to mercurial from subversion and there is one thing that is taking up more time than expected; merging heads.
We love the fact that it keeps merges independent from the 2 commits (compared to subversion) but we end up on a regular basis merging 2 heads for unrelated changes.
Simple scenario.
Both me and Bob are up to date.
We both have ou repo up to date on default (aka main) branch and do improvement in different files.
We commit and only one will be able to push to the central server, the other one will create 2 heads. Then, pull, select 2 heads, merge (it will go easily since changes are on different files). Commit, then push.
Therefore, is there an extension that does these steps
Attempt merge
If no conflicts
Commit
else
Cancel merge
We are looking to have this run on an automated server, so +1 it this is command line and another +1 if it can do the merge without touching the working copy.
Thanks!
Update:
We ended up doing a few python scripts to manage the most common tasks (merge up & build; merge 2 heads).
Thanks for the help!
It sounds like you should be able to use hg fetch for this. It'll pull the changes from the server, merge, and then automatically commit the merge. It does prompt for merge conflicts as well. It's included with Mercurial, so just add
fetch =
to your hgrc, and you should be all set. It doesn't automatically push, but that's usually a bad idea anyway. You would typically want to run tests and resolve any merge problems before pushing your code out to everyone else.
Are the merges really taking that much time? If they're "unrelated changes" doesn't it just take a blink?
Someone already suggested fetch and someone else will probably suggest rebase, but personally I consider merging to be coding, and want it to be manual. It takes almost no time and it's an opportunity to give a good message like "Pulling in Jane's work half-way through my FooBar work" (instead of the useless commit messages fetch provides).
I'm going through Bitbucket and I can't seem to find any Mercurial repositories that look like what I suspect our repository would look like, provided we switch to Mercurial.
As such, I'm wondering, is there a workflow that we're not considering here?
The thing I'm talking about is that I did a small automated test. We're 14 people that work on the same project, split into 4 scrum teams. To simulate 14 (I picked 10, round number) people working in parallel on the code, using Mercurial DVCS, pushing to the same central master repository, I wrote a script.
I created a new "master" repository, and then cloned it for 10 virtual people
I then ran a 1000 iteration loop, picking a random clone, and doing one of the following:
10% of the time, do a pull from master, merge, commit merge, and push
90% of the time, do a local change and commit
Note that I ensured that there would never be merge conflicts by simply making each virtual person work on his own file.
This would simulate people working locally by doing 1+ commits before pulling, merging, and pushing (to avoid 2+ heads in the master repo). It might be that this workflow is wrong.
This is a sample of what the repository now looks like (screenshot + link to repo):
The repository can be found here: http://hg.vkarlsen.no/hgweb.cgi/parallel_test/graph. Unfortunately this repository is no longer available and I no longer have a copy of the code due to an unfortunate backup incident, but this was just an example for people to visit, it should not be important any more
This looks awfully messy, and as I said, I can't seem to find any repositories that have similar history. By "messy", I mean that it looks like older history of the project will almost always have 10 parallel branches. Close to the top, it tapers off of course, but it will expand as people that are currently working in their local repository pushes to the master.
So I have two questions:
Can anyone show me a repository that has similar history? Since I can't seem to find any, I'm starting to wonder about what kind of conclusions I can draw from that...
Is there something wrong with our workflow (that is, the workflow I've laid out here)? Should we rebase/squash/transplant, delegate push responsibility to one person, other things, instead of the way it was done here?
Impressive preparation!
It always looks messy if you go back a bit and look at all old commits at the same time. It always tapers of, even looking at a small bit old history. See http://hg.intevation.org/mercurial/crew/graph/12402?revcount=120 for instance. This is not the most recent commit, but shows all history up to that commit.
Rebase helps quite a lot, especially if persons are working on separate areas. (I usually check the incoming commits to see if there are potential file or functionality conflicts, and if not, I do rebase.)
Rebase is not fool-proof though, so merge is the preferred "safe" action, but it leaves more "garbage" in the history. A trade-off.
Rebase is sort-of like the bog standard SVN update. The existing stuff is made baseline and your changes go on top, cross your fingers it still works. It's useful, but there are times when you feel safer having yours, theirs and the merge as separate commits in the history.
There is also commit-squashing as an option (histedit extension maybe), which squashes all in-between commits to one. This is useful when you're about to push and want to transferring many partials commits in your own repo as a single commit to the main.
I have 12 developers working in the same Mercurial repository at work, and our history looks nothing like that. There are occasional merge commits, but most merges are from merging actual branches, i.e there might be a merge in our main development branch bringing in changes from a bugfix release made on the production/release branch.
This is very easy to achieve, developers hack and commit to their local repository and when they have something stable enough to share with the rest of the team they push.
If nothing has been committed since they started committing the push goes through without problems.
If someone else has committed a change, Mercurial complains that the push will create remote heads. The developer then does a hg pull --rebase and retries the push. The push goes through and everyone is happy.
If you are using continuous integration with developers regularly pushing to a shared repository, this is the way to go. Knowing whether you have pushed changes or not is easy and you avoid lots of useless merge commits cluttering up your history.