In a way, the Git vs. Mercurial debate feels like vi vs. emacs all over again. Hardcore emacs users never quite understood the appeal of a modal editor; hardcore vi users couldn't quite understand how people lived with an input model that constantly moved their fingers off home row.
Usability preferences can differ greatly by person. Another example is information retrieval in a personal database or help system. Some people prefer going through a search engine; others find a directory-based approach more intuitive (and forcing one approach on the other group does not improve productivity).
Similarly, having a unified set of tools for all kinds of version control problems is not necessarily an unalloyed good for everyone. Dealing with persistent history does not necessarily warrant the same approach as dealing with work-in-progress changes. For some users, it may be easier and better to consolidate both problems, for others, it can be more productive to keep them separate.
The Mercurial designers, for better or worse, have decided to separate persistent history changes from local work-in-progress changes, the latter being done via Mercurial Queues. That has the disadvantage that you need to learn a separate set of tools; it has the advantage that unfinished stuff does not pollute your repository's history and that you can tailor both sets of tools to their respective needs (whether they are in fact properly tailored is a different debate).
I suspect that, similarly, Bzr's one-directory-per-branch approach (inherited from Arch) is an easier mental model for some users to deal with than either git's or Mercurial's DAG-based approach, despite many git and Mercurial users not understanding the appeal.
Incidentally, both examples that you list (git stash and git commit --amend) are easily handled by Mercurial Queues. You don't need several separate extensions. (Obviously, some people do prefer special extensions because they reflect their mental models better or optimize common workflows.)
Incidentally, both examples that you list (git stash and git commit --amend) are easily handled by Mercurial Queues.
No, no, no. Let's get this myth out of the way that Mercurial Queues can somehow be part of a modern revision control system. Mercurial Queues are a simple stack of DUMB patches. The only reason why they are used is that often that is all you really need.
But the moment you need any kind of advanced functionality, such as say, something unimaginable like rebasing a Mercurial Queue against an upstream change that conflicts, you are suddenly dealing with tools that are no more advanced than diff and patch, and most certainly don't support any advanced operation on the patches that they juggle. I heard some modern tools like CVS support an advanced operation they call "merge". I'm still waiting until someone implements a usable version for Mercurial Queues.
So please, the moment you use Mercurial Queues in an argument, you've lost. Mercurial Queues are diff and patch in a fancy packaging, but with all the limitations of those. If your revision control system needs them to have the same functionality as another, you've lost.
The dirty secret is this: Mercurial users use Mercurial Queues because Mercurial got branching wrong. It's as simple as that.
In a way, the Git vs. Mercurial debate feels like vi vs. emacs all over again. Hardcore emacs users never quite understood the appeal of a modal editor; hardcore vi users couldn't quite understand how people lived with an input model that constantly moved their fingers off home row.
Emacs and vi both have their strengths and weaknesses. I've used both over the years sometimes trending to one or the other depending on the circumstances. As I've gotten to know both better, I understand the relative strengths better and know when it makes sense to use either. They're both good tools, and will both keep big user-bases for the foreseeable future.
Can I say the same about Mercurial and Git? That's a resounding NO.
I can accept that some holy wars can't have winners. But we should also be willing to accept that some tools can be just better than others.
I disagree (and we have already had this argument I think ;). Mercurial Queues are different from git branches, not just "worse".
With MQ, and especially with a versioned MQ directory, you have a great workflow for review-ready patches. And review-ready patches are what you are creating, after all, in most large projects: You do some work, you refactor that work N times, then you submit it for review, then you repeat that M times until it passes review and you push it to trunk.
With MQ, you can see the entire history of your set of patches. If you have a queue and you refactor two patches into one, you can go back in history in the versioned MQ dir to see what things were like before that. That is useful, because again, the "product" you are creating is a set of review-ready patches. So versioning the patches makes sense.
I understand that you can use git branches very effectively - I use git myself, not mercurial. However, if you use git to rewrite the history of your branch as part of your development process, AFAIK there is no way to go back in time and instantly see what your branch looked like at time K in the past, because history has been rewritten.
Rewriting history is great - you don't want to submit for review a huge list of patches that include bugfixes as you were working. You want to submit the final patches. But what if you do need to look at the state your work was in the past, before you rewrote history?
Mercurial Queues are different from git branches, not just "worse".
Mercurial Queues are bolted onto Mercurial and you can often see the cracks. Merging is my pet peeve which I've already mentioned. I think it's not controversial to say that it's a pain? I think that, in true Mercurial tradition, there's an extension in development for it now...
So why do we need to deal with this bolt-on and the resulting pain? Because Mercurial branches aren't good enough, or at least can't adequately support the workflow people need. Compare the amount of Mercurial users using mq to the amount of git users using quilt or equivalents.
I don't disagree with the abstract principle of operation of Mercurial Queues. I disagree with Mercurial as it is.
However, if you use git to rewrite the history of your branch as part of your development process, AFAIK there is no way to go back in time and instantly see what your branch looked like at time K in the past, because history has been rewritten.
1) It may be possible to do this with reflog. I don't know for sure because I haven't needed to do this yet. (I think the main problem is that by default reflog purges old history at some point)
2) You can simply create more branches as you go. i.e. replace qcommit by git checkout -b etc. Then push the final ones.
> 1) It may be possible to do this with reflog. I don't know for sure because I haven't needed to do this yet. (I think the main problem is that by default reflog purges old history at some point)
I've done this when I was submitting patches to a large git based project (perl5). The trick is to to the rebase and then re-tag your old branch. That way the old work is there if you need to reference it. Since it has a real live tag, it will not get garbage collected.
I agree that MQ has some pain points. Merging, as you say.
But git branches also have pain points. The only way to save history from before you rewrite history is to save branches, as you mentioned - but doing that manually every time you rewrite history is a pain.
Actually the history is kept by reflog for 90 days by default I believe (and you can change this). This covers the large majority of cases where you have completely screwed up your history rewriting and need to go back to a state you remembered you were in.
90 days, or any other finite amount, isn't a solution for what I want. I don't need a quick undo if I erred, I want to see the development process that went into creating some code that later was committed into trunk (and perhaps much much later turned out to have a bug).
I always see this argument about "I want to see everything that a developer did during the development process."
In reality, 'rewriting history' comes down to things like:
* Creating a commit, then amending the commit message.
* Rebasing all of your current changes on top of a new version of master (basically re-applying all of your commits/patches on top of master).
* Fixing a typo creating a commit, and then squashing that into the original commit.
(Note: That these operations all happen on topic branches prior to being merged into master. Once you merge into master, or just publish for public consumption, then you should not be rewriting history at all.)
From my perspective, the view that git is useless because the ability to rewrite history means that valuable information is being lost is an extreme overreaction by people without much (or any) git experience.
If you want to hold this view, you should have rational examples of workflows where people will lose valuable information just as a matter of course.
This probably comes down to discipline, meaning that when you rewrite history in git you may want to take care that you're keeping the useful bits of it and not just squashing everything down to get fat feature-rich commits. Do you think that the history-rewriting tools in git are too often abused by the average git user such that the use of git in general has the problems you've described?
Not sure if I agree as to what is normal and what is abuse here. If you write some feature in a branch, and have various commits for bugfixes as you go, you might want to merge those little commits away for review as well as for bisection purposes. This seems both normal and desirable to me - no one wants to review a set of 100 patches for a feature if they contain a lot of redundancy. It's useful to do small commits as you work to get a feature stable, but it isn't useful to ask someone to review all those commits, especially if they fix a previous bug introduced by another such small commit.
However, that history can still be very useful: You might hit a variation on those bugs later, and seeing the original unrewritten history can help a lot in refreshing your memory on what you did there (and it can be even more helpful for someone else getting up to speed on the code trying to fix that bug). Losing the history after history rewriting isn't a good thing.
In my experience what is being reviewed by your peers are the feature diffs, not the individual commit diffs. What the actual history looks like is entirely up to you as the coder.
I want to see the development process that went into creating some code that later was committed into trunk (and perhaps much much later turned out to have a bug).
With your MQ workflow, you can only ever do this for your own patches.
I think Steve Losh, who's written a series of insightful posts on the differences between Git and Mercurial, has a great one on Mercurial Queues: http://stevelosh.com/blog/2010/08/a-git-users-guide-to-mercu.... From what I can see, Mercurial Queues look very useful.
But the moment you need any kind of advanced functionality, such as say, something unimaginable like rebasing a Mercurial Queue against an upstream change that conflicts, you are suddenly dealing with tools that are no more advanced than diff and patch
This is incorrect. "hg rebase" is more advanced and smarter than diff and patch. Also, people arguing against Mercurial seem unaware of "hg collapse" which allows rewriting history in a way similar to git.
(However I would probably not use hg rebase on Mercurial queues, which are meant to be managed by mq extension commands.)
I think most of the git vs. mercurial debates are non-productive because proponents of one tool don't know the other tool well enough to argue against it.
This is incorrect...However I would probably not use hg rebase on Mercurial queues, which are meant to be managed by mq extension commands.
You completely contradicted your own claim already.
This is exactly what I'm complaining about: Mercurial Queues are diff and patch. And you need Mercurial Queues for decent Mercurial workflows.
I think most of the git vs. mercurial debates are non-productive because proponents of one tool don't know the other tool well enough to argue against it.
I use Mercurial extensively and on a daily basis, so I think I'm qualified to talk about it. People who claim the complaint is invalid should do Mercurial users a favor and point out a workflow that avoids the issue. I'm still waiting (and manually merging all my patch queues whenever I get a conflict in a topmost patch).
> I think most of the git vs. mercurial debates are non-productive because proponents of one tool don't know the other tool well enough to argue against it.
You hit the nail on the head there. I wouldn't claim at all to know git well, despite having used it in numerous projects. On the other hand I felt like I "knew" Mercurial from the moment I picked it up. I've never written code to work around a problem (as the article suggests), and typically on the few occasions I've had problems I've remedied them by using Mercurial commands I already knew without even needing to look up documentation.
Opinions are clearly divided between two tools that perform the same task in very different ways. You can't please all of the people all of the time, long may both continue. More productive for everyone in my opinion would be ensuring bridge projects like hg-git become first-class citizens of the DVCS world.
The key difference is that, unlike text editors, version control systems have substantial network effects.
The popularity of GitHub has made using Git a bit of a no-brainer, in the literal sense - a lot of Git users never really thought about the decision, they just needed some code from a Git repo and picked up Git along the way. I just don't see where people would be having the same experience with Mercurial. I've picked up several books recently where Git was taught in the first few chapters as a necessary precursor.
It appears to me that Git is the new SVN, the new version control tool that we're just stuck with whether we like it or not. I can think of much worse things.
The key difference is that, unlike text editors, version control systems have substantial network effects.
That's not entirely true, in the sense that popular editors tend to have more extensions, syntax highlighting for more languages, auto-completion, etc... That helps draw in more users.
I just don't see where people would be having the same experience with Mercurial.
Well, there's bitbucket. IIRC some programming language communities have standardized on even more off-mainstream VCS.
But yeah, on the whole Git got an advantage in users somewhere along the way, and that's now self-reinforcing. It helps that there's no competition that's obviously better.
They can do interop at the level DAG level, but higher or lower level abstractions aren't really supported (hg branch information isn't accessible in git, git doesn't have access to mq information, etc).
This article seemed to start off well, but at the end turned into a 'Git is better because tools can edit the DAG storing state. QED'.
It is possible that that is true, but I'd want a stronger backup. Making no negative comments about git at all sets off very strong alarm bells for me.
Is it necessary to find something negative in git if you want to highlight a limitation in mercurial? (That can admittedly be worked around with extensions)
The author makes a point that git's more transparent approach makes certain things easy to implement and consistent. To reiterate his example, stashes are just objects in a place where they won't be found by default, but they still work with everything because there's no magic.
The second example shows that git trusts that the user knows best what to do. If you want to reset a branch to a certain commit, git allows you to do it, and because the data model is not hidden git can simply expose the needed operation (reset branch pointer) as is.
For the most part, git has neat porcelains for most operations nowadays, but the UI is sometimes a bit weird because it started off as nothing more than a set of tools to manipulate a DAG of content on disk. In my view this ended up becoming one of its strong points in comparison to other DVCS.
The title of the post was "The Real Difference Between Git and Mercurial". This implies to me that the article is about one, clear difference, which is the main distinction between the two.
Had the post been called "An advantage of git over mercurial", I would have placed a much lower requirement.
Fair assessment. This is where my bias towards git shows through. I use git and understand what it's capable of and why mercurial does it differently. The opposite isn't true.
If you give me some examples, I can probably roll them into a followup post later on.
The piece may be improved by highlighting the fact that while Mercurial users have to write extensions to work around problems, the flip side is they _can_ write extensions to do things the built-in tools don't do. For example, the Golang project has an extension that integrates with their code review system. With Git you can write shell scripts and tools that wrap git, but that isn't quite the same thing as an extension (though it can frequently accomplish the same purpose).
That said, I really enjoyed the article. As a hardcore git user, I've occasionally skirted the edges of Mercurial (mostly just by poking at Golang) and always been confused at some of the stuff I saw. I knew Mercurial branches were more permanent than Git ones, but I never realized quite how permanent they were.
I don't know hg's extensions, so perhaps I don't know what I'm missing, but I have no complaints about git's extensibility. It allows editing of its entire database and all branches (I've been able to convert SVN repo and re-create all merges, change authorship and dates of commits) and has hook scripts that can intercept and customize important actions in the workflow (I've been able to build non-trivial website deployment automation using git as a base).
I guess the big difference is the level of interaction. A Mercurial extension has access to all the functionality that Mercurial offers: applying patches, creating commits, history walking, etc. But it doesn't really modify the underlying representation of that data (queues store their data in the working copy, for example).
Git doesn't give you access to its functionality but instead gives access to its data model. Stashes are just references, commits are created or destroyed at will, notes are just objects that point at commits and are stored in a different set of references, etc.
Interesting. I've never considered that git doesn't give access -- it's always seemed right there to me, whether I want to tweak it by calling out to a git tool to do it, or doing it myself.
It does, but instead of giving you a library/API access, like Mercurial, it gives you command line access. I feel as though one is a little more black box than the other.
I think the author does say something negative about git, just doesn't say it in a negative way. "When a git user runs into a problem, they look at the tools they have on hand and ask, “how can I combine these ideas to solve my problem?”"
The negative here is that A) git user has to know about all the tools, which takes a long time, and then solving the issue requires quite a bit of thought.
That's one of the problems about git is that as a result of the massive flexibility there doesn't seem to a "standard" way to do things, even basic things. Each org has to develop their own processes which is annoying and difficult for new people in the org.
another negative sentence: "you can just point the branch pointer back at the previous commit with git reset --hard HEAD@{1}"
just? Wtf is HEAD@{1} ?
That might be simple, but as usual, only if you know a lot about git.
As a casual git user this annoys me; Even when doing basic stuff I often have to read a long blog-post about how git works internally. I can't remember having this problem when I was a casual Mercurial user.
A small nit about git stashes: they aren't stored in a special linear branch. Each stash is a little branch off of wherever you were when you created the stash. The only trick is that the stash commits are named something weird so that "git stash list" can find them and list them.
You can check this yourself:
git show stash@{0}
Look where it says "WIP on {branch-name}: {hash}". That {hash} will be one of the hashes in the "Merge" header near the top of the commit.
You are correct. They aren't a linear history. In fact, the key is the @{#} syntax (man git-rev-parse). Each stash commit is a single commit pointed to by a ref/stash reference. Because of the reflog, we can see what ref/stash used to point at, that is @{1}, @{2}, etc.
It's actually (potentially) more than a single commit. If you have a dirty index when you stash then that will also be committed along with your working directory changes. If you use the new(ish) --include-untracked option to stash, a 3rd commit will be added that has the untracked files in it. The main stash commit (that holds your working directory changes) is a fake merge of all the commits, just so there are pointers back to the other 2 commits.
I sometimes wonder that BitKeeper had allowed kernel developers to use it freely, none of git would have happened. Conversely, does anyone know what's going on with BitKeeper these days? Assumedly they can sell their commercial product to some markets but practically I haven't heard of BK once since git was announced. Potentially a big blunder on their part.
imho, as biased as a huge fan of hg can be, and someone who lives in git on a day to day basis, is that git has an actively hostile UI, mercurial has a great one.
all the other technical gizwangs can be debated by propellerheads till the cows come home, but the user experience is quite plainly better in hg.
I think the point that the UI of the default tools is better in Mercurial is entirely uncontroversial.
However, equating that to the user experience is short-sighted. The user experience is also how well the tool works and fills the needs of the user. It think it's very controversial to state hg is better there (this is a polite way to say you're completely wrong).
In git, we solve this problem by sticking a .gitignore file in any directories we want to be part of the repo, but without the contents (cache folders, user-generated data destinations, etc.)
I think the author was referencing hg's numerous extensions. In reality I think both git and hg users turn to Google when they get stuck (same for bzr, svn, cvs, and every other scm).
(I know Mercurial very well. I evaluated 5 or 6 distributed VCS tools and decided to migrate my employer's repository from CVS to Mercurial in 2008: 2GB of history, 150k files, 20k changesets, dozens of developers.)
I don't understand the poster's insistence about wanting to perform an operation similar to git stash in Mercurial "without creating a commit". Creating an ephemeral commit is precisely the perfect solution in Mercurial! Do it, then all regular Mercurial commands (log, diff, etc) will work to manage it. To get rid of the temporary commit later, simply "hg strip" it. It will remove the changeset (and all its children, if any) from the history (a backup will be made in .hg/strip-backup). hg strip is part of the built-in mq extension.
Also, a simple solution to the poster's last complain (re-doing a commit while keeping history of the original commit) is as follow: let's say you are at revision A. You commit B. You realize you screwed up. So you go back to A: hg update A. Then you revert your working directory to the state of B: hg revert --all --no-backup -r B. Then you make the changes you forgot, and commit again: hg commit.
I don't understand the poster's insistence about wanting to perform an operation similar to git stash in Mercurial "without creating a commit".
Having it as a real commit is an issue when you want to pull upstream for example. My solution would be hg qnew stashname, but I already ranted about the limitations of MQ in another thread here.
Why is it an issue when you want to pull upstream? If you do it, the temp commit will live aside from all the csets pulled from upstream. If you want to resume work on it later, then just update to it. If you want to resume work on it while effectively "merging" its changes with recent upstream changes, then simply rebase the temp commit: hg rebase -s tempcommit -d new-head-pulled-from-upstream. (rebase is a built-in extension.) That's the workflow policy I implemented and it works well. It is also easy to keep track of temp commits: running hg incoming/outgoing will show which changesets are present/absent in one repo compared to whatever other repo you use as a reference.
Will this preserve the original B? Is it easy to throw away B' and go back to B? (honest question, I know hg only superficially)
The two hg commands you mentioned are summed up as one with git: git reset --soft HEAD^. Then if you commit B' but ever want to go back to B, you could do git reset --hard HEAD@{2}
Mercurial was my first DVCS so I'm perhaps biased but its API has always fit my brain better. We use Git at my current job but after a few days of trying to get used to it, adding shortcuts to avoid remembering the cryptic switches required to do simple tasks and finally screwing up in some merge conflict, I said the hell with it, installed hg-git and work happily ever after.
The biggest advantage of Git's storage model is imo the reflog- I have irretrievably lost work to Mercurial Queues, and that's virtually impossible in Git.
The MQ versioning repo is separate from the main versioning repo. So I don't see how one follows from the other here. You can perfectly modify history in the main repo and version that editing in the MQ repo. The main repo will look clean because the history editing is versioned in the MQ repo.
I agree with Scott's assessment: it's really not that huge a deal if your using Git or Mercurial; they're very similar--it's using a distributed version control system that's a huge deal. Many many places are still locked into old school, centralized systems that make collaboration much harder than it is using Mercurial or Git.
I think that the real difference between git and mercurial is allowing multiple heads in the same branch. Everything else is just an API difference, but from high level point of view -- they're just trees if commits, that's all.
The real difference is the terminology: mercurial named branches mean something other than git branches (git branches are similar to mercurial bookmarks). Steve Losh's article explains that very well.
No, I know about bookmarks, but still, it's all about multiple heads. In mercurial branches, if you merge someone's work on the same bookmark as you did, you get new anonymous head. That head gets it's bookmark lost, since bookmark can only point to one changeset, that's why this bookmarks mechanism fits mercurial not too good.
While in mercurial native branching, you are allowed to get multiple heads in one branch, which from one point of view is frustrating, but from another is natural (since you really were both working on the same branch at the same time).
In Git they tried to solve this problem by origins system, but now, when I worked with both, I find mercurial branches to be the simplest concept that is easier to explain than git's origins.
The only big problem with mercurial branches is their speed, but I think that it can be solved (algorithms are not so complex to make it fast).
Usability preferences can differ greatly by person. Another example is information retrieval in a personal database or help system. Some people prefer going through a search engine; others find a directory-based approach more intuitive (and forcing one approach on the other group does not improve productivity).
Similarly, having a unified set of tools for all kinds of version control problems is not necessarily an unalloyed good for everyone. Dealing with persistent history does not necessarily warrant the same approach as dealing with work-in-progress changes. For some users, it may be easier and better to consolidate both problems, for others, it can be more productive to keep them separate.
The Mercurial designers, for better or worse, have decided to separate persistent history changes from local work-in-progress changes, the latter being done via Mercurial Queues. That has the disadvantage that you need to learn a separate set of tools; it has the advantage that unfinished stuff does not pollute your repository's history and that you can tailor both sets of tools to their respective needs (whether they are in fact properly tailored is a different debate).
I suspect that, similarly, Bzr's one-directory-per-branch approach (inherited from Arch) is an easier mental model for some users to deal with than either git's or Mercurial's DAG-based approach, despite many git and Mercurial users not understanding the appeal.
Incidentally, both examples that you list (git stash and git commit --amend) are easily handled by Mercurial Queues. You don't need several separate extensions. (Obviously, some people do prefer special extensions because they reflect their mental models better or optimize common workflows.)