I wasn't there to witness this, but I repeat it because it's actually kind of hard to dig up this history. I don't know of a single place that neatly chronicles the whole transition from bitkeeper -> git/mercurial.
I remember using Mercurial very early on in its lifetime, during my first internship at IBM, because Xen used it.
Mercurial also ran on Windows far, far earlier than Git did. A few projects (notably Mozilla) selected Mercurial for that reason, because they had developers on Windows.
Unfortunately, Mercurial took longer to develop some of its infrastructure, such as a repository structure optimized for performance, fast branches without making a separate working directory for each, and history editing capabilities. Today, as far as I know, Mercurial does have all of those things (some through plugins).
> Some git users relied on cogito for another year or so, as simple things like `git-commit` still had to be manually handcrafted out of `git-commit-tree`.
Many people (myself included) also used cogito as a crutch for a while longer, until really internalizing the value of the git index, because cogito defaulted to bypassing the index. I originally saw the index as an obstacle to the commit model I'd gotten used to from subversion. Today, I find it a critical part of git's culture of making small commits with one logical change each.
Ouch, yet another way in which running on Windows can lead to poor technical decisions.
In my own case, I really preferred hg's command congruence to SVN; git's deceptive similarity took a long time to get over.
> I originally saw the index as an obstacle to the commit model I'd gotten used to from subversion. Today, I find it a critical part of git's culture of making small commits with one logical change each.
Same here, on both counts. I'd never go back, now, but it did take time to understand the benefits.
That's quite dismissive of Windows...
I didn't see any indication in the parent comment (or in general, really) that Windows support was the cause of Mercurial's difficulty in implementing those features.
I've never heard from anyone that choosing/using Mercurial was a poor decision. Are you biased?
I liked hg too, but as the passage of time has indicated choosing it for one's project would have been a mistake, as git has effectively won.
Separately, GitHub has won the "place where you share you project code" prize that used to belong to sourceforge.
Edit: to be clear, the kind of "everything" I have in mind is the code review system which now has to support two version control tools. Indeed if we'd used git from the start there might well have been an off-the-shelf code review tool we could have used without putting multiple man years of effort into customisations.
Not that this has changed much, the CLI git has been renamed to "git on windows" but fundamentally you're still installing msys (2) to run git.
That issue is greatly mitigated by the existence of libgit2 though, it builds natively on windows (and just about everything else) so windows git (GUI) clients need not depend on CLI git.
You're installing msys to run git because (I guess) it was considered the git CLI would be useless without a decent shell. Would you see yourself use Git or Mercurial in cmd?
Git itself in Git for Windows, afaik, is not actually an msys program, and uses native win32 APIs.
Are you implying that choosing hg was a poor technical decision?
Or are you just making the general observation that if you include non-technical requirements when choosing a tool (and if we accept that running on a specific set of platforms is not a technical requirement...) then you might not end up with the choice that would have been best if all the requirements were purely technical?
If the former, then you should elaborate. As far as I was able to determine when I evaluated both hg and git is that they are essentially equivalent technically. Git's default interface makes some things visible that hg keeps behind the scenes, but these are all a quick hg extension installation away for those who want them.
Today, yes. Significant work went into getting Mercurial's internals up to parity with Git's, and conversely into getting Git's UI up to parity with Mercurial's.
Don't discount the effect that familiarity with a tool or process can have on your perception of it. The most succinct explanation of this effect that I know comes from the title of a post on the Light Table blog called, "Pain We Forgot".
Coming from a Mozilla-influenced, pre-GitHub-explosion background, I'm one of those people always favored Mercurial but used both out of necessity. Mostly that meant using hg for my own stuff that is most likely never to see the light of day and git for almost everything else. But I also ended up calling it quits on Mercurial and pulled the trigger on git-for-everything last week.
So, having just written (what should be a completely unnecessary) tool to dump out stats about files' line ending conventions, again, I'll say that Git has a long way to go.
(And before you ask, yes the problem manifests itself using the latest version of Git, and there's nothing exotic or wacky to my workflow, nor am I witnessing the effect of interplay with other tools of dubious quality. This is an outright case of Git's tendency to drop the ball and then gesture in the vague direction of a poorly documented non-fix that cuts orthogonally to the problem it's supposed to be solving.)
(Another pre-emptive response: yes I'm aware of both core.autocrlf and "text eol", but those are exactly the sort of sideways-cutting non-fixes that I'm talking about.)
I expect that if a file uses CRLF everywhere, `git merge` will not leave it in a state with mixed line endings after inserting conflict resolution markers that end in LF instead of CRLF.
This shouldn't require a configuration option, but if it does, fine. However, Git doesn't even seem to have this.
What it does have are 'autocrlf' and 'eol' and 'text' options/attributes. For anyone who mentions those, I'm going to ask that you be familiar with not just what those actually control, but also how they're documented in the git man pages and in the book from git-scm.org—the entire premise was a discussion about Git's user-facing parts. By either source, those options control line normalization (i.e., implicit automatic conversion), which is not what I'm talking about. And the documentation for those is sick enough that even if they were the things to look to in order to configure this, then the idea that Git's UI is on par with Mercurial nowadays would still be wrong.
EDIT: To clarify, the desired approach for this is, "Use whatever line endings the file is already using". Git's approach to this is, "Standardize on either LF or CRLF, and at your discretion enable what amounts to some glorified git hooks to ensure that policy is followed, through the use of some obtusely documented configuration options. Make sure to work around any problems with that (e.g., when it's corrupting files that should have never been normalized) by applying another liberal layer."
Not to mention that you can't send CRLF in emails. So how are you going to email patches.
So you can shelve. When you have enabled the extension.
If I'm not mistaken, even CVS handled this better.
This is way, way better than CVS. Some people complain about how this doesn't work in place, like git or shelve, but I prefer I don't have to change anything in my main repo, like regenerate IDE files, dependency caches etc.
In any event, I've always like how this worked.
In a way, actually, that still seems to be the case. The Mercurial community seems to be working hard on making enormous monolithic repositories much more performant and realiable, whereas a lot of Git community seems to prefer to merely respond "YOU'RE USING IT WRONG" to these issues (although I suspect the developers themselves are also working on some of the issues; it's just that I see the community at large as much more visible).
So there's definitely a sense to me that Mercurial is the better VCS because it will quietly support whatever development model you want to use, whereas Git tries to force you to use the One True Model™--and I'm firmly in the camp that development tools should support developers' habits, not force them.
Wow, I can't disagree with that notion more. I've been on many projects that use git and practically every one used git in different ways. I've never felt that git was trying to force a particular workflow on me. Git's greatest strength, to me, has always been its toolbox nature—you can make it do whatever you like (want to comb through your entire repo and change someone's email address, or backdate an entire branch? No problem!).
Considering the number of tools based on the Git data model to do completely unrelated things (I'm thinking about e.g. bup or git-annex). I wouldn't say that's Git imposes you a One True Model. Also, Git doesn't restrict you to an arbitrary number of parents on a commit ;).
BTW,
> The Mercurial community seems to be working hard on making enormous monolithic repositories much more performant and realiable
The irony is that to do so, Mercurial had to bend its data model, adding (backwards incompatible) support for per-directory manifests (which sound a lot like trees in Git, except the part where manifests have history attached to them, where Git only has history attached to commits).
How is this different from mercurial ? I know that the latter doesn't have the index, but is there any practical difference from the point of view of the user ? In Mercurial you can easily commit a subset of the files, or even a part of a file if you use the record extension.
It's now part of core with `hg commit -i`, although it's still experimental.
You can commit a subset of changed files in most version control systems, but it isn't smart because you didn't test that state and it's relatively easy to garble files.
Not having the index is a very practical difference for users, because it means that you do not get any editable "staging" commits, only commits that will be on the permanent record.
I understand the appeal of that, in fact Mercurial acquired similar capabilities during it's evolution, thanks to a number of extensions (for example histedit [1])
The clean solution here is to stash/shelve the changes you don't want, then commit the ones you wanted. This works pretty much the same way in either VCS.
> Not having the index is a very practical difference for users, because it means that you do not get any editable "staging" commits, only commits that will be on the permanent record.
Use hg commit [-i], hg commit --amend [-i], and hg uncommit (with evolve) to modify the most recent commit as needed. Or, frankly, just use hg shelve [-i] to do the reverse as described above.
The Git index doesn't improve upon the situation, since you still can't test the partial commit without stashing the remaining changes first. At which point you could have just done that first.
In any event, the closest equivalent of Git's index in Mercurial is MQ, not hg commit -i and friends. The difference is that in Mercurial it's opt-in rather than opt-out.
I had this hook in Mercurial on OS X:
pre-commit = mdfind -0 -onlyin . "kMDItemContentTypeTree = 'com.apple.package'" | xargs -0 hg addremove
For those not familiar with Mercurial, "hg addremove dir ..." adds any files from the specified directory that are not already in the repository, and removes from the repository any files that were from the repository that have been deleted from the specified directory.
For those not familiar with OS X, that mdfind command is finding directories in or under the current directory that have the kMDItemContentTypeTree list in the metadata includes com.apple.package. These are directories that are logically treated as if they are single files.
Suppose I am keeping a TODO list named "TODO" with my project, and I'm using OmniOutliner to organize it. The TODO list will be in a directory named "TODO.oo3". OmniOutliner will keep an XML file in that directory that has most of my TODO list. If all my TODO list consists of is formatted text, that will be all that is in there, and everything is simple. As far as any DVCS goes, I can just treat that XML file as my entire TODO list. It will be no different than a code file, except that I edit it with OmniOutliner instead of vim or TextMate.
Now suppose I add more than just simple formatted text to my TODO. OmniOutliner allows adding files as attachments. They get copied into the TODO.oo3 tree. It also allows recording audio notes, which get stored as files in TODO.oo3. Deleting an attachment in OmniOutliner will delete the file from TODO.oo3.
So what my Mercurial pre-commit hook is doing is finding any files that have been added or removed in directories like my TODO.oo3, and adds any newly added files and removes any deleted files. Files that have just had contents changed will be taken care of by the normal operation of Mercurial.
With git, I'm not sure how to handle this. There are two main issues.
1. Where to handle this. I think the adding and removing of files from the magic directories need to occur on commands that modify the index. In particular, on "add -u". However, I don't see any hook for this. Git's pre-commit hook is, unsurprisingly, for commits, which is too late.
2. Dealing with fancy things like stashes. In general going over ever git command that affect the index and making sure that magic directories are being handled right.
It would be ugly, but I'm starting to suspect it might require putting a wrapper around the git command itself, which is kind of ugly.
Another possibility is a pre-commit hook that just checks to see if any magic directories have added or removed files, and if so aborts the commit and alerts the user that they need to "git add" or "git rm" those files or add --no-verify if they want to commit anyway. It wouldn't be as clean as it was in Mercurial, but it would at least be an improvement over relying on noticing in the "git status" I almost always do before committing that I've got some add/removes in a magic directory that need to be taken care of first.
README.txt
src/
include/
doc/
TODO.oo3
In the midst of development, I may end up with files in some of these directories that are not supposed to go into the repository. There may be output files from test runs that I'm keeping around temporarily while I debug, notes (that will be incorporated into commit messages which is why the notes files do not belong in the repository), short-lived alternative versions of some of the source or include files, and so on.I don't want to "git add" on the project directory, or any of the subdirectories other than TODO.oo3 because I don't want to pick up those files. For everywhere except TODO.oo3, "git add -u" is what I (think I) want. It's only with TODO.oo3 that I want "git add" instead of (or in addition to) "git add -u".
I mostly use "git add -p" and it misses new files, which doesn't feel right either :\
I've never understood why the index has to be forced on everyone for every commit. Apparently it's due to a belief that everyone always just munges a bunch of changes together in their working copy in a mad coding frenzy and then later realize they need to filter and separate those changes into separate commits? That happens to me from time to time, but it's not the common case. When it does happen (since I use mercurial) I can use use tools such as commit --amend, or commit <list of filenames>, or record or crecord to filter and separate the changes in my working copy into separate commits. I believe even git has some of those same options.
> I've never understood why the index has to be forced on everyone for every commit.
You can generally bypass it if making a simple commit; I use "git commit -a" all the time. But every time you use tools like "git add" on individual files, or "git add -p" on parts of files, you rely on the index.
Understanding the index also helps greatly when you need to do a merge, cherry-pick, or other similar operation; you need a staging area to work in, separate from the work tree.
Actually, with mercurial I don't need a staging area to work in separate from the working copy to perform merge, cherry-pick, or other similar operations. The index appears to be needless complication.
> such as a repository structure optimized for performance
Actually, repository structure hasn't fundamentally changed (unless you count the RevlogNG change in 0.9). There have been changes so that data on disk compresses better (the generaldelta change) and there's more underway to support new features (such as narrow clones), but they generally aren't performance-related.
I note that this is a good thing: Mercurial's repository structure allows it to do things that aren't easy for Git, especially efficient random access to history (Git's structures are generally optimized for access close to HEAD and the root of the directory tree), at the expense of requiring more disk space.
The performance improvements you've seen most likely come from more/better caching or reimplementation of time-critical code.
> fast branches without making a separate working directory for each
That was always possible. Documentation (such as the Mercurial book) suggested a clone-based workflow for reasons of convenience and because that's what people were used to at the time, not because you had to do it this way.