Git и Mercurial - сравни и сравни

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

Я все больше и больше слышу о Git, Mercurial и DVCS в целом.

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

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

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

11 ответов

Решение

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

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



Резюме

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

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

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

Структура репозитория, хранение ревизий

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

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

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

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

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

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

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

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

Насколько я знаю, у Mercurial нет эквивалента аннотированных тегов (объектов тегов) из Git. Частным случаем аннотированных тегов являются подписанные теги (с подписью PGP / GPG); эквивалент в Mercurial можно сделать с помощью GpgExtension, расширение которого распространяется вместе с Mercurial. Вы не можете пометить объект без фиксации в Mercurial, как вы можете это сделать в Git, но это, я думаю, не очень важно (некоторые репозитории git используют теговый блоб для распространения открытого ключа PGP, который используется для проверки подписанных тегов).

Ссылки: ветки и метки

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

Теги

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

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

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

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

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

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

ветви

В Git локальная ветвь (tip tip или head branch) является именованной ссылкой на коммит, где можно вырастить новые коммиты. Ветвь также может означать активную линию развития, то есть все коммиты, достижимые из кончика ветви. Местные отделения проживают в refs/heads/ namespace, например, полное имя ветви 'master' - 'refs/heads/master'.

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

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

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

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

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

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

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

Отводы в толкании

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

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

По умолчанию (при условии push.default переменная конфигурации) "git push" или "git push < remote >" Git будет выдвигать совпадающие ветви, то есть только те локальные ветви, которые имеют свой эквивалент, уже присутствующий в удаленном репозитории, в который вы помещаете. Ты можешь использовать --all опцию git-push ("git push --all"), чтобы протолкнуть все ветви, вы можете использовать "git push < remote > < branch >", чтобы протолкнуть данную отдельную ветку, и вы можете использовать "git push < remote > HEAD "нажать текущую ветку.

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

Филиалы в получении

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

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

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

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

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

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

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

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

Имена ревизий

В Git существует множество способов присвоения имен ревизиям (описанных, например, на man - странице git rev-parse):

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

Существуют также спецификаторы ревизий, включающие reflog, не упомянутые здесь. В Git каждый объект, будь то фиксация, тег, дерево или блоб, имеет свой идентификатор SHA-1; Существует специальный синтаксис, например, "следующий: Документация" или "следующий:README" для ссылки на дерево (каталог) или BLOB-объект (содержимое файла) в указанной ревизии.

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

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

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

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

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

Личное мнение: я думаю, что номера ревизий переоценены (по крайней мере, для распределенной разработки и / или нелинейной / ветвистой истории). Во-первых, для распределенной системы контроля версий они должны быть либо локальными по отношению к хранилищу, либо требовать особого подхода к некоторому хранилищу в качестве центрального органа нумерации. Во-вторых, более крупные проекты с более длинной историей могут иметь количество ревизий в диапазоне 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 имеет смысл, только если A является предком B или наоборот, то есть с линейной историей; в противном случае (я предполагаю, что) диапазон непредсказуем, и результат является локальным для репозитория (потому что номера ревизий являются локальными для репозитория).

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

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

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

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

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

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

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

Сетевые протоколы

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

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

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

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

Расширение: скриптируемость против расширений (плагинов)

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

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

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


TL; DR

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

Линус Торвальдс на 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 Code поддерживает только 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, и вы должны использовать расширение Bookmark, чтобы иметь только локальные облегченные имена (если вы хотите их; Mercurial, по умолчанию, использует анонимные облегченные кодовые строки, которые в его терминологии являются называется "головы"). В Git имена веток и их инъективное отображение на удаленные ветки хранятся локально, и вы должны управлять ими явно, что означает знание того, как это сделать. Это в значительной степени то, где Git получает репутацию более трудного для изучения и использования, чем Mercurial.

Как другие заметят здесь, есть много и много мелких различий. Дело в ветвях - это большая разница.

Взгляните на Git vs. Mercurial: пожалуйста, расслабьтесь в блоге Патрика Томсона, где он пишет:
Git - МакГайвер, Mercurial - Джеймс Бонд

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

После прочтения, что Mercurial проще (что я до сих пор считаю, после того, как интернет-сообщество придерживается такого мнения), когда я начал работать с Git и Mercurial, я почувствовал, что Git относительно проще для меня адаптироваться (я начал с Mercurial с TortoiseHg) при работе из командной строки, главным образом потому, что команды git были названы соответствующим образом, как мне кажется, и их меньше. Mercurial имеет разные названия для каждой команды, которая выполняет отдельную работу, в то время как команды Git могут быть многофункциональными в зависимости от ситуации (например, checkout). В то время как Git был сложнее, сейчас разница вряд ли существенная. YMMV.. С хорошим клиентом с графическим интерфейсом, таким как TortoiseHg, правда, работать с Mercurial было намного проще, и мне не нужно было запоминать слегка запутанные команды. Я не буду вдаваться в подробности, как менялись все команды для одного и того же действия, но вот два исчерпывающих списка: 1 с собственного сайта Mercurial и 2-й из вики.

╔═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════╗
║           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 есть подпункты, но это не совсем подмодуль Git.

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

У каждого есть свои преимущества и недостатки, с любым из которых вы не потеряете.

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

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

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

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

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

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

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

Проверьте почту Скотта Чакона некоторое время назад.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам