Lately I'm playing with Mercurial (hg) and Git but I couldn't tell the difference between the two. Actually it is quite thin but noticable. Here's a comparison of hg vs git and my conclusion
Sorry for the format but these are notes I took while playing with hg and git. I 'm too lazy to format them in html ;)
# this comparison assume that you have # a ~/.gitconfig and a ~/.hgrc configured # with your username (otherwise you need to # add your username at every commit) mkdir /tmp/scm-tests cd /tmp/scm-tests # create a central repo mkdir [scm]-central git: git init --bare git-central # bare: you need to look at the man page to # find this - needed otherwise you not be # able to do push (you will need to go to central and pull) hg: hg init hg-central # on the contrary hg assume by default # that you can push (might be seen as # a security issue - that doesn't bother me) # user1 clone central mkdir [scm]-user1 git: git clone /tmp/scm-tests/git-central/ git-user1/ # you will get a 'warning: You appear to # have cloned an empty repository.' I don't # understand why they putted that ?! what's the problem here ? hg: hg clone /tmp/scm-tests/hg-central/ hg-user1/ # add and commit 2 initial files $ cd [scm]-user1 $ ls OTHER.TXT README.TXT $ cat OTHER.TXT other file $ cat README.TXT readme file git: git add README.TXT OTHER.TXT git commit -a -m "user1 modif1" # using the 'a' option or not # could be a post on itself hg: hg add README.TXT OTHER.TXT hg commit -m "user1 modif1" # pushing modification to central repo git: git push origin master # here you get some obscure # message in the output like # 'Delta compression using up to 2 threads' hg: hg push default # creating user2 and cloning central $ cd /tmp/scm-tests mkdir [scm]-user2 git: git clone /tmp/scm-tests/git-central/ git-user2/ hg: hg clone /tmp/scm-tests/hg-central/ hg-user2/ # - - - - - - - - - - - - - - - - - - - - # concurrent modification of different files # - - - - - - - - - - - - - - - - - - - - modify [scm]-user1/README.TXT modify [scm]-user2/OTHER.TXT git: cd git-user1 git commit -a -m "user1 modif" cd ../git-user2 git commit -a -m "user2 modif" hg: cd git-user1 hg commit -m "user1 modif" cd ../git-user2 hg commit -m "user2 modif" # push user2 modif to central git: git push origin hg: hg push default # pull from user1 cd ../[scm]-user1 git: git pull origin master # I always have a doubt if it's # origin master or the opposite hg: hg pull default # notice that you don't need to tell # hg where you want to send the changes # it assume it's the current dir ... (run 'hg heads' to see heads, 'hg merge' to merge) # this message is important because it means you # have to issue 2 extra command to merge otherwise you can't push # the merge will be easy but in this case git just does it ! hg merge # we don't specify any revision, # hg is smart enough to find the right one hg commit -m "Merge" # by default in tortoisehg the # commit message is already configured - don't know if it's # a tortoisehg feature... # push user1 modif to central git: git push origin hg: hg push default # pull user1 modif in user2 folder cd ../[scm]-user2 git: git pull origin master hg: hg pull default ... (run 'hg update' to get a working copy) # again this message is important, hg fetched the central # repo info, but didn't moved you automatically on the latest revision # we could have done this by using the -update option, # but I wanted to show you this situation hg update # another extra command compare to git # diplay graph of what we made git: git log --graph --color # notice the commit 'Merge branch...' was done # automatically, we did nothing (except push and pull) * commit 817f6e11a14530c6b09502edd069895ab19d8aea |\ Merge: b0647d4 c0a4f25 | | | | Merge branch 'master' of /tmp/scm-tests/git-central | | | * commit c0a4f259c33f8d8876088b08703776bb2739bb4a | | | | user2 modif | | * | commit b0647d415b30a407f0367ff96e5a417956d83d93 |/ | | user1 modif | * commit 6ffe857f8ece5ea7df051975b36c4384bdbe1383 hg: # didn't found any text based graphical tool # at first but apparently there is an # extension off by default: # http://mercurial.selenic.com/wiki/GraphlogExtension hg log hangeset: 3:2e322ec563c5 tag: tip parent: 2:995f574cea3d parent: 1:4d258b644a75 summary: Merge changeset: 2:995f574cea3d parent: 0:a3ebb2490ce5 summary: user1 modif changeset: 1:4d258b644a75 summary: user2 modif changeset: 0:a3ebb2490ce5 summary: user1 modif1 # git and hg: same number of revisions # - - - - - - - - - - - - - - - - - - - - # concurrent modification of the same file (with conflict) # - - - - - - - - - - - - - - - - - - - - modify [scm]-user1/README.TXT modify [scm]-user2/README.TXT the same line commit code omitted # push user1 to central git: git push origin hg: hg push default # pull central to user2 cd ../[scm]-user2 git: git pull origin master ... Auto-merging README.TXT CONFLICT (content): Merge conflict in README.TXT Automatic merge failed; fix conflicts and then commit the result. hg: hg pull default ... (run 'hg heads' to see heads, 'hg merge' to merge) hg merge # extra command merging README.TXT warning: conflicts during merge. merging README.TXT failed! ... use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon # fix conflict by editing file vi README.TXT # mark file as merged git: git add README.TXT git commit -a -m "fixing conflict" hg: hg resolve -m README.TXT # this m option was hard to find hg commit -m "fixing conflict" rm README.TXT.orig # I don't know if it's me not # using hg properly or hg behavior but we need to # cleanup manualy some backup file :( # push user2 conflict fix to central git: git push origin hg: hg push default # update user1 cd ../[scm]-user1 git: git pull origin master hg: hg pull default ... run 'hg update' to get a working copy) hg update # extra command # diplay graph of what we made git: git log --graph --color # notice that this time there is no automatic merge message but ours * commit 58e0ec598f272ac5d4dff02b7a9d0e3842a08c81 |\ Merge: 7c4b4dc e176f07 | | | | fixing conflict | | | * commit e176f07da2db925528c7a068af5f558484af6f56 | | | | user1 modif conflict | | * | commit 7c4b4dc8cbbb49138312df41fe19f2b2dee90d2b |/ | | user2 modif conflict | * commit 817f6e11a14530c6b09502edd069895ab19d8aea ... hg: hg log changeset: 6:6f8dceccba2d tag: tip parent: 5:32085fee1b07 parent: 4:7417be83b483 summary: fixing conflict changeset: 5:32085fee1b07 parent: 3:2e322ec563c5 summary: user2 modif2 changeset: 4:7417be83b483 summary: user1 modif2 changeset: 3:2e322ec563c5 ... # git and hg: same number of revision: 3 # - - - - - - - - - - - - - - - - - - - - # conclusion # - - - - - - - - - - - - - - - - - - - - learning curve (if you already know svn): git: not easy, need regular practice and at least one week to become familiar with command line args hg: 1 day, just feels like svn commands: git: 21 commands with (obscure) command line arguments hg: 50 (obvious) commands branches: git: merging from branch is done with one command line hg: you need to type extra (useless) command to merge in obvious (non conflicting changes) case. Apparently the extra (useless) commands behavior can be change by tuning some conf parameter: http://hgbook.red-bean.com/read/a-tour-of-mercurial-merging-work.html#sec:tour-merge:fetch vocabulary: git: origin hg: default windows support: git: lame hg: good (tortoisehg) linux support: git: good (git help are man pages) hg: good enough merge conflict: git: easy hg: less obvious / elegant me: I like both hg: because it's so easy to use git: for it's elegant way of handling merge and branches