Mercurial Tips

Started by dmilligan, December 11, 2013, 08:38:25 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


ML was my first foray into the world of distributed version control. I have learned a lot from reading and making mistakes, and I thought I'd share what I've learned and my general workflow here in the hopes that it will be useful to other DVCS newbies.

If you're not already an expert on mercurial, see:
I assume you already know how to do basic stuff like clone/add/commit/branch/merge etc. I also recommend finding a nice GUI that you like (I use SourceTree, its nice, but Mac/Windows only and IMO the mac version is superior to the windows)

#1: Branches over Forks
In DVCS there's not really much difference between a branch and a fork (clone). You can use both to work on something outside of the main 'trunk' and then merge it back later. But there are some very good reasons to use branches rather than multiple forks (like I see a lot of ppl do, and like I did starting out). The main reason is that it is much easier and faster to switch your working copy between branches of the same repo, than it is to change repos entirely. This comes in very handy (more on that later). You don't have to submit a pull request (PR) from your 'unified' branch to the main repo's 'unified' branch, you can select any of your own branches to submit a PR from, which leads into the next point...

#2: Don't commit to 'unified' in your fork
If you keep unified (the main branch) 'pure and undefiled' then you know every time you click the 'sync now' button in your bitbucket fork (and then pull to your local), 'unified' will contain exactly the current state of the main repo. If you want to do a 'quick-fix' patch to the current main, you can just create a new branch off of 'unified' at the current point in time, and submit that branch as a PR without worring about it containing any of your other, unrelated WIP or a pending PR.

Another use of this is that you can easily switch to unified and build if you want test that an issue is being caused by ML main or your own code. Switch to 'unified' and build, then run some tests, switch back to your own branch, build and test. Now you know the source of your issue. If you have uncommited local changes when attempting to switch branches, you can easily 'shelf' them and restore them later.

This also allows you to keep using the same fork and keep it up to date, even if you have a PR pending for a while (which happened to me frequently).

#3: Keep your personal tweaks in their own branch
We all have our own personal tweaks for ML (disable the warning screen, flexinfo customizations, etc) that would never get merged. To avoid them finding their way into your PRs, keep them in a separate branch. This makes it easy for you to still keep them under version control and easily merge them with updates from your other feature branches (that are intended to be PRs) and changes from the main repo.

#4: Use a 'working' branch
So now you've got a bunch of branches for each different feature you're working on and for your tweaks. You say: now I can't use all of them together for my own working version of ML that I actually use day to day out in the field. Wrong! This is where the 'working' branch comes in. The purpose of this branch is simply to create your 'working' version of ML, with all your changes, pending PR, and tweaks all combined. All you do is simply create this branch and merge all of your other branches to it. Don't ever work on this branch or commit (other than merge commits) stuff to it. It's simply there to be merged onto, like a 'branch aggregator.' (You can even pull other dev's tweaks that you want to use into your working, like 'unsafe' stuff from TL)

Make your changes in other branches and then merge them into this branch. This lets you keep you changes separate (so you can easily PR them separately). When you are testing and working on certain things, you do it in those particular branches. This helps you know the source of bugs. If you're working on two different features at the same time and you have a bug, you might not know which feature is the source, unless you keep them separated like this, then you'll know instantly. Finally, when you're done developing/testing and ready to have Your Version Of ML™ to work with in the field, just merge everything to working and build.

#5: Close unused branches
This wasn't exactly intuitive to figure out how to do in bitbucket so I'm simply sharing how you do it, so that you can keep your 'tree pruned' from branches you're no longer using:
Click on 'branches' in bitbucket.
For the branch you want to close hover your mouse near the right edge of the list, you'll see three dots.
Click and you get a pull down with an option to close the branch.

If you have any additional tips, please share them. I'll update this post with others' tips or new things as I learn them.


Thanks for this!  I'm just getting started developing and use hg at work and for private projects, but didn't have a clue to the "best practices" for a distributed version control open source project spread out across multiple individuals.


Is there a special way to get a clone from a specific date of sources on bitbucket?

Quotehg clone -r 852ad87b59fd7a9b948482eff6da25ad8fc122e1
To clone 2014-01-20 ML sources reports 'not found'.


clone the whole repo, then update to the changeset you want


To clone a specific commit, only use the first 7 characters.

hg clone -r 852ad87

Or, as dmilligan said.


When creating a pull request to a branch in ML, other then unified, you must start from that (other) branch when making the changes in your own repo.

If you do what I did, and start from the unified branch and create a pull request, any new commits in the unified branch will become part of your pull request, when try to pull request to this other branch.

Here's how I fixed it without creating a new pull request.

Update this other branch to head.
Make changes and commit it to the same branch name that you used for the pull request.  Confirm restart branch.
hg update -r 123  (the revision being the original branch revision you created for the pull request)
hg commit --close-branch -m 'Closing old branch'
hg update -C unified
Push your changes to your online repo.
Edit the existing pull request.

Pruning the old branch first may be another way.


Thanks dmilligan! This made keeping track of all the various branches so much easier. Installed the on my Mac and life is wonderful. However, there's trouble in paradise--how to do a pull request for the main unified branch? I setup my remote repository paths like this:

default           https://[email protected]/daniel_fort/magic_lantern

but when I tried to post a pull request to origin it wouldn't accept my password then it gave me an "Access denied" error on the webpage. I would have tried doing it on the command line but the Mercurial tutorial isn't that clear on how to do it. The tutorial also says that users should be registered to access the main repository.

On my last pull request I went back to Audionut's Submitting a pull request all via web browser instructions but next time I'd really like to do it via Mercurial or SourceTree.


You can't push directly to the main ML repo ( You have to push to your remote, then create a pull request from a branch in your remote (in the bitbucket web interface). That's why it's called a pull request. Only the maintainer (a1ex) has the ability to pull changes, so you submit a request for them to pull your changes in, rather than you pushing yours (a push from repo A to repo B is the same thing as a pull from repo B to repo A).

In your situation there are actually 3 repos (and they are really all peers, the only difference is who controls them): You local repo, your bitbucket repo, and the main ML repo. You make changes in your local, push to your remote, and then make a request for the maintainer to pull from your remote to the main repo. To get new changes, you can just pull directly from the ML repo into your local.

a1ex has granted permission to devs who make regular contributions to ML to push to branches in the main repo, but not the unified branch. So we can create branches in the main repo and then create pull requests for those branches into 'unified' (the main branch). There's not a whole lot of difference between the two methods, but working in branches in the main repo makes it a little easier for us to collaborate on new stuff before it's merged (and eliminates the need for the intermediate repo as described in the above paragraph).


Thanks for the lesson. I certainly don't want to mess up anything, especially since one of my branches (fork?) ended up in the main repository without me being able to delete it. Thanks for cleaning up after me.

Let me see if I got this right:

Quote from: dmilligan on August 26, 2015, 11:13:04 PM
You make changes in your local, push to your remote, and then make a request for the maintainer to pull from your remote to the main repo.

I did changes on my local and pushed to the remote. I was even able to make a pull request to unified in my repository. Of course following your instructions we should never commit a change to the local unified branch. So at that point I should have submitted a request to pull in my changes? That's the piece of the puzzle that I'm missing, how to submit a request to move a pull request from a local repository to the main ML repository.

Making a new fork and redoing everything in a web browser to make a pull request isn't elegant but I also don't want to bother developers. Uh--guess I'm doing that now. Hope you don't mind that I added you as a reviewer to my last pull request.


You can't make a pull request to your local repo, because the maintainer has no access to your local computer. So you must push your changes to your publicly hosted remote repo, and make the pull request from that repo. A pull request really is just like saying "Hi, please pull commits from my repo X, branch Y into your repo Z, branch Q"

So, make your changes in a branch in your local repo. Push the branch to your remote repo. In bitbucket, create a pull request from your remote repo and the branch you created TO the hudson repo and the unified branch. If you are unclear on this process there is plenty of help documentation available bitbucket.


Forks over Branches?

That's what I got out of reading this document from the developers of bitbucket. I followed your instructions, specifically:
Quote from: dmilligan on December 11, 2013, 08:38:25 PM
#1: Branches over Forks

I was happly hacking away until I finally came up with something worthy of a pull request when this happened:

What? I can't make a pull request to the main unified branch?

So I went back to doing everything on the bitbucket website following Audionut's tutorial. This created a second repository in my work area which I didn't really want but according to Atlassian this one was a fork, not a branch which allowed me to make a pull request to the main branch:

So what I got out of this experience is that while developers with access to the main repository should probably work with branches, the rest of us should use forks instead.

Now I'd like to clean up my work area and start over with just a single fork to work off of but I have a feeling that deleting my "raw2dng Windows port" will also wipe out my current pull requests, right?


When I say branches over forks I'm talking about something different. That article is written from the maintainer's perspective. I'm talking from the contributor's perspective.

Yes, you do have to use forks, but what I mean is that you should only use one fork. A lot of people create a new fork for each pull request. This starts getting difficult to manage if you have several things in the queue at once.

Instead of creating a new repository (fork) for each PR, simply create branches in your single fork for each different thing you might be working on, and create the PR from that branch to the main ML repo's unified branch. This allows you to have several PRs open at once from one single repo and makes it easier to pull and merge any changes that might happen on the mainline in the meantime back into your branches. It also makes it easier locally, you can switch between the different branches you're working on and even merge them together.


Got it--one fork, many branches.

Thanks again for the lesson.


Thank for the tips, i have started developing  just now and i hope it will be helpful for me.