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

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

Все больше и больше я слышу большие вещи о Git и Mercurial и DVCS вообще.

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

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

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

Ответы

Ответ 1

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

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



Резюме

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

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

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

Структура хранилища, сохранение версий

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

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

Хранилища

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

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

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

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

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

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

Насколько я знаю, Mercurial не имеет эквивалента аннотированных тегов (объектов тега) из Git. Особым случаем аннотированных тегов являются подписанные теги (с подписью PGP/GPG); эквивалент в Mercurial может быть выполнен с использованием GpgExtension, расширение которого распространяется вместе с Mercurial. Вы не можете отмечать неблокирующий объект в Mercurial, как вы можете в Git, но это не очень важно, я думаю (некоторые репозитории Git используют tagged blob для распространения открытого ключа 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 описывают".

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

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

Филиалы

В Git локальная ветвь (ветвь или ветвь ветки) является именованной ссылкой на фиксацию, где можно вырастить новые коммиты. Филиал также может означать активную линию развития, т.е. Все фиксации достижимы от кончика ответвления. Локальные ветки находятся в пространстве имен refs/heads/, так, например, полное имя ветки "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/* означает, что в удаленном репозитории можно найти состояние "ведущей" ветки ( "refs/heads/master" ) в ветке удаленного отслеживания "источник/мастер" ( "refs/remotes/origin/master" ").

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

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

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

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

Филиалы в нажатии

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

Насколько я понимаю, если вы нажмете целый ряд ревизий, которые содержат коммиты, помеченные как "на определенной ветки" в языке 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>", чтобы получить единственная ветвь. Вы можете указать <rev> используя идентификатор ревизии, имя "named branch" (ветвь, встроенная в журнал изменений) или имя закладки. Однако название закладки (по крайней мере в настоящее время) не передается. Все "названные ветки", которые вы получаете, принадлежат для передачи. "hg pull" хранит концы ветвей, которые он набирал как анонимные, неназванные головы.

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

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

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

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

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

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

Именование версий

В Git существует много способов переименования версий (описано, например, в Git rev-parse manpage):

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

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

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

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

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

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

См. также: Много разных спецификаций ревизий статья об блоге Илии (newren's).

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

В диапазонах меркурийного пересмотра используется диапазон номеров версий. Диапазон задается с использованием синтаксиса 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 эта информация сохраняется в форме "расширенный diff" в метаданных filelog (файл revlog). Следствием этого является то, что вы должны использовать hg rename/hg mv... или вам нужно помнить о запуске hg addremove для обнаружения переименования на основе сходства.

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

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

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

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

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

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

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

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

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

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

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

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


TL; DR

Ответ 2

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

Линус Торвальдс на 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). У него много хорошей информации.

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

Mercurial почти полностью написан на питоне. Ядро 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 они могут быть записаны в любой исполняемой форме (исполняемый двоичный файл, оболочка script и т.д.). Некоторые расширения сумасшедшие, например git bisect.

Ответ 7

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

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

Ответ 8

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

То, что я пропустил в Hg, является функцией подмодуля Git. Hg имеет подпозицию, но не точный подмодуль Git.

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

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

Ответ 9

Откажитесь от сообщение Скотта Чакона через некоторое время.

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

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

Ответ 10

Одно отличие, полностью не связанное с самими DVCS:

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

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

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

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

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

Ответ 11

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

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

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

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

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

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

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

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