About Mercurial, Git, and Github

Keep it Simple

Follow me onGitHub

I have gathered in this page my notes on using Github, Mercurial with Github, and Git (outside of Github) but from a Mercurial user point of view, and also from a lover-of-simplicity point of view :-).

In case of mistakes, please do not hesitate to use the current project issues to report them by simply creating a new issue on this project.

Using github

Please find some information below on Github usage.

Github is very well documented and for what is not described below, chances are the Github bootstrap articles will be helpful.

How to create static pages

To create "pages", see https://help.github.com/articles/creating-pages-with-the-automatic-generator (a bootstrap kind of doc).

Pages can be attached to:

  • organizations,
  • persons, like this one, or
  • projects (repositories)

How to use Mercurial with a Github repository

You do not need to have Git installed in order to commit and push your changes back to Github. You will need Mercurial, obviously, and also the Dulwhich python library and the hg-git extension; which installations are covered in the first step below. Once the extension has been enabled, the rest is pretty straightforward for Mercurial users: clone, commit and push as usual.

download and install hg-git

You need to install first the dulwich python git library, then the hg-git extension.

$ mkdir -p $HOME/.hgext
$ cd $HOME/.hgext
$ whet https://pypi.python.org/packages/source/d/dulwich/dulwich-0.9.5.tar.gz
$ tar zxvf dulwich-0.9.5.tar.gz
$ rm dulwich-0.9.5.tar.gz
$ cd dulwich-0.9.5
$ ./setup.py build
$ sudo ./setup.py install
[sudo] password for cmuller: 
running install
[...]
$ cd $HOME/.hgext
$ hg clone https://bitbucket.org/durin42/hg-git
$ cd hg-git/
$ hg update -C 'max(tagged())'

enable the hg-git extension in $HOME/.hgrc

[extensions]
hg-git = $HOME/.hgext/hg-git/hggit

clone the repository using Mercurial

$ hg clone git+ssh://git@github.com:cmuller/test.git
$ cd test
$ hg branch
default
$ hg bookmark
 * master                    1:0b48f2edc3f7
$ hg pull -u
pulling from git+ssh://git@github.com:cmuller/test.git
["git-upload-pack 'cmuller/test.git'"]
no changes found

Note: if the clone prints an error like AttributeError: 'match' object has no attribute 'traversedir', it is a known error in Mercurial 2.6.x: please upgrade to Mercurial >= 2.8.1.

commit some changes

$ vi README.md 
$ hg status
M README.md
$ hg commit -m"test of commit using hg"
$ hg status
$ hg outgoing
comparing with git+ssh://git@github.com:cmuller/test.git
["git-receive-pack 'cmuller/test.git'"]
searching for changes
changeset:   2:2ee128a7362a
bookmark:    master
tag:         tip
user:        Christophe Muller <...>
date:        [...]
summary:     test of commit using hg

push your changes back to Github

$ hg push
pushing to git+ssh://git@github.com:cmuller/test.git
searching for changes
["git-receive-pack 'cmuller/test.git'"]

Notes:

  1. it works. see https://github.com/cmuller/test/commit/a0b9ae9aa49118a915f1784894967f8e938ccf9e :-)
  2. it is interoperable with the usage of Git on the same repository. E.g.,
$ cd /tmp
$ git clone git@github.com:cmuller/test.git
$ cd test
$ git branch
* master
$ git show HEAD
commit a0b9ae9aa49118a915f1784894967f8e938ccf9e
Author: Christophe Muller <...>
Date:   [...]
    test of commit using hg
[...]

Using git

This is my cheatsheet for using git, with a few links to tutorials that I found useful.

Some Git equivalent to Hg commands

This is my Hg to Git cheatsheet. A complete list exist in the mercurial wiki that you might want to check in addition with the explanations on the deep differences (e.g., on branches). I advocate using only default in mercurial and master in git :-) so I won't get into these details. As for the equivalences, I have put below mostly what I use every day, so this is not an exhaustive list.

help

hg help -> git help

In hg you basically need to know that the concept you are looking for exists or is implemented by an extension; after that, hg help, 99% of the time, is enough and provides you with the information you need. On the other hand with git it is probably better to know beforehand what to do and only spend time in git help at the very last resort, i.e., after google, SO, etc.

basic commands

hg init -> git init

hg clone -> git clone

hg add -> git add

hg commit -> git commit -a

hg update -u -> git pull

hg push -> git push

Not much differences here except the use of the staging area in git (you need to do git add before git commit or use the -a option) and the git pull which on the other hand does what we want in a single command.

displaying information

hg paths -> git remote -v

hg status -> git status

hg diff -> git diff

hg id -> git rev-parse --verify --short HEAD

hg tip -p -> git show

hg log -r 112 -p -> git show 2a0867...

hg branches -> git branch -a

hg branch -> git branch

Note that if a git add has already been performed on the modified file, the modification has moved to the staging area, so git diff --cached should be used in order to see it. The git show command is quite nice and easy to use. On the contrary if you really need to often get the current id, you'd better create an alias for that..

more complex (dangerous) commands

hg update -C -> git checkout --force

hg revert -> git reset --hard

hg backout -> git revert

Please note that the revert-type commands are completely different between Hg and Git so please double check the documentation before using! :-)

local server

hg serve -> git daemon --reuseaddr --base-path=. --export-all --verbose

Once hg serve is launched, a local server is started from which it is possible to clone, pull, push, etc. (using http protocol). Similarly with the above git command, a local server is started and it is possible to clone using the git protocol, e.g.,

git clone git://<ip-address>/.git project

Some Miscellaneous Information

My git links

There are literally hundreds of docs, tutorials, posts, manuals, books etc. on Git. That probably.. shows the need :-) Below are just two links I found useful: the first one is the very minimal survival guide (but not Mercurial-user oriented) in which you will learn what is the Index, the staging area, how to push to a central repo, how to use branches, etc. The second one is not actually git-specific, it helps you ask yourself the right question and helps you choose a workflow that suits your needs.

FAQ: How to create a new repository on a server

Whereas with mercurial-server it is possible to create a repository on a server by simpy cloning from your machine to the server's URL, this is not possible with git: you have to manually at least create a directory on the server (with the right access-rights, e.g., for your group of developers) init it, and then push to it, e.g.,

  1. log in the server
  2. mkdir /var/lib/git/repo.git
  3. cd /var/lib/git/repo.git
  4. git init --bare --shared
  5. find . -type d -exec chmod 775 {} \;
  6. find . -type f -exec chmod 664 {} \;
  7. exit
  8. on your PC, link to the server and then push to it, e.g.,

git remote add origin ssh://<server>/var/lib/git/repo.git

git push --all origin master

FAQ: How to change a commit log message after commit but before push

git commit --amend

How to merge a commit from a branch to master

If you have committed on a branch "b1" and want to merge this into "master", you only need to switch to the master branch, merge, and then you can push master back to the central repo, e.g.,

git checkout master

git pull

git merge b1

git push

After the merge you do not need to commit again: your changeset is already in the outgoing queue with the same metadata (author, date, log message) than the one on the branch.

How to permanently remove files or directories that have been committed and pushed

When this happen and something was committed that shouldn't have been, it can be useful to be able to log on the server and make things right again.. E.g., a clear password or confidential information, a huge data file, etc. In Subversion this operation involves using svndump and filters; in Mercurial using the convert extension; and in Git it appears to be a bit touchy as it will involve commands you probably do not use everyday (gc, prune etc.).

You can either follow the Github step-by-step tutorial here: https://help.github.com/articles/remove-sensitive-data

Or try solutions from the SO post below. This is what I did: I created a shell script starting from David Underhill's one: http://dound.com/2009/04/git-forever-remove-files-or-folders-from-history/ and adding the git reflog, fsck, repack, and prune commands as described in: http://stackoverflow.com/questions/2164581/remove-file-from-git-repository-history

Please let me know if you would need my script but basically all the commands needed are already in both David blog post and the SO answer.