You're right that Mercurial didn't have bookmarks until years after Git had branches. There were various things you could do to get a similar effect (eg having a branch with multiple heads), but none quite as good, and it took the Mercurial team a long time to come around to the idea.
I have to disagree about the index, though. I use Git every day, and i'm still struck by how pointless the index and the idea of staging is.
Ditto rebase. The routine use of rebase still seems completely wrongheaded to me. Mercurial's convention of preferring merges is better, and the last few years' developments around safe evolution of history really show rebase up as the misconceived hack it is.
Mercurial got 'commit --amend' a long time ago, but even before that, it had 'rollback', which undoes the last commit, leaving the working tree untouched (that is, with the state it had in the commit), so you can make your fixes and commit again.
I'd entertain the argument that Git won because it was better if even a handful of the people who now use Git had learned both Git and Mercurial and made an informed choice between them. That simply does not appear to be the case. Git got ahead because Linus invented it, and won because of GitHub.
I use Git every day, and i'm still struck by how pointless the index and the idea of staging is.
I find it amazingly useful. The staging area is for building your commit. I always ever use -p (ie., "add -p", "reset -p" and "checkout -p") and use it to construct the commit out of parts.
The way I work, I split my current work into multiple commits. I may have implemented a feature, fixed a bug I found along the way in the same file, and updated the readme with something unrelated; those are three separate commits. I do "add -p" to pick the fragments, and when I'm happy, I commit. Repeat until repo is clean.
Sometimes, my current work results in a whole bunch of such commits. Sometimes I have to split part of my current work into a separate branch. Again: Stage stuff, stash -k, checkout new branch, commit as a WIP commit, go back, unstash.
Darcs has "record", which is like "add -p" except it also commits at the same time, and back when I was using it, I remember hating the fact that it required that everything had to be recorded in one go. Git's incremental staging area is much more pleasant because you don't get stressed out by the impending commit that is looming over you.
I prefer to use shelving / stashing to do this sort of stuff. This way you don't need to learn two ways to do the same thing and you can be sure that the code version that you commit is the same that you ran your tests on.
In contrast, I never use `git stash`. Never-ever-ever-(ok-rarely). It bit me HARD early on, so I prefer to do it manually, or rebase branches.
One thing I really like about git is that it lets me be mindful of my actions in a way that hg didn't seem to encourage. In return, it gives me what feels like True Power to recover from _any_ mistake. Wrong branch? Accidentally merged (and pushed) my master branch? No problem, they're just bookmarks to commits anyways.
Mercurial, by contrast, felt Rather Convenient, with occasional chasms of despair if you strayed too far from the path. It's possible that my high opinion of Git is mainly from the fact that it forced me to learn more, but it really feels more flexible. I always have the right tool for whatever I need, and I know why and how to use them.
I use Git on a daily basis, but I never understood it.
If I just want to commit a specific part of my changes, I just do it. It's nice to see which files are staged for a commit, but I also see them in the commit msg comments.
They're called "hunks" in git parlance: sections of the file that define a "diff". A diff on a file can be made of multiple hunks.
Very often, my changes to a file are a mix of "fixing a serious bug" and "minor refactoring" and "removing dead code". When the time to commit comes, git makes it trivial to separate all these changes in different commits so that each commit does one thing and one thing only.
I just noticed recently that TortoiseHG lets you do that in the GUI. Definitely is a nice feature. I only just started using Git and did like the ability to cherry pick from a file, but happy to know I can still do that with hg.
Actually Hg record can do this. It lets you 'edit' a hunk using a text editor, before adding it to the list of changes to include in the current commit....
> if even a handful of the people who now use Git had learned both Git and Mercurial and made an informed choice between them. That simply does not appear to be the case. Git got ahead because Linus invented it, and won because of GitHub.
I think you also underestimate the developer community (or may I overestimate them.) Regardless, my anecdotal evidence is that I did try HG and Git, and while I preferred HG when I first started evaluating them, as soon as I found out how to use Git branches, it was all over for HG. At work we currently inherited a project in HG and everyone that has to work on it complains about it. Some know Git, some are .Net or even old school CVS/SVN people (our VCS migration took a bit longer than it should have), but it doesn't matter. HG = hard to use for them, whereas Git make sense after getting over the initial hurdles. I see the same kind of path I took, where at first they are like, oh, Hg isn't bad, and then after using both, choosing Git as their preference.
I used Mercurial for years because I tried early git and didn't like it. Then I tried it again, everything was easier than Mercurial and I wouldn't ever go back.
Hey, if you don't use the index then don't use the index. Use git commit -a. If you wan't something like the index in Mercurial you have to specify which files you want to commit, or which to exclude, which IMHO is a lot more tedious and error prone. Then again I haven't used Hg in a couple of years, could be they have something like the index now.
Rebase is a hack? Rebase copies a series of commits on top of an immutable history at a certain point in time. This allows you to deal with merges a single conflict at a time, instead of dealing with all the conflicts at once with a merge. It also allows you to avoid cluttering your history with useless merge-commits when just syncing with another repo.
Merges have their place. I use them whenever I merge branches, using --no-ff so I can attach a "Fixes issue #77" in the merge commit message. Of course, before I do that, I sync the branch I'm merging into, then rebase on top of that (to have a clean merge). I might also rebase --interactive to clean up the commits of my branch, so that the history is as easy to read as possible.
Comparing rebase to rollback is wrong. Git has rollback (or revert) as well, and it's used for other usecases, like when reverting changes on a public branch (where rebase would fuck it up for everyone).
I'm sorry, but your comments make it sound like you don't really understand Git.
>Rebase allows you to deal with merges a single conflict at a time, instead of dealing with all the conflicts at once with a merge...
Not sure what you mean by 'deal with a single conflict at a time'. To rebase or merge, you will have to resolve all conflicts that merge/rebase produce, right?
Yes, but a rebase re-applies every commit to the new base. So you solve conflicts one commit at a time, instead of solving every conflict in a single merge commit.
It's easier to remember the intended behaviour when the code changes are as small as possible, and when you have a (hopefully) good commit message to look at.
I am not sure it make any difference to the user at all. If you use a merge tool, it will present the conflicts one at a time for merging and re-basing.
If you are concerned about reading history, then a merge can give you more context regarding the commits. With re base, commits will jump between features. For example, You are looking at commit for feature 1, but the next series of commits are for a bug fix in feature 2. Next series of commits belong to minor tweaks in feature 3..
A merge will provide you with a single commit-message, rebasing will provide you a commit-message for every commit, making it easier to remember what the intent of a change was. Sometimes that isn't clear.
Regarding the "rebase, commits will jump between features" part: that really depends on how you do things. On my projects, we use git flow. In such a scheme, every branch you would rebase, belongs to the same feature or bugfix.
>In such a scheme, every branch you would rebase, belongs to the same feature or bugfix..
Not sure if I made that clear. But I was talking about the result of the rebase. Once you rebase, all the commits that were in different branch ends up being back to back, and hence become interleaved...
I don't use hg much these days but you can just pass the file(s) you want to commit to 'hg commit'; no need for staging. Even better, hg (or its shell integration at any rate) has tab completion so it's easy to go though the modified files and pick those you wanted to commit. I kinda miss this now I'm working with git mostly.
I have to disagree about the index, though. I use Git every day, and i'm still struck by how pointless the index and the idea of staging is.
Ditto rebase. The routine use of rebase still seems completely wrongheaded to me. Mercurial's convention of preferring merges is better, and the last few years' developments around safe evolution of history really show rebase up as the misconceived hack it is.
Mercurial got 'commit --amend' a long time ago, but even before that, it had 'rollback', which undoes the last commit, leaving the working tree untouched (that is, with the state it had in the commit), so you can make your fixes and commit again.
I'd entertain the argument that Git won because it was better if even a handful of the people who now use Git had learned both Git and Mercurial and made an informed choice between them. That simply does not appear to be the case. Git got ahead because Linus invented it, and won because of GitHub.