views:

6524

answers:

8

For a while now I've been using subversion for my personal projects.

More and more I keep hearing great things about Git and Mercurial, and DVCS in general.

I'd like to give the whole DVCS thing a whirl, but I'm not too familiar with either option.

What are some of the differences between Mercurial and Git?

Note that I'm not trying to find out which one is "best" or even which one I should start with. I'm mainly looking for key areas where they are similar and where they are different, because I am interested to know how they differ in terms of implementation and philosophy.

+30  A: 

I think you can get a feeling of what those systems are similar or different in by whatching those two videos:

Linus Torvalds on Git (http://www.youtube.com/watch?v=4XpnKHJAok8)
Bryan O'Sullivan on Mercurial (http://www.youtube.com/watch?v=JExtkqzEoHY)

Both of them are very similar in design but very different in implementations.

I use Mercurial. As far as I understand Git, one major thing git is different is that it tracks contents of files instead of files themselves. Linus says that if you move a function from one file to another, Git will tell you the history of that single function across the move.

They also say that git is slower over HTTP but it has it's own network protocol and server.

Git works better as an SVN thick client than Mercurial. You can pull and push against an SVN server. This functionality is still under development in Mercurial

Both Mercurial and Git have very nice web hosting solutions available (BitBucket and GitHub), but Google Code supports Mercurial only. By the way, they have a very detailed comparison of Mercurial and Git they did for deciding which one to support (http://code.google.com/p/support/wiki/DVCSAnalysis). It has a lot of good info.

artemb
I'd recommend reading all of the comments on that google code page. The information does feel somewhat biased and doesn't match my experience well. I like hg, and used it *extensively* for a year or so. I use git almost exclusively now. There are things I need to accomplish that git makes easy and hg makes nearly impossible (though some like to call this by means of "complication.") Basic git is as easy as base hg.
Dustin
Dustin, maybe list some of those "git easy, hg not so much" cases?
Gregg Lind
afaik google code supports git too?
knittl
@knittl no it doesn't. Mainly because it would be a pain for them to deploy it since git lacks a smart http protocol (most of Google front-ends are http-based).
tonfa
@tonfa: Smart HTTP protocol for Git is currently being developed (as in: there are patches on git mailing list, and they are in 'pu' = proposed updates branch in git.git repository).
Jakub Narębski
@Jakub is the protocol described somewhere? We might do major changes in hg protocol so it might be helpful to see what has been done elsewhere.
tonfa
@tonfa: Search for "smart HTTP" (or "Return of smart HTTP" in git mailing list (archives). For example latest protocol description is here: http://thread.gmane.org/gmane.comp.version-control.git/129732/focus=129734
Jakub Narębski
+8  A: 

Mercurial is almost fully written in python. Git's core is written in C (and should be faster, than Mercurial's) and tools written in sh, perl, tcl and uses standard GNU utils. Thus it needs to bring all these utils and interpreters with it to system that doesn't contain them (e.g. Windows).

Both support work with SVN, although AFAIK svn support is broken for git on Windows (may be I am just unlucky/lame, who knows). There're also extensions which allow to interoperate between git and Mercurial.

Mercurial has nice Visual Studio integration. Last time I checked, plugin for Git was working but extremely slow.

They basic command sets are very similar(init, clone, add, status, commit, push, pull etc.). So, basic workflow will be the same. Also, there's TortoiseSVN-like client for both.

Extensions for Mercurial can be written in python (no surprise!) and for git they can be written in any executable form (executable binary, shell script etc). Some extensions are crazy powerful, like git bisect.

elder_george
Mercurial core is written in C too FYI (but it's probably a smaller core than git).
tonfa
I use git-svn on Windows without any trouble. That's using Cygwin (the only *right* way to use git on Windows if you ask me). Can't speak for msysgit.
Dan Moulding
@Dan Moulding: Yes, I've experienced problems with msysgit. Maybe need give a try to cygwin port (I had some poor experience of using cygwin earlier, so I avoided it). Thanks for advice!
elder_george
I personally dislike cygwin's intrusion into the registry to store user data. It's a PITA to get it to run off USB key and keep a local c:\ drive copy synchronized for when I want to run faster than my USB key can go. :-/
Chris Kaminski
I use the Git plugin for Visual Studio mentioned above, and the performance of the current version is good. It shells out to the command-line tools to do the work, so I don't think that it will significantly lose performance on large projects.
Stuart Ellis
@Stuart Ellis Thanks, I need to give it a try again then =)
elder_george
@Chris Kaminski, `subst` your actual installation place to "W:\" and install Cygwin to W:\. This will make it relocatable.
Vi
+16  A: 

I use both quite regularly. The major functional difference is in the way Git and Mercurial name branches within repositories. With Mercurial, branch names are cloned and pulled along with their changesets. When you add changes to a new branch in Mercurial and push to another repository, the branch name is pushed at the same time. So, branch names are more-or-less global in Mercurial, and you have to use the Bookmark extension to have local-only lightweight names (if you want them; Mercurial, by default, uses anonymous lightweight codelines, which in its terminology are called "heads"). In Git, branch names and their injective mapping to remote branches are stored locally and you must manage them explicitly, which means knowing how to do that. This is pretty much where Git gets its reputation for being harder to learn and use than Mercurial.

As others will note here, there are lots and lots of minor differences. The thing with the branches is the big differentiator.

james woodyatt
See also this post for a good explaination about the four kinds of branches in Mercurial: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/
Martin Geisler
+3  A: 

Check out Scott Chacon's post from a while back.

I think git has a reputation for being "more complicated", though in my experience it's not more complicated than it needs to be. IMO, the git model is way easier to understand (tags contain commits (and pointers to zero or more parent commits) contain trees contain blobs and other trees... done).

It's not just my experience that git is not more confusing than mercurial. I'd recommend again reading this blog post from Scott Chacon on the matter.

Dustin
Mercurial model is actually almost identical: changelog points to manifest point to file revisions/blob... done.If you were comparing the on-disk format you probably didn't account for the packs file which are more tricky to explain than the simple revlog format from hg.
tonfa
Well, that simplified model ignores tagging which is considerably clunkier in practice in hg (though I do argue that git tag is a bit confusing because it doesn't create a tag object by default). The on-disk format was particularly expensive for both projects that had a history of a lot of filenames.
Dustin
I don't think the model ignores tagging: tagging is trivial in Mercurial -- as you know, it's just a file which gives names to SHA-1 hashes. There's not guesswork as to how tags flow around in the system: they move along with pushes and pulls. And if there is a tag conflict, well then it's also trivial to solve it: you solve it like any other conflict. After all, it's just a line in a text file. I think the simplicity of this model is a very nice feature.
Martin Geisler
Martin, I'm sorry, but hg tags are confusing: http://pastebin.com/f34398ad8
Dustin
Dustin: Yeah, users are often confused by the fact that you cannot see the the 1.0 tag in `.hgtags` when you've checked out revision 1.0. However, you don't need to look inside `.hgtags` and you you'll find that `hg tags` still lists all tags. Furthermore, this behavior is a simple consequence of storing tags in a version controlled file -- again the model is easy to grasp and very *predictable*.
Martin Geisler
**Martin Geisler** I'd argue that rules for tags in Mercurial, required because it uses version-controled file for transport, with layer on special rules to make tags non-versioned, is anything but easy to grasp.
Jakub Narębski
+129  A: 
Jakub Narębski
What could be added is that hg tries very hard to discourage history rewriting (it can only be done with extensions: mq, histedit, rebase), while git does it out-of-the-box (and it looks like part of the community even encourages it).
tonfa
I'm not sure I get your point about the one version vs. whole history thing. It's an implementation detail: git addresses content with a unique key (sha hash), while hg addresses content with a tuple (filename, sha hash). Then how those revs are stored is a different problem (a packed git repo will store all the revs in a single file, the hg revs can be stored in Google's bigtable or with a scheme similar to git (one file per-rev), etc.)
tonfa
I think "rewriting history" is unnecessarily negative sounding. What *I* encourage in git is people to consider the history they publish. Other people need to consume that history. Nobody (not even you) is interested in all of your "oops, forgot a file" commits. Nor does anyone care about the series of inbound merges you went through while you were tracking an upstream branch while working on a new feature. That kind of stuff makes history (and related tools) much harder to understand and provides no value.
Dustin
I rewrite the history all the time with hg (using mq), I just wanted to point that Matt wanted, while designing hg, to not make it easy to do that. It's somewhat reserved to advanced user (needs an extension, etc.).
tonfa
@Jakub: named branches are something that doesn't exist in git. It's simply a field in the cset description (and that is part of the history, so it is immutable unless you changes hashes, etc.).Something like git branches are bookmarks ("named heads") but they aren't currently remote transferrable (you don't import the remote bookmarks when pulling).http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/ explains it very well.
tonfa
"As far as I know Mercurial doesn't have equivalent of annotated tags (tag objects) from Git, which special case are signed tags (with PGP / GPG)" -- Mercurial comes with an extension for signing changesets: http://mercurial.selenic.com/wiki/GpgExtension
Steve Losh
"Mercurial originally supported only one branch per repository workflow, and it shows."Uh, no. Mercurial didn't support *named* branches originally, but you've always been able to have as many anonymous branches as your heart desires in a single repo.Contrast that with git, which makes anonymous branching a *huge* pain. You pretty much *have* to think of a name for every little branch if you want to get anything done (and avoid having your work garbage collected).
Steve Losh
@tonfa: I'll try to come up with description of diference between "named heads", Mercurial "floating tags" / "bookmarks" and Git "branch tips"; as I said I am Git user, and do not know much about Mercurial.
Jakub Narębski
@Steve Losh: Thanks for mentioning **GpgExtension** for signing changesets (but I guess it is not exact equivalen of signed tags in Git, isn't it?). I am planning to write a bit more about **anonymous heads** in Mercurial (which are required to be able to pull then merge); OTOH I think that named branches are better than unnamed ones. BTW in modern Git you can be on a unnamed branch (called "detached HEAD" in Git). Also in Git you can delete branches after you finished working with them.
Jakub Narębski
@tonfa I was quite a heavy mq user when I used hg a lot. I can see that it was possible, but it's harder to safely use mq than it is to safely use rebase, etc... (since everything is undoable by default).
Dustin
@Steve I don't see why you feel that git requires naming branches, but hg does not. Is that because you can't easily have multiple anonymous heads? To be honest, I don't see a big fuss in putting a name on a branch when I intend to have more than one.
Dustin
**@Dustin**: Some quick testing with git 1.6.1: If I make three commits, then use `git log --all` I see all 3. Great.Now I `git co` the first commit and make a new commit without thinking up a name for a branch. `git log --all` doesn't include this new commit, because no ref points to it. It's a commit, but it's not in the log -- not great.Let's hope I never checkout something else or I'm going to have fun with grep trying to find the hash to get back to it. I'm pretty sure git will GC it as well after a while if I forget to tag it. Definitely not great.
Steve Losh
@Dustin: And no, it's not usually *too* hard to think up a branch name (for long-running branches, it's actually a very good idea). But for branches that will only take a couple of minutes it's probably not necessary, and git's "you will now stop thinking about your code so you can think of a name for this 3-commit branch and you will *like* it because that's the way we do things here" attitude is pretty annoying.
Steve Losh
@Steve Losh: You still have this commit in `git log` (or `git log HEAD`); for some reason `--all` doesn't include HEAD ref. And even if you checkout some other branch, there is always HEAD reflog (for 30 days). Also in Git you can name your branch e.g. 'tmp' or 'feature-a' or 'subsystem-b' (if you don't like using detached HEAD for some reason), and then **delete it** if this doesn't work (if it is there to stay you need to think some name anyway to later refer to it).
Jakub Narębski
**Jakub Narębski** You still have it in `git log` *until* you check out something else, then it's gone unless you wrote down the revision hash or want to find it in `.git/objects` manually.The fact that it never appears in `git log --all` is kind of amusing. I would think `log --all` should always show an equal or greater number of revisions than `log`.And sure, you can name it a throwaway name and delete it later, but that's *still* doing unnecessary work just to please `git`. I don't like using tools that make me work around them, even if it's not a *lot* of work.
Steve Losh
*Sorry about abusing comment system to hold discussion* **@Steve Losh** You seem to have missed mentioning **reflog** : even if you checkout something else, you still have it in "git reflog" output; no need to write down revision hash or creating a branch or a tag. Besides I don't see having to name a branch (name which you can change later, without any sign of old name) is more of the work than e.g. trying to come up with good commit message. As to `git log --all`: it` means all references in `refs/` namespace, and HEAD is outside it - thanks for noticing this.
Jakub Narębski
**@Jakub Narębski** I didn't know about `git reflog`, and yes, it will contain the hash, but you're still going to want to use `git reflog | grep "message"` or something if you want to find a specific commit. To me, reading that output is too much effort compared to `hg heads`. And sure, `branch name effort` <= `commit message effort`, but that doesn't really matter because naming a branch doesn't excuse you from writing a commit message: you need to do *both.* And yes, `git log --all` works how you say, but intuitively it seems wrong that using `--all` can result in *less* output.
Steve Losh
**@Steve Losh:** Actually `git log --all` includes HEAD since git version 1.6.1.3 or later.
Jakub Narębski
Hrmph. Due to SO policy this post was made Community Wiki after sixth edit by the original owner (me). While I can understand this policy, this means that if I want to get reputation, I should not create answer incrementally.
Jakub Narębski
**@Steve Losh** your preference to 'hg heads' is **personal** ; many people would rather have identifiers in order to identify things (i.e. tmp-cleanup-x). However, you could implement a script that creates a 'head-n' branch, and another one (e.g. git heads) that shows those branches if that suits you. That's irrelevant to this discussion.
felipec
**@Dustin:** That's actually what rewriting history is for: Rewriting the "oops" commit so that they are merge with the correct one. It's never about changing something big (except special cases like sensitive files submitted...).
Wernight
+16  A: 

I wrote a blog entry about Mercurial's branching models a while ago, and included comparisons to git's branching model. Maybe you'll find it interesting: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/

Steve Losh
@Steve Losh: I wanted to comment about this blog entry (about unnamed branch aka detached HEAD, and about git-fetch fetching all branches, not one), but I got 500 server error.
Jakub Narębski
**@Jakub Narębski** I bet the problem is the non-ASCII character in your name. I'm pretty sure I ran into the same problem on another site and it turned out that the Python Askimet binding chokes on Unicode. I'll take a look.
Steve Losh
@Steve Losh: Thanks for an info, after "unidecoding" my name I was able to post comment. Very good description of branching in Mercurial (but I still think it is inferior ;-))
Jakub Narębski
+6  A: 

If you need good Windows support, you might prefer Mercurial. TortoiseHg (Windows explorer plugin) manages to offer a simple to use graphical interface to a rather complex tool. As state here, you will also have a Visual Studio plugin. However, last time I tried, the SVN interface didn't work that well on Windows.

If you don't mind the command line interface, I would recommend Git. Not for technical reason but for a strategical one. The adoption rate of git is much higher. Just see how many famous open source projects are switching from cvs/svn to Mercurial and how many are switching to Git. See how many code/project hosting providers you can find with git support compared to Mercurial hosting.

Eric Darchis
There is also TortoiseGit, if you don't like using the command line. (But it requires msysgit to be installed.)
Ben James
Our company ended up choosing git *because* of its great support on Windows - check out [Git Extensions](http://code.google.com/p/gitextensions/).I'm biased because I'm now a contributor, but I wasn't when we started using it.
Jacob Stanley
+9  A: 

Take a look at Git vs. Mercurial: Please Relax blog post by Patrick Thomson, where he writes:
Git is MacGyver, Mercurial is James Bond

Note that this blog post is from August 7, 2008, and both SCM improved much since.

Jakub Narębski