Git и Mercurial-сравнение и контраст

некоторое время я использую subversion для своих личных проектов.

все больше и больше я слышу отличные вещи о Git и Mercurial, и DVCS в целом.

Я хотел бы дать всю вещь DVCS вихрь, но я не слишком хорошо знаком с любым вариантом.

Каковы некоторые различия между Mercurial и Git?

обратите внимание, что я не пытаясь выяснить, какой из них "лучший" или даже какой из них я должен начать с. Я в основном ищу ключевые области, где они похожи и где они отличаются, потому что мне интересно знать, как они отличаются с точки зрения реализации и философии.

11 ответов


отказ от ответственности: я использую Git, следую за развитием Git в списке рассылки git и даже немного помогаю Git (в основном gitweb). Я знаю Mercurial из документации и некоторые из обсуждения на # revctrl IRC-канале на FreeNode.

спасибо всем людям на канале # mercurial IRC, которые предоставили помощь о Mercurial для этой записи



резюме

здесь было бы неплохо иметь некоторый синтаксис для таблицы, что-то вроде расширения уценки PHPMarkdown / MultiMarkdown / Maruku

  • репозиторий структуру: Mercurial не позволяет осьминогу сливаться (с более чем двумя родителями), а также помечать объекты, не связанные с фиксацией.
  • Теги: Mercurial использует versioned .hgtags файл со специальными правилами для тегов репозитория, а также поддерживает локальные теги в .hg/localtags; в тегах Git РЭС, проживающего в refs/tags/ пространство имен, и по умолчанию autofollowed на выборки и требует явного нажатия.
  • отрасли: в Mercurial основной рабочий процесс основан на анонимный главы; Git использует легкие именованные ветви и имеет специальный вид ветвей (удаленные ветки), которые следуют за ветвями в удаленном репозитории.
  • имена и диапазоны ревизий: Mercurial обеспечивает пересмотр числа, локальный для репозитория и базирует относительные ревизии (считая от tip, т. е. текущей ветви) и диапазоны ревизий на этом местные нумерация; Git предоставляет способ ссылки на ревизию относительно наконечника ветви, а диапазоны ревизий являются топологическими (на основе графика ревизий)
  • Mercurial использует переименовать отслеживания, в то время как Git использует переименовать обнаружения чтобы иметь дело с переименованиями файлов
  • сеть: Mercurial поддерживает протоколы SSH и HTTP " smart "и статический протокол HTTP; современный Git поддерживает протоколы SSH, HTTP и GIT" smart "и протокол HTTP(S)" dumb". Оба имеют поддержку файлов пакетов для автономного транспорта.
  • Mercurial использует расширения (плагины) и установленный API; Git имеет возможности написания скриптов для и установленных форматов.

есть несколько вещей, которые отличаются Mercurial от Git, но есть и другие вещи, которые делают их похожими. Оба проекта заимствуют идеи друг у друга. Например hg bisect команда в Mercurial (ранее расширение bisect) был вдохновлен git bisect команда в Git, в то время как идея git bundle был вдохновлен hg bundle.

структура репозитория, хранение изменения

в Git есть четыре типа объектов в базе данных объекта: blob объекты, содержащие содержимое файла, иерархические дерево объекты, которые хранят структуру каталогов, включая имена файлов и соответствующие части разрешений файлов (исполняемое разрешение для файлов, являющееся символической ссылкой), фиксация объект, содержащий информацию об авторстве, указатель на снимок состояния репозитория при ревизии, представленный фиксацией (через объект дерева верхнего каталога проекта) и ссылки на ноль или более родительских фиксаций, и tag объекты, которые ссылаются на другие объекты и могут быть подписаны с помощью PGP / ГРО.

git использует два способа хранения объектов: свободный формат, где каждый объект хранится в отдельном файле (эти файлы записываются один раз, и никогда не изменяется), а упакованные формат, в котором многие объекты хранятся Дельта-сжатыми в одном файле. Атомарность операций обеспечивается тем, что ссылка на новый объект записывается (атомарно, с помощью create + rename trick) после написания объекта.

репозитории Git требуют периодическое обслуживание с помощью git gc (для уменьшения дискового пространства и повышения производительности), хотя в настоящее время Git делает это автоматически. (Этот метод обеспечивает лучшее сжатие репозиториев.)

Mercurial (насколько я понимаю) хранит историю файла в filelog (вместе, я думаю, с дополнительными метаданными, такими как отслеживание переименования и некоторая вспомогательная информация); он использует плоскую структуру под названием манифест для хранения структуры каталогов и структуры называется изменений которые хранят информацию о наборах изменений (ревизиях), включая сообщение фиксации и ноль, один или два родителя.

Mercurial использует журнал операций для обеспечения атомарности операций и полагается на усек файлы для очистки после неудачной или прерванной операции. Revlogs добавляются только.

глядя на структуру репозитория в Git по сравнению с Mercurial, можно увидеть, что Git больше похож на объект база данных (или файловая система с адресом содержимого) и Mercurial больше похожи на традиционную реляционную базу данных с фиксированным полем.

отличия:
в ГИТ в дерево объекты образуют иерархические структура; в Mercurial манифест и квартира структура. В Git blob объект магазин одной из версий содержимого файла; в Mercurial filelog магазины вся история одним файлом (если не учитывать здесь каких-либо осложнений с переименованиями). Это означает, что существуют различные области операций, где Git будет быстрее, чем Mercurial, все остальные вещи считаются равными (например, слияния или отображение истории проекта), и области, где Mercurial будет быстрее, чем Git (например, применение патчей или отображение истории одного файла). эта проблема может быть не важна для конечного пользователя.

из-за фиксированной структуры Меркуриал в изменений структура, коммиты в Mercurial могут иметь только до двух родителей; коммиты в Git могут иметь более двух родителей (так называемое "слияние осьминогов"). Хотя вы можете (теоретически) заменить слияние осьминогов серией двух родительских слияний, это может вызвать осложнения при преобразовании между репозиториями Mercurial и Git.

насколько я знаю, Mercurial не имеет эквивалент аннотированный теги (объекты тегов) из Git. Особый случай аннотированных тегов -подписали теги (с подписью PGP / GPG); эквивалент в Mercurial можно сделать используя GpgExtension, расширение которого распространяется вместе с Mercurial. Ты не можешь!--59-->объект non-commit тега в Mercurial, как вы можете в Git, но это не очень важно, я думаю (некоторые репозитории git используют помеченный blob для распространения открытого ключа PGP используется для проверки подписанных тегов).

ссылки: ветви и теги

в ссылках Git (ветви, ветви удаленного отслеживания и теги) находятся вне DAG коммитов (как и должно быть). Ссылки в refs/heads/ пространство имен (местные отделения) указывают на коммиты и обычно обновляются "git commit"; они указывают на кончик (головку) ветви, поэтому такое имя. Ссылки в refs/remotes/<remotename>/ пространство имен (удаленные ветки) точка фиксации, следуйте ветвям в удаленном репозитории <remotename>, и обновляются с помощью "git fetch" или эквивалента. Ссылки в refs/tags/ пространство имен (теги) обычно указывают на коммиты (легкие теги) или объекты тегов (аннотированные и подписанные теги) и не предназначены для изменения.

Теги

в Mercurial вы можете дать постоянное имя ревизии, используя tag; теги хранятся аналогично шаблонам игнорирования. Это означает, что глобально видимые теги хранятся в ревизия-контролируется .hgtags файл в вашем репозитории. Это имеет два последствия: во-первых, Mercurial должен использовать специальные правила для этого файла, чтобы получить текущий список всех тегов и обновить такой файл (например, он читает самую последнюю исправленную версию файла, в настоящее время не проверенную версию); во-вторых, вы должны зафиксировать изменения в этом файле, чтобы новый тег был виден другим пользователям / другим репозиториям (насколько я понимаю).

Mercurial также поддерживает местные теги, хранящиеся в hg/localtags, которые не видны другим (и конечно не передаваемы)

в тегах Git фиксируются (постоянные) именованные ссылки на другие объекты (обычно объекты тегов, которые в свою очередь указывают на коммиты), хранящиеся в refs/tags/ пространство имен. По умолчанию при извлечении или перемещении набора ревизий git автоматически извлекает или перемещает теги, указывающие на извлекаемые или перемещаемые ревизии. Тем не менее вы можете управления в какой-то степени какие теги извлекаются или толкнул.

Git обрабатывает легкие теги (указывая непосредственно на коммиты) и аннотированные теги (указывая на объекты тегов, которые содержат сообщение тега, которое необязательно включает подпись PGP, которая в свою очередь указывает на фиксацию) немного по-разному, например, по умолчанию он рассматривает только аннотированные теги при описании коммитов с помощью "Git describe".

Git не имеет строгого эквивалента локальных тегов в Mercurial. Тем не менее git рекомендуется настроить отдельный открытый репозиторий, в который вы помещаете готовые изменения и из которого другие клонируют и извлекают. Это означает, что теги (и ветви), которые вы не нажимаете, являются частными для вашего репозитория. С другой стороны, вы также можете использовать пространство имен, отличное от heads, remotes или tags, например local-tags местные теги.

личное мнение: на мой взгляд, теги должны находиться вне графика ревизии, поскольку они внешние по отношению к нему (они являются указателями на график ревизий). Теги должны быть не версионными, но переносимыми. Выбор Mercurial использования механизма, подобного тому, который игнорирует файлы, означает, что он либо должен лечить .hgtags специально (файл в дереве можно передавать, но обычный он версионный), или имеют теги, которые являются локальными только (.hg/localtags не является версионным,но непередаваемым).

отделения

В Git местного отделения (филиал совет, или руководителя филиала) - это именованная ссылка на коммит, где можно выращивать новые коммиты. Ветвь также может означать активную линию развития, т. е. все коммиты, доступные из кончика ветви. Местные филиалы находятся в refs/heads/ пространство имен, поэтому, например, полное имя ветви "master" - "refs/heads/master".

текущая ветвь в Git (что означает проверенную ветвь и ветвь, куда пойдет новая фиксация) - это ветвь, на которую ссылается HEAD ref. Можно иметь голову, указывающую прямо на commit, а не символическая ссылка; эта ситуация нахождения на анонимной неназванной ветви называется отрезанная голова ("git branch" показывает, что вы находитесь на '(нет ветви)').

в Mercurial есть анонимные ветви (головки ветвей), и можно использовать закладки (через расширение закладок). Такие филиалы закладки являются чисто локальными, и эти имена (до версии 1.6) не могут быть переданы с использованием Mercurial. Вы можете использовать rsync или scp для копирования .hg/bookmarks файл в удаленный репозиторий. Вы также можете использовать hg id -r <bookmark> <url> чтобы получить идентификатор редакции текущей подсказки закладки.

поскольку закладки 1.6 могут быть нажаты / вытащены. The BookmarksExtension страница имеет раздел Работа С Удаленными Репозиториями. Есть разница в том, что в Mercurial имена закладок являются глобальные, в то время как определение "удаленного" в Git описывает также отображение ветви имена от имен в удаленном репозитории до имен локальных ветвей удаленного отслеживания; например refs/heads/*:refs/remotes/origin/* отображение означает, что можно найти состояние ветви "master" ("refs/heads/master") в удаленном репозитории в ветви удаленного отслеживания "origin/master" ("refs/remotes/origin/master").

Mercurial также называется имени отделения, где название филиала встроенный в фиксации (в наборе). Такое название-global (переведен на выборку). Эти имена ветвей постоянно записываются как часть метаданных changeset\u2019s. С помощью modern Mercurial вы можете закрыть "именованную ветку" и остановить запись имени ветки. В этом механизме кончики ветвей рассчитываются на лету.

"названные ветви" Меркуриала, на мой взгляд, следует называть совершить метками вместо этого, потому что это то, что они есть. Существуют ситуации, когда "именованная ветвь" может иметь несколько советов (несколько бездетных коммитов), а также может состоять из нескольких непересекающихся частей графика ревизий.

в Git нет эквивалента этих ртутных "встроенных ветвей"; более того, философия Git заключается в том, что, хотя можно сказать, что ветвь включает некоторую фиксацию, это не означает, что фиксация принадлежит какой-то ветви.

обратите внимание, что Mercurial documentation по-прежнему предлагает использовать отдельные клоны (отдельные репозитории), по крайней мере, для долгоживущих ветвей (одна ветвь на рабочий процесс репозитория), он же ветвление путем клонирования.

ветви в толчке

Mercurial по умолчанию толкает все главы. Если вы хотите нажать одну ветку (одиночная головка), вы должны указать ревизию подсказки ветви, которую вы хотите нажать. Вы можете указать наконечник ветви по номеру редакции (локальный для репозитория), идентификатору редакции, имени закладки (локальный для репозитория, не передается) или по встроенному наименование филиала (название филиала).

насколько я понимаю, если вы нажмете ряд ревизий, содержащих коммиты, помеченные как находящиеся на некоторой "именованной ветви" на языке Mercurial, у вас будет эта "именованная ветвь" в репозитории, к которому вы нажимаете. Это означает, что имена таких встроенных ветвей ("именованные ветви") являются глобальные (в отношении клонов данного репозитория / проекта).

по умолчанию (при push.default переменная конфигурации) "нажим git" или - ГИТ, толкай!--295-->пульт ДУ> " Git будет толкать соответствующие ветки, т. е. только те локальные ветви, эквивалент которых уже присутствует в удаленном репозитории, в который вы нажимаете. Вы можете использовать --all возможность git-push ("git push --all"), чтобы нажать все филиалы, вы можете использовать " git push пульт ДУ> филиала>" нажать один филиал, и вы можете использовать " git push пульт ДУ > Глава " к толкай!--59-->текущая филиала.

все вышеизложенное предполагает, что Git не настроен, какие ветви нажимать через remote.<remotename>.push переменные конфигурации.

ветви в выборке

Примечание: здесь я использую терминологию Git, где "fetch" означает загрузку изменений из удаленного репозитория без интеграция этих изменений с местной работы. Вот что "git fetch" и "hg pull" делает.

если я правильно понимаю, по умолчанию Mercurial fetches все главы из удаленного репозитория, но вы можете указать ветку для извлечения через"hg pull --rev <rev> <url>" или "hg pull <url>#<rev>" для получения один филиал. Вы можете указать с помощью идентификатора ревизии, имени "именованной ветви" (ветви, встроенной в журнал изменений) или имени закладки. Однако имя закладки (по крайней мере в настоящее время) не передавалось. Все" именованные ветви", которые вы получаете, принадлежат get переданный. "HG pull" хранит кончики ветвей, которые он получил как анонимные, безымянные головы.

в Git по умолчанию (для "origin" remote, созданного "git clone", и для пультов, созданных с помощью" git remote add")"git fetch" (или "git fetch <remote>") становится все филиалы из удаленного репозитория (с refs/heads/ namespace), и сохраняет их в refs/remotes/ пространство имен. Это означает, например, что ветка с именем "master" (полное имя: "refs/heads/master") в удаленном "origin" будет храниться (сохранено) как "origin/master"пульт дистанционного отслеживания ветви (полное название: 'refs / remotes / origin / master').

можно найти один филиал в Git с помощью git fetch <remote> <branch> - Git будет хранить запрошенную ветку (ы) в FETCH_HEAD, что-то похожее на Mercurial безымянные головы.

это только примеры случаев по умолчанию мощных refspec синтаксис Git: с помощью refspecs вы можете указать и / или настроить, какие ветви нужно принеси и где их хранить. Например, по умолчанию "fetch all branches" case представлен "+refs/heads/*:refs/remotes/origin/*" подстановочный знак refspec, а "fetch single branch" - сокращение от " refs/heads/:". Refspecs используются для сопоставления имен ветвей (refs) в удаленном репозитории с локальными именами refs. Но вам не нужно знать (много) о refspecs, чтобы эффективно работать с Git (в основном благодаря команде "git remote").

личные мнение: я лично думаю, что " именованные ветви "(с именами ветвей, встроенными в метаданные набора изменений) в Mercurial являются ошибочным дизайном с его глобальным пространством имен, особенно для распределенные система контроля версий. Например, возьмем случай, когда и Алиса, и Боб имеют "именованную ветвь" с именем "for-joe" в своих репозиториях, ветви, которые не имеют ничего общего. Однако в хранилище Джо эти две ветви будут рассматриваться как одна ветвь. Так у вас есть как-то придумали конвенцию, защищающую от столкновения названий филиалов. Это не проблема с Git, где в репозитории Джо "для-Джо" ветвь от Алисы будет "Алиса/для-Джо", а от Боба это будет "боб/для-Джо". См. также отделение имени ветви от идентификатора ветви вопрос поднят на Mercurial wiki.

Mercurial "закладки ветви" в настоящее время не хватает в ядре распределения механизм.

отличия:
Эта область является одним из основных различий между Mercurial и Git, как Джеймс woodyatt и Стив Лошь сказано в их ответах. Mercurial по умолчанию использует анонимные облегченные кодовые линии, которые в своей терминологии называются "heads". Git использует легкие именованные ветви с инъективным отображением для сопоставления имен ветвей в удаленном репозитории с именами ветвей удаленного отслеживания. Мерзавец "заставляет" вас называть ветви (ну, за исключением одной неназванной ветви, ситуация называется отделенной головкой), но я думаю, что это лучше работает с тяжелыми рабочими процессами ветвей, такими как рабочий процесс ветви темы, что означает несколько ветвей в парадигме единого репозитория.

изменения наименования

в Git есть много способов именования ревизий (описанных, например, в git rev-parse manpage):

  • полное имя объекта SHA1 (40-байтовое шестнадцатеричное string) или подстрока такой, которая уникальна в репозитории
  • символическое имя ref, например "master" (относится к ветви "master") или " v1.5.0' (относится к тегу) или "origin/next" (относится к ветви удаленного отслеживания)
  • суффикс ^ to revision параметр означает первый родитель объекта commit,^n означает n-й родитель фиксации слияния. Суффикс ~n to revision параметр означает n-й предок фиксации в прямой первой родительской строке. Эти суффиксы могут быть объединены, чтобы сформировать спецификатор ревизии, следующий по пути из символической ссылки, например "pu~3^2~3"
  • вывод "git describe", т. е. ближайшего тега, необязательно с тире и рядом коммитов, а затем тире, " g "и сокращенное имя объекта, например" v1.6.5.1-75-g5bf8097'.

есть также спецификаторы ревизий с участием reflog, не упомянутые здесь. В Git каждый объект, будь то commit, tag, tree или blob имеет свой Идентификатор SHA-1; существует специальный синтаксис, например, "next: Documentation" или "next: README" для ссылки на дерево (каталог) или blob (содержимое файла) в указанной редакции.

Mercurial также имеет много способов именования наборов изменений (описано, например, в hg manpage):

  • простое целое число рассматривается как номер редакции. Нужно помнить, что номера ревизий являются локальный для данного репозитория; в другом репозитории они могут быть отличающийся.
  • отрицательные целые числа рассматриваются как последовательные смещения от наконечника, с -1 обозначающим наконечник, -2 обозначающим ревизию до наконечника и т. д. Они тоже местные в репозиторий.
  • уникальный идентификатор редакции (40-значная шестнадцатеричная строка) или его уникальный префикс.
  • имя тега (символическое имя, связанное с данной редакцией) или имя закладки (с расширением: символическое имя, связанное с данной головкой, локальное репозиторий) или "именованная ветвь" (метка фиксации; ревизия, заданная "именованной ветвью", - это подсказка (бездетная фиксация) всех фиксаций с данной меткой фиксации, с наибольшим номером ревизии, если таких подсказок больше одного)
  • зарезервированное имя "tip" - это специальный тег, который всегда идентифицирует самую последнюю версию.
  • зарезервированное имя "null"указывает на нулевую ревизию.
  • зарезервированное имя "."указывает рабочий каталог родитель.

различия
Как вы можете видеть, сравнивая выше списки Mercurial предлагает номера версий, локальные для репозитория, в то время как Git нет. С другой стороны, Mercurial предлагает относительные смещения только от " tip " (текущей ветви), которые являются локальными для репозитория (по крайней мере, без ParentrevspecExtension), в то время как Git позволяет указать любую фиксацию, следующую из любого наконечника.

самая последняя редакция называется HEAD в Git, и "наконечник" в Mercurial; в Git нет нулевой ревизии. Как Mercurial, так и Git могут иметь много корней (может иметь более одного родительского коммита; это обычно результат объединения ранее отдельных проектов).

Читайте также: много различных видов спецификаторов ревизии статья в блоге Элайджи (ньюрена).

личное мнение: думаю, что номер версии переоценивают (по крайней мере для распределенная разработка и / или нелинейная / ветвистая история). Во-первых, для распределенной системы контроля версий они должны быть либо локальными для репозитория, либо требовать особого отношения к некоторому репозиторию как к центральному органу нумерации. Во-вторых, более крупные проекты с более длинной историей могут иметь количество ревизий в диапазоне 5 цифр, поэтому они предлагают лишь небольшое преимущество перед сокращенными до 6-7 идентификаторами ревизий символов и подразумевают строгий порядок, в то время как ревизии только частично упорядочены (Я имею в виду, что ревизии n и n+1 не должны быть родительскими и дочерними).

пересмотр квот

в диапазонах ревизий Git являются топологическая. Обычно видели A..B синтаксис, который для линейной истории означает диапазон ревизий, начинающийся с A (но исключая A) и заканчивающийся на B (т. е. диапазон открыть снизу), является сокращением ("синтаксический сахар") для ^A B, что для команд обхода истории означает все коммиты, доступные из B, исключая те, которые достижимы из A. Это означает, что поведение A..B диапазон полностью предсказуем (и весьма полезен), даже если A не является предком B:A..B означает диапазон изменений от общего предка A и B (слияние базы) до версии B.

в Mercurial диапазоны пересмотра основаны на диапазоне номер версии. Диапазон задается с помощью A:B синтаксис, и вопреки диапазону Git действует как закрытые интервал. Также диапазон B:A является ли диапазон A:B в обратном порядке, чего нет в Git (но см. ниже примечание по A...B синтаксис). Но такая простота имеет свою цену: пересмотр Серии А:Б имеет смысл только если a-предок B или наоборот, т. е. с линейной истории; в противном случае (думаю, что) диапазон непредсказуем, и результат локального репозитория (из-за пересмотра числа местных в репозиторий).

это исправлено с Mercurial 1.6, который имеет новый топологическая пересмотра диапазон, где А..B '(или "A::B") понимается как набор наборов изменений, которые являются как потомками X, так и предками Y. Это, я думаю, эквивалентно " -- ancestry-path A..B ' in Git.

Git также имеет обозначения A...B для симметричной разности ревизий; это означает A B --not $(git merge-base A B), что означает, что все коммиты достижимы из A или B, но исключая все коммиты, достижимые из обоих (достижимые из общего предки.)

переименовать

Mercurial использует переименовать отслеживания чтобы иметь дело с переименованиями файлов. Это означает, что информация о том, что файл был переименован, сохраняется во время фиксации; в Mercurial эта информация сохраняется в форме "enhanced diff" в filelog (файл revlog) метаданные. Следствием этого является то, что вы должны использовать hg rename / hg mv... или вы должны помнить, чтобы запустить hg addremove сделать на основе схожести переименовать обнаружение.

Git уникален среди систем управления версиями в том, что он использует переименовать обнаружения чтобы иметь дело с переименованиями файлов. Это означает, что тот факт, что файл был переименован, обнаруживается в то время, когда это необходимо: при слиянии или при отображении diff (при запросе / настройке). Это имеет то преимущество, что алгоритм обнаружения переименования может быть улучшен и не заморожен во время фиксации.

как Git, так и Mercurial требуют использования для следуйте renames при отображении истории одного файла. Оба могут следовать переименованиям при отображении линейной истории файла в git blame / hg annotate.

в ГИТ в git blame команда может следить за движением кода, также перемещая (или копируя) код из одного файла в другой, даже если движение кода не является частью переименования файла. насколько я знаю, эта функция уникальна для Git (на момент написания, октябрь 2009).

сеть протоколы

как Mercurial, так и Git поддерживают извлечение и нажатие на репозитории в одной файловой системе, где URL-адрес репозитория-это просто путь файловой системы к репозиторию. Оба также имеют поддержку для извлечения из bundle files.

Mercurial поддержка извлечения и нажатия через SSH и через HTTP-протоколы. Для SSH требуется доступная учетная запись оболочки на конечном компьютере и копия HG, установленная / доступная. Для доступа HTTP hg-serve или Mercurial cgi script требуется, и Mercurial должен быть установлен на серверной машине.

Git поддерживает два типа протоколов, используемых для доступа к удаленному репозиторию:

  • "умные" протоколы, которые включают доступ через SSH и через пользовательский протокол git:// (по git-daemon), требуется установить git на сервере. Обмен в этих протоколах состоит из клиентских и серверных переговоров о том, какие объекты у них общие, а затем генерирует и отправляет packfile. Современный Git включает поддержку "умного" протокола HTTP.
  • "тупой" протоколы, которые включают HTTP и FTP (только для извлечения) и HTTPS (для нажатия через WebDAV), не требуют git, установленного на сервере, но они требуют, чтобы репозиторий содержал дополнительную информацию, генерируемую git update-server-info (обычно бегут с крючка). Обмен состоит из клиента, идущего по цепочке фиксации и загружающего свободные объекты и packfiles как необходимый. Недостатком является то, что он загружает больше, чем строго требуется (например, в угловом случае, когда есть только один packfile, он будет загружаться целиком, даже при извлечении только нескольких ревизий), и что для завершения может потребоваться много соединений.

расширения: возможности написания скриптов для Против расширений (плагинов)

Mercurial реализован в Python, С некоторым основным кодом, написанным на C для производительности. Он предоставляет API для записи расширения (плагины) как способ добавления дополнительных функций. Некоторые функции, такие как "ветви закладок" или изменения подписи, предоставляются в расширениях, распространяемых с Mercurial, и требуют включения.

Git реализован в C, Perl и shell скрипты. Git предоставляет множество команд низкого уровня (сантехники) подходит для использования в скриптах. Обычный способ введения новой функции-написать это как Perl или shell script, и когда пользовательский интерфейс стабилизируется, перепишите его в C для производительности, переносимости и в случае сценария оболочки, избегая угловых случаев (эта процедура называется builtinification).

Git полагается и строится вокруг форматов [репозитория] и [сетевых] протоколов. Вместо языковых Привязок есть (частичные или полные) reimplementations Git на других языках (некоторые из них являются частично переосмыслениями и частично обертки вокруг команд git): Jgit (Java, используемый Egit, Eclipse Git Plugin), Grit (Ruby), Dulwich (Python), git# (C#).


TL; DR


Я думаю, вы можете получить представление о том, что эти системы похожи или отличаются в whatching эти два видео:

Линус Торвальдс на Git (http://www.youtube.com/watch?v=4XpnKHJAok8)
Брайан О'Салливан на Mercurial (http://www.youtube.com/watch?v=JExtkqzEoHY)

оба они очень похожи по дизайну, но очень разные по реализации.

Я использую Mercurial. Насколько я понимаю Git, одна важная вещь git отличается тем, что он отслеживает содержимое файлов вместо самих файлов. Лайнус говорит, что если вы перемещаете функцию из одного файла в другой, Git расскажет вам историю этой единственной функции через перемещение.

Они также говорят, что git медленнее по HTTP, но у него есть собственный сетевой протокол и сервер.

Git работает лучше как толстый клиент SVN, чем Mercurial. Вы можете тянуть и толкать против сервера SVN. Эта функциональность все еще разрабатывается в Mercurial

оба Mercurial и Git имеют очень хорошие решения для веб-хостинга (BitBucket и GitHub), но код Google поддерживает только Mercurial. Кстати, у них есть очень подробное сравнение Mercurial и Git, которое они сделали для решения, какой из них поддержать (http://code.google.com/p/support/wiki/DVCSAnalysis). У него много хорошей информации.


Я написал запись в блоге о моделях ветвления Mercurial некоторое время назад и включил сравнения с моделью ветвления git. Может быть, вам будет интересно:http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/


Я использую оба довольно регулярно. Основное функциональное различие заключается в том, как Git и Mercurial ветви имен в репозиториях. С Mercurial имена ветвей клонируются и вытягиваются вместе с их наборами изменений. Когда вы добавляете изменения в новую ветвь в Mercurial и нажимаете на другой репозиторий, имя ветви одновременно нажимается. Таким образом, имена ветвей более или менее глобальны в Mercurial, и вы должны использовать расширение закладки, чтобы иметь только локальные облегченные имена (если вы хотите them; Mercurial, по умолчанию, использует анонимные облегченные кодовые линии, которые в своей терминологии называются "головами"). В Git имена ветвей и их инъективное сопоставление с удаленными ветвями хранятся локально, и вы должны управлять ими явно, что означает, что вы знаете, как это сделать. Это в значительной степени, где Git получает свою репутацию труднее учиться и использовать, чем Mercurial.

как другие заметят здесь, есть много и много незначительных различий. Вещь с веток большой дифференциатор.


посмотри Git против Mercurial: пожалуйста, расслабьтесь сообщение в блоге Патрика Томсона, где он пишет:
Git-это MacGyver, Mercurial-это Джеймс Бонд

обратите внимание, что это сообщение в блоге от 7 августа 2008 года, и оба SCM значительно улучшились с тех пор.


Mercurial почти полностью написан на python. Ядро Git написано на C (и должно быть быстрее, чем Mercurial), а инструменты написаны на sh, perl, tcl и используют стандартные утилиты GNU. Таким образом, он должен принести все эти utils и интерпретаторы с ним в систему, которая их не содержит (например, Windows).

обе поддержки работают с SVN, хотя поддержка AFAIK svn сломана для git на Windows (может быть, мне просто не повезло/хромой, кто знает). Есть также расширения, которые позволяют взаимодействие между git и Mercurial.

Mercurial имеет хороший интеграция с Visual Studio. Последний раз, когда я проверял,плагин для Git работает, но очень медленно.

они базовые наборы команд очень похожи(init, clone, add, status, commit, push, pull и т. д.). Таким образом, основной рабочий процесс будет таким же. Кроме того, есть TortoiseSVN-подобный клиент для обоих.

расширения для Mercurial могут быть написаны на python (неудивительно!) и для ЖКТ они может быть написано в любой исполняемой форме (исполняемый файл, скрипт и т. д.). Некоторые расширения сумасшедшие мощные, как git bisect.


Если вам нужна хорошая поддержка Windows, вы можете предпочесть Mercurial. TortoiseHg (Windows explorer plugin) удается предложить простой в использовании графический интерфейс для довольно сложного инструмента. Как государство здесь, у вас также будет плагин Visual Studio. Однако в последний раз, когда я пытался, интерфейс SVN не работал так хорошо в Windows.

Если вы не возражаете против интерфейса командной строки, Я бы рекомендовал Git. Не по техническим причинам, а по стратегическим. Коэффициент принятия git много выше. Просто посмотрите, сколько известных проектов с открытым исходным кодом переключаются с cvs/svn на Mercurial и сколько переключаются на Git. Посмотрите, сколько хостинг-провайдеров кода / проекта вы можете найти с поддержкой git по сравнению с Mercurial hosting.


после прочтения всего этого Mercurial легче (что я все еще считаю, что это, в конце концов, интернет-сообщество придерживается мнения), когда я начал работать с Git и Mercurial, я почувствовал, что Git относительно проще для меня адаптироваться (я начал с Mercurial с TortoiseHg) при работе из командной строки, главным образом потому, что команды git были названы соответствующим образом в соответствии со мной и меньше по количеству. Mercurial имеет разные имена для каждой команды, которая выполняет отдельная работа, в то время как команды Git могут быть многоцелевыми в зависимости от ситуации (например,checkout). В то время как Git был сложнее тогда, теперь разница едва ли существенна. YMMV.. С хорошим клиентом GUI, таким как TortoiseHg, правда, было намного проще работать с Mercurial, и мне не нужно было запоминать слегка запутанные команды. Я не буду вдаваться в подробности, как каждая команда для одного и того же действия менялась, но вот два полных списка: 1 с собственного сайта Mercurial и 2-й из 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 сохраняет запись каждой версии зафиксированных файлов внутри, в то время как Hg сохраняет только наборы изменений, которые могут иметь меньший размер. Git облегчает изменение истории по сравнению с Hg, но опять же это функция ненависти или любви. Мне нравится Hg для первого и Git для последнего.

то, что я пропускаю в Hg, - это функция подмодуля Git. Hg имеет subrepos, но это не совсем подмодуль Git.

экосистема вокруг двух может также повлиять на выбор: Git должен быть более популярным (но это тривиально), Git имеет GitHub в то время как Mercurial имеет BitBucket, Mercurial имеет TortoiseHg, для которого я не видел эквивалента, как хорошо для Git.

каждый имеет свои преимущества и недостатки, с ними вы не проиграете.


проверить сообщение Скотта Чакона некоторое время назад.

Я думаю, что git имеет репутацию "более сложной", хотя по моему опыту это не сложнее, чем должно быть. ИМО, модель git путь легче понять (теги содержат коммиты (и указатели на ноль или более родительских коммитов) содержат деревья, содержащие капли и другие деревья... сделанный.)

Это не только мой опыт, что git не более запутанным, чем деятельный. Я бы рекомендовал еще раз прочитать это сообщение в блоге от Скотта Чакона по этому вопросу.


Я использовал Git чуть более года на моей нынешней работе, а до этого использовал Mercurial чуть более года на моей предыдущей работе. Я хочу дать оценку с точки зрения пользователя.

во-первых, оба являются распределенными системами контроля версий. Распределенные системы управления версиями требуют изменения менталитета от традиционных систем управления версиями, но на самом деле работают намного лучше во многих отношениях, как только их понимают. По этой причине, я считаю, Git и Mercurial намного превосходит Subversion, Perforce и т. д. Разница между распределенными системами управления версиями и традиционными системами управления версиями намного больше, чем разница между Git и Mercurial.

однако существуют также значительные различия между Git и Mercurial, которые делают каждый лучше подходит для своего подмножества вариантов использования.

Mercurial проще в освоении. Я дошел до того, что мне редко приходилось ссылаться на документацию или заметки после несколько недель использования Mercurial; я все еще должен регулярно ссылаться на свои заметки с Git, даже после использования его в течение года. Git значительно сложнее.

Это отчасти потому, что Mercurial просто чище. Вам редко приходится вручную ветвиться в Mercurial; Mercurial автоматически создаст анонимную ветвь для вас, если и когда вам это нужно. Переменчивая номенклатура более интуитивна; вам не нужно беспокоиться о разнице между "fetch" и "pull", как вы это делаете с Мерзавец. Mercurial немного менее багги. Есть проблемы с чувствительностью к регистру имени файла, которые вызывали проблемы при нажатии проектов на разных платформах с Git и Mercurial; это было исправлено в Mercurial некоторое время назад, пока они не были исправлены в Git последний раз, когда я проверял. Вы можете рассказать Mercurial о переименованиях файлов; с Git, если он не обнаруживает переименование автоматически - очень хит или пропустить предложение в моем опыте-переименование не может быть отслежено вообще.

другая причина Однако дополнительное осложнение Git заключается в том, что многое из этого необходимо для поддержки дополнительных функций и мощности. Да, сложнее обрабатывать ветвление в Git - но, с другой стороны, как только у вас есть ветви, не слишком сложно делать вещи с теми ветвями, которые практически невозможны в Mercurial. Перебазирование ветвей-одна из таких вещей: вы можете переместить свою ветвь так, чтобы ее основание, вместо того, чтобы быть состоянием ствола, когда вы разветвлялись, было состоянием ствола сейчас; это значительно упрощает историю версий, когда есть много людей, работающих на одной и той же базе кода, поскольку каждый из толчков к магистрали может быть сделан последовательным, а не переплетенным. Аналогично, гораздо проще свернуть несколько коммитов в вашей ветви в одну фиксацию, что снова может помочь в сохранении истории управления версиями: в идеале, вся работа над функцией может отображаться как одна фиксация в магистрали, заменяя все второстепенные коммиты и суббранки, которые разработчик возможно, сделали при разработке функции.

в конечном счете, я думаю, что выбор между Mercurial и Git должен зависеть от того, насколько велики ваши проекты контроля версий, измеряемые с точки зрения количества людей, работающих над ними одновременно. Если у вас есть группа из дюжины или более, работающих над одним монолитным веб-приложением, например, более мощные инструменты управления филиалами Git сделают его гораздо лучше подходящим для вашего проекта. С другой стороны, если ваша команда разрабатывает гетерогенная распределенная система, в которой только один или два разработчика работают над одним компонентом в любое время, использование репозитория Mercurial для каждого из проектов компонентов позволит более плавно продвигаться вперед с меньшими затратами на управление репозиторием.

итог: если у вас есть большая команда, разрабатывающая одно огромное приложение, используйте Git; если ваши отдельные приложения малы, с любым масштабом, исходя из числа, а не размера таких приложений, используйте Деятельный.


одно отличие, совершенно не связанное с самими DVCSs:

Git, похоже,очень популярен у разработчиков C. Git-это де-факто репозиторий для ядра Linux, и это может быть причиной, почему он так популярен у разработчиков. Это особенно верно для тех, кто имеет роскошь работать только в мире Linux/Unix.

разработчики Java, похоже, предпочитают Mercurial над Git. Возможно, есть две причины для этого: одна заключается в том, что количество очень больших Java проекты размещаются на Mercurial, включая сам JDK. Другое дело, что структура и чистая документация обращений к людям из лагеря Java, в то время как такие люди находят git непоследовательным именованием команд wrt и отсутствием документации. Я не говорю, что это на самом деле правда, я говорю, что люди привыкли к чему-то из своей обычной среды обитания, а затем они склонны выбирать DVCS из этого.

разработчики Python почти исключительно предпочитают Mercurial, я бы предположить. На самом деле нет никакой рациональной причины для этого, кроме того, что Mercurial основан на Python. (Я тоже использую Mercurial, и я действительно не понимаю, почему люди поднимают шум вокруг языка реализации DVCS. Я не понимаю ни слова Python, и если бы не тот факт, что он указан где-то, что он основан на Python, я бы не знал).

Я не думаю, что вы можете сказать, что один DVCS подходит для языка лучше, чем другой, поэтому вы не должны выбирать от этого. Но на самом деле люди выбирают (частично), на основе которых DVCS они наиболее подвержены как часть своего сообщества.

(нет, у меня нет статистики использования для резервного копирования моих утверждений выше .. все это основано на моей собственной субъективности)