Mercurial Workflow with Branching

I've written a bit about mercurial over the years, but never once mentioned branching. This is my basic guide to branching (I'm a basic kind of person) and it's based on a short email I wrote myself a long time ago, which I still occasionally rely upon. If you're unsure about anything, simply test it for yourself.

Our story begins, some happy day, when you are working very hard, in an existing repository. I don't know or care how you got the repository. Maybe you created it (with 'hg init') or you copied it (with 'hg clone').

Now, as you are working you realize that you want your current work to be put into a branch, to keep it out of harm's way.

Let's say you are working on a feature called WEAPONISE_SPACE, and you don't want to accidentally release it before the public have been warned. A branch is a nice place to perform your work, away from the boring, safe work the rest of your team are engaged in.

> hg branch WEAPONISE_SPACE
marked working directory as branch WEAPONISE_SPACE
(branches are permanent and global, did you want a bookmark?)

And obviously, if you are brave enough to weaponise space, you are brave enough to create branches that are permanent and global. If you do regret the 'hg branch {branchname}' command, then it can be immediately undone with 'hg branch -C' (or 'hg branch --clean').

The beautiful thing here is that you didn't need to create the branch before you started writing code. You just need to decide before your first commit.

Now when you commit, you will be committing on that branch:

> hg commit -m "Adding a small laser to the space shuttle"

When you try to push your work, let's see what happens...

> hg push
pushing to https://Nasa.gov/repo/shuttle
searching for changes
abort: push creates new remote branches: WEAPONISE_SPACE!
(use 'hg push --new-branch' to create new remote branches)

This is good... maybe you wanted to finish working on that feature before you pushed it? Mercurial won't let you accidentally push out a new branch. But it is an OK thing to do, if you want someone else to help you with your work, so let's use the new-branch option:

> hg push --new-branch
pushing to https://Nasa.gov/repo/shuttle
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 4 changes to 4 files

Now, your comrade Veronika is helping you weaponise space, as she is a specialist in weapon targeting systems.

She can see that the repository now has two heads (the default branch, which she last worked on, and your new branch)

> hg heads
changeset:   35:099848c53b6c
branch:      WEAPONISE_SPACE
tag:         tip
user:        laserKid
date:        Thu Sep 17 16:19:44 2015 +1000
summary:     further improvements to laser

changeset:   34:c836214f7238
user:        Veronika
date:        Wed Sep 16 17:04:16 2015 +1000
summary:     initial

She gets all changes:

> hg pull
pulling from https://Nasa.gov/repo/shuttle
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads)

Now Veronika has your code on her machine, but not in her working folder, as she hasn't 'update'd yet. If she's unsure what branch she's currently on, she can easily check:

> hg branch
default

She's still on default. If you haven't branched, then you are in the "default" branch.

How do we switch to the branch of our choice? We update to it...

> hg up WEAPONISE_SPACE
4 files updated, 0 files merged, 0 files removed, 0 files unresolved

If she had some local uncommitted work (or uncommitted merges) she would've gotten one of these two error messages:

abort: crosses branches (merge branches or use --clean to discard changes)
abort: outstanding uncommitted merges

...and she would've needed to commit her current work to default (or revert it)(or commit it to a different new branch, I guess), before proceeding.

Now, she's updated to the WEAPONISE_SPACE branch, she can work on it, commit her changes, and push:

> hg commit -m "Added a targeting system to LaserKid's laser."
> hg push

Back on your machine, you can pull Veronika's changes and update your local files.

> hg pull
...
> hg up
...

The manager rushes into the room and tells you that global tensions have increased and we must weaponise space TODAY! There's no time to inform the public, or test the lasers! You must ship the code as is! So, with a heavy heart, you close the branch, using a commit just for this purpose. (This is an optional step... but good repo hygiene! Any subsequent work on that branch will automatically cause it to reopen.)

> hg commit -m 'Finished Weaponising Space!' --close-branch

Now you want to merge that feature into the default branch. First, switch back to the default branch. Then merge the feature branch in. After that you can commit the merge and push it to the world.

> hg up default
...
> hg merge WEAPONISE_SPACE
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
> hg commit -m "Space... get ready for Weapons!"
> hg push
pushing to https://Nasa.gov/..

The rest, of course, is written in the history books. The targeting systems were good, but the laser intensity was poorly calibrated. Two continents were destroyed in the ensuing war.

Live fast, die young, leave a well-maintained repo history.

For extra credit....

When pushing, *only* push the current branch (the branch you are working on)

hg push
> hg push -b .

So, when pushing a new branch...

hg push
> hg push -b . --new-branch

When committing, include the A option (short for '--addremove') to ensure you're adding any new files.

hg commit -m "My commit message"
> hg commit -Am "My commit message"

(Make sure your .hgignore file is fully fleshed out, so you are not committing new files that don't belong in the repository)

For fullest extra credit... when pulling in other people's changes, if you want to merge them with your local changes, without creating spurious extra commits, use the --rebase option (requires the rebase extension in your mercurial config)

> hg pull -b . --rebase

To enable the rebase extension, you need to... actually, I've written all about that in this guide to mercurial extensions so just go there.

Summary/Cheatsheet

Command Comment
hg branch Check which branch you're working on
hg branch WEAPONISE_SPACE Create a branch
hg push -b . --new-branch Push only the current branch (which happens to be new)
hg push -b . Push only the current branch
hg heads See if there are any open "heads" (e.g. open branches)
hg pull -b . --rebase Pull just the current branch
hg pull -b WEAPONISE_SPACE --rebase Pull only the contents of a named branch (and merge any local commits you've already made)
hg up WEAPONISE_SPACE Switch to a named branch. So this will update the current working folder to contain the work from the named branch.
hg commit -Am "committing here!" Commit to the current branch, while addremoving files
hg commit -m 'Finished Weaponising Space!' --close-branch Close the current branch (good hygiene)
hg up default Update so that the current branch is now the default branch
hg merge WEAPONISE_SPACE Merge a named branch into the current branch

External Links

See Also

 

My book "Choose Your First Product" is available now.

It gives you 4 easy steps to find and validate a humble product idea.

Learn more.

(By the way, I read every comment and often respond.)

Your comment, please?

Your Name
Your Url (optional)
Note: I may edit, reuse or delete your comment. Don't be mean.