Git與Mercurial - 比較與對比


Answers

我認為你可以通過對這兩個視頻的描述來了解這些系統的相似或不同:

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

它們兩者在設計上非常相似,但在實現方式上非常不同。

我使用Mercurial。 就我理解Git而言,git的一個主要不同之處在於它跟踪文件的內容而不是文件本身。 Linus說如果你將一個函數從一個文件移動到另一個文件,Git會告訴你整個移動過程中單個函數的歷史。

他們還說git比HTTP慢,但它擁有自己的網絡協議和服務器。

作為SVN厚客戶端,Git比Mercurial更好。 你可以拉和推SVN服務器。 該功能在Mercurial中仍在開發中

Mercurial和Git都有非常好的網絡託管解決方案(BitBucket和GitHub),但Google Code只支持Mercurial。 順便說一下,他們對Mercurial和Git進行了非常詳細的比較,他們在決定支持哪一種( http://code.google.com/p/support/wiki/DVCSAnalysis )時做了相應的比較。 它有很多很好的信息。

Question

一段時間以來,我一直在為我的個人項目使用顛覆。

越來越多的我一直聽到有關Git和Mercurial以及DVCS的優秀信息。

我想給整個DVCS一個旋風,但我對兩種選擇都不太熟悉。

Mercurial和Git有什麼區別?

請注意,我並沒有試圖找出哪一個是“最好的”,或者甚至是我應該從哪一個開始。 我主要尋找他們相似的地方和他們不同的地方,因為我有興趣了解他們在實施和哲學方面的差異。




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 (eg 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 .




After reading all over that Mercurial is easier (which I still believe it is, after all the internet community is of the opinion), when I started working with Git and Mercurial I felt Git is relatively simpler for me to adapt to (I started off with Mercurial with TortoiseHg) when working from the command line, mainly because the git commands were named appropriately according to me and are fewer in number. Mercurial has different naming for each command that does a distinct job, while Git commands can be multipurpose according to situation (for eg, checkout ). While Git was harder back then, now the difference is hardly substantial. YMMV.. With a good GUI client like TortoiseHg, true it was much easier to work with Mercurial and I did not have to remember the slightly confusing commands. I'm not going into detail how every command for the same action varied, but here are two comprehensive lists: 1 from Mercurial's own site and 2nd from wikivs .

╔═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════╗
║           Git               ║                Mercurial                                                                       ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
║ git pull                    ║ hg pull -u                                                                                     ║
║ git fetch                   ║ hg pull                                                                                        ║
║ git reset --hard            ║ hg up -C                                                                                       ║
║ git revert <commit>         ║ hg backout <cset>                                                                              ║
║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
║ git add -i                  ║ hg record                                                                                      ║
║ git commit -a               ║ hg commit                                                                                      ║
║ git commit --amend          ║ hg commit --amend                                                                              ║
║ git blame                   ║ hg blame or hg annotate                                                                        ║
║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
║ git bisect                  ║ hg bisect                                                                                      ║
║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
║ git merge                   ║ hg merge                                                                                       ║
║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
║   and git send-mail         ║                                                                                                ║
║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
║ git checkout HEAD           ║ hg update                                                                                      ║
║ git log -n                  ║ hg log --limit n                                                                               ║
║ git push                    ║ hg push                                                                                        ║
╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝

Git saves a record of every version of committed files internally, while Hg saves just the changesets which can have a smaller footprint. Git makes it easier to change the history compared to Hg, but then again its a hate-it-or-love-it feature. I like Hg for former and Git for latter.

What I miss in Hg is the submodule feature of Git. Hg has subrepos but that's not exactly Git submodule.

Ecosystem around the two can also influence one's choice: Git has to be more popular (but that's trivial), Git has GitHub while Mercurial has BitBucket , Mercurial has TortoiseHg for which I haven't seen an equivalent as good for Git.

Each has its advantages and disadvantages, with either of them you're not going to lose.




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.




I've used Git for a little over a year at my present job, and prior to that, used Mercurial for a little over a year at my previous job. I'm going to provide an evaluation from a user's perspective.

First, both are distributed version control systems. Distributed version control systems require a change in mindset from traditional version control systems, but actually work much better in many ways once one understands them. For this reason, I consider both Git and Mercurial much superior to Subversion, Perforce, etc. The difference between distributed version control systems and traditional version control systems is much larger than the difference between Git and Mercurial.

However, there are also significant differences between Git and Mercurial that make each better suited to its own subset of use cases.

Mercurial is simpler to learn. I got to the point where I rarely had to refer to documentation or notes after a few weeks of using Mercurial; I still have to refer to my notes regularly with Git, even after using it for a year. Git is considerably more complicated.

This is partly because Mercurial is just plain cleaner. You rarely have to branch manually in Mercurial; Mercurial will create an anonymous branch automatically for you if and when you need it. Mercurial nomenclature is more intuitive; you don't have to worry about the difference between "fetch" and "pull" as you do with Git. Mercurial is a bit less buggy. There are file name case sensitivity issues that used to cause problems when pushing projects across platforms with both Git and Mercurial; this were fixed in Mercurial some time ago while they hadn't been fixed in Git last I checked. You can tell Mercurial about file renames; with Git, if it doesn't detect the rename automatically - a very hit or miss proposition in my experience - the rename can't be tracked at all.

The other reason for Git's additional complication, however, is that much of it is needed to support additional features and power. Yes, it's more complicated to handle branching in Git - but on the other hand, once you have the branches, it's not too difficult to do things with those branches that are virtually impossible in Mercurial. Rebasing branches is one of these things: you can move your branch so that its base, instead of being the state of the trunk when you branched, is the state of the trunk now; this greatly simplifies version history when there are many people working on the same code base, since each of the pushes to trunk can be made to appear sequential, rather than intertwined. Similarly, it's much easier to collapse multiple commits on your branch into a single commit, which can again help in keeping the version control history clean: ideally, all the work on a feature can appear as a single commit in trunk, replacing all the minor commits and subbranches that the developer may have made while developing the feature.

Ultimately I think the choice between Mercurial and Git should depend on how large your version control projects are, measured in terms of the number of people working on them simultaneously. If you have a group of a dozen or more working on a single monolithic web application, for example, Git's more powerful branch management tools will make it a much better fit for your project. On the other hand, if your team is developing a heterogeneous distributed system, with only one or two developers working on any one component at any one time, using a Mercurial repository for each of the component projects will allow development to proceed more smoothly with less repository management overhead.

Bottom line: if you have a big team developing a single huge application, use Git; if your individual applications are small, with any scale coming from the number rather than the size of such applications, use Mercurial.