Git і Mercurial - Порівняйте та контрастуйте


520

Я певний час використовую підривну діяльність для своїх особистих проектів.

Все більше й більше чую чудові речі про Git та Mercurial та DVCS загалом.

Я хотів би передати всю річ з DVCS, але я не надто знайомий з жодним із варіантів.

Які існують відмінності між Mercurial та Git?

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


5
Дивіться також stackoverflow.com/questions/995636 / ...
VonC

2
Можливий дублікат Що є різницею між Mercurial і Git?
nawfal

Відповіді:


451

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

Дякуємо всім людям на #mercurial IRC-каналі, які надали допомогу щодо 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 має можливість написання та встановлені формати.

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

Структура сховища, що зберігає версії

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

Git використовує два способи зберігання об'єктів: вільний формат, де кожен об'єкт зберігається в окремому файлі (ці файли записуються один раз і ніколи не змінюються) та запакований формат, де багато об’єктів зберігаються дельта-стиснутими в одному файлі. Атомність операцій забезпечується тим фактом, що посилання на новий об'єкт записується (атомно, використовуючи твір створення + перейменування) після запису об'єкта.

Репозиторії Git потребують періодичного обслуговування git gc(для зменшення дискового простору та підвищення продуктивності), хоча сьогодні Git робить це автоматично. (Цей метод забезпечує кращу компресію сховищ.)

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

Mercurial використовує журнал транзакцій для забезпечення атомності операцій і покладається на обрізку файлів для очищення після невдалої або перерваної роботи. Огляди доступні лише для додавання.

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

Відмінності:
у Git дерева об'єкти утворюють ієрархічну структуру; у файлі Mercurial manifest є плоска структура. В об’єкті Gb blob зберігається одна версія вмісту файлу; у файловому файлі Mercurial зберігається вся історія одного файлу (якщо ми не враховуємо тут жодних ускладнень із перейменовуванням). Це означає, що існують різні області операцій, де Git був би швидшим, ніж Mercurial, всі інші речі вважаються рівними (наприклад, злиття або показ історії проекту), і області, де Mercurial був би швидше, ніж Git (наприклад, застосування патчів або показ історія одного файлу).Ця проблема може бути не важливою для кінцевого користувача.

З - за фіксовану структуру записи ртутної в журналу змін структури, що здійснюють в 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 опису".

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

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

Гілки

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

Поточна гілка в Git (тобто перевірена гілка та гілка, куди піде нова комісія) - це галузь, на яку посилається HEAD ref. Можна HEAD вказувати безпосередньо на зобов'язання, а не бути символічним посиланням; ця ситуація перебування на анонімній безіменній гілці називається відокремленою HEAD ("гілка гіта" показує, що ви перебуваєте на "(немає гілки)").

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

Так як 1.6 закладки можна натискати / тягнути. На сторінці закладок Розширення є розділ Робота з віддаленими сховищами . Існує різниця в тому, що в Mercurial назви закладок є глобальними , тоді як визначення "віддаленого" в Git описує також зіставлення імен гілок з імен у віддаленому сховищі до імен локальних гілок віддаленого відстеження; наприклад, refs/heads/*:refs/remotes/origin/*картографування означає, що можна знайти стан 'master' гілки ('refs / heads / master') у віддаленому сховищі у відділенні віддаленого відстеження 'origin / master' ('refs / Remotes / origin / master').

Mercurial також має так звані названі гілки , де назва гілки вбудовується у коміт (у набір змін). Така назва є глобальною (передається на вибір). Ці назви гілок постійно записуються як частина метаданих набору змін. За допомогою сучасного Mercurial ви можете закрити "названу гілку" і зупинити запис назви гілки. У цьому механізмі кінчики гілок розраховуються на льоту.

На мою думку, "названі гілки" Меркуріала слід називати замість цього робити позначки , тому що вони є. Бувають ситуації, коли "названа гілка" може мати декілька підказок (кілька бездітних доручень), а також може складатися з декількох розрізнених частин графіку змін.

Не існує еквівалента тих меркурійських «вбудованих гілок» у Git; Більше того, філософія Гіта полягає в тому, що, хоча можна сказати, що філія включає деякий коміт, це не означає, що комісія належить якійсь галузі.

Зауважте, що документація Mercurial все ще пропонує використовувати окремі клони (окремі сховища) принаймні для довгоживучих гілок (одна гілка на робочий процес сховища), так само розгалуження шляхом клонування .

Гілки в штовханні

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

Наскільки я розумію, якщо ви натиснете на цілий ряд редакцій, що містять комітети, позначені як такі, що знаходяться на якійсь "названій гілці" в Меркурійській мові, ви будете мати цю "названу гілку" у сховищі, до якого ви натискаєте. Це означає, що назви таких вбудованих гілок ("названі гілки") є глобальними (стосовно клонів даного сховища / проекту).

За замовчуванням (залежно від push.defaultзмінної конфігурації) "git push" або "git push < remote >" Git підштовхує відповідні гілки , тобто лише ті локальні гілки, які мають їх еквівалент, які вже є у віддаленому сховищі, в яке ви натискаєте. Ви можете використовувати --allопцію git-push ("git push - всі"), щоб натиснути всі гілки , ви можете використовувати "git push < віддалений > < гілка >", щоб натиснути задану одну гілку , і ви можете використовувати "git push < пульт > HEAD "для просування поточної гілки .

Все вищесказане передбачає, що Git не налаштований, які гілки можна пересувати через remote.<remotename>.push конфігураційні змінні.

Гілки в плоді

Примітка: тут я використовую термінологію Git, де "отримання" означає завантаження змін із віддаленого сховища без інтеграції цих змін із локальною роботою. Це те, що робить " git fetch" і " hg pull".

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

У Git за замовчуванням (для "origin" віддаленого, створеного "git clone", а для віддалених файлів, створених за допомогою "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 без назви.

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

Особиста думка: Я особисто вважаю, що "названі гілки" (з іменами гілок, вбудованими у метадані зміни набору) у Mercurial є неправильним дизайном із його глобальним простором імен, особливо для розподіленої системи управління версіями. Для прикладу візьмемо випадок, коли і Аліса, і Боб у своїх сховищах назвали гілку "for-joe", гілки якої не мають нічого спільного. Однак у сховищі Джо, ці дві гілки будуть жорстоко поводитися як одна гілка. Таким чином, ви якось придумали конвенцію, яка захищає від зіткнень з назви галузей. Це не проблема в Git, де в сховищі Джо для відділення "for-joe" від Alice було б "alice / for-joe", а від Bob це було "bob / for-joe".

На даний момент у "відділеннях закладок" Меркуріала відсутній основний механізм розподілу.

Відмінності:
Ця область є однією з головних відмінностей між Меркуріалом та Гітом , про що Джеймс Вудріат та Стів Лош сказали у своїх відповідях. Mercurial за замовчуванням використовує анонімні полегшені коделі, які в своїй термінології називаються "голови". Git використовує легкі гілки з назвою, з інжективним відображенням для відображення назв гілок у віддаленому сховищі до назв гілок віддаленого відстеження. Git "змушує" вас називати гілки (ну, за винятком однієї безіменної гілки; ситуація називається відокремленою HEAD), але я думаю, що це краще працює з важкими для галузей робочими процесами, такими як робочий потік тематичної гілки, тобто декілька гілок в єдиній парадигмі сховища.

Іменування змін

У Git існує багато способів іменування редакцій (описаних, наприклад, у git rev-parse manpage):

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

Також є специфікатори редагування, що включають reflog, про які не йдеться. У Git кожен об’єкт, будь то фіксація, тег, дерево або блоб, має свій ідентифікатор SHA-1; є спеціальний синтаксис, наприклад, "наступний: Документація" або "Наступний: README" для посилання на дерево (каталог) або blob (вміст файлу) при вказаній редакції.

У Mercurial також є багато способів іменування наборів змін (описаних, наприклад, на hg manpage):

  • Просте ціле число розглядається як ревізійний номер. Потрібно пам’ятати, що номери ревізії локальні для даного сховища ; в інших сховищах вони можуть бути різними.
  • Негативні цілі числа розглядаються як послідовне зміщення від наконечника, причому -1 позначає кінчик, -2 позначає ревізію до кінця тощо. Вони також локальні для сховища.
  • Унікальний ідентифікатор редакції (40-значний шістнадцятковий рядок) або його унікальний префікс.
  • Ім'я тега (символічне ім'я, пов’язане із заданою редакцією), або ім'я закладок (з розширенням: символічне ім'я, пов’язане із заданою заголовком, локальним для сховища), або "названа гілка" (label label; редакція, надана "названою гілкою") tip (бездітна фіксація) усіх комісій із заданим ярликом фіксації, з найбільшим номером редакції, якщо таких є більше)
  • Зарезервоване ім'я "порада" - це спеціальний тег, який завжди ідентифікує останню редакцію.
  • Зарезервована назва "null" вказує на нульову редакцію.
  • Зарезервоване ім’я "." вказує робочий батьківський каталог.

Відмінності
Як ви бачите, порівнюючи вищевказані списки, Mercurial пропонує номери редагування, локальні для сховища, тоді як Git - ні. З іншого боку, Mercurial пропонує відносні компенсації лише від 'tip' (поточної гілки), які є локальними для сховища (принаймні, без ParentrevspecExtension ), тоді як Git дозволяє вказати будь-яку комісію , що випливає з будь-якої підказки.

Остання редакція має назву HEAD у Git, а «tip» у Mercurial; в Git немає жодної нульової редакції. Як Mercurial, так і Git можуть мати багато корінців (можуть мати більше, ніж один без батьківських домовленостей; це зазвичай є результатом приєднання раніше окремих проектів).

Дивіться також: Багато різних видів перегляду специфікаторів статті на блозі Іллі (Newren - х).

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

Діапазони редагування

Діапазон редагування Git є топологічним . Загальноприйнятий A..Bсинтаксис, який для лінійної історії означає діапазон перегляду, починаючи з A (але виключаючи A), і закінчуючи на B (тобто діапазон відкритий знизу ), - це стенограма ("синтаксичний цукор") для ^A B, що для команд переходу історії означає всі здійснює доступність від B, виключаючи ті, досяжні з A. Це означає, що поведінка A..Bдіапазону є цілком передбачуваною (і цілком корисною), навіть якщо A не є родоначальником B: A..Bозначає, то діапазон ревізій від загального предка A і 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. Це , Я здогадуюсь, еквівалентний "--stryst-path A..B" у Git.

Git також має позначення A...Bсиметричної різниці ревізій; це означає A B --not $(git merge-base A B), що означає всі зобов'язання, доступні або від А, або з Б, але виключаючи всі домовленості, доступні від обох (доступні від загальних предків).

Перейменовує

Mercurial використовує відстеження перейменувань для обробки перейменувань файлів. Це означає, що інформація про те, що файл був перейменований, зберігається під час фіксації; у Mercurial ця інформація зберігається у формі "розширений розріз " у метаданих filelog (file revlog). Наслідком цього є те, що вам доведеться використовувати hg rename/ hg mv... або вам потрібно пам'ятати, щоб запустити, hg addremoveщоб зробити виявлення перейменування на основі подібності.

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

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

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

Мережеві протоколи

І Mercurial, і Git мають підтримку для отримання та перенесення до сховищ у тій же файловій системі, де URL-сховище - це лише шлях файлової системи до сховища. Обидва також мають підтримку для отримання файлів у пакеті .

Меркуріальна підтримка отримання та натискання через 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 для продуктивності, переносимості, а якщо сценарій оболонки уникає кутових випадків (ця процедура називається buildinification ).

Git покладається і будується навколо [сховища] форматів та [мережевих] протоколів. Замість прив'язки мови є (часткове або повне) повторне виконання Git іншими мовами (деякі з них є частково реімплементацією, а частково обгортками навколо команд git): JGit (Java, використовувана EGit, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), git # (C #).


TL; DR


32
Що можна додати, це те, що hg дуже намагається відмовити від переписування історії (це можна зробити лише з розширеннями: mq, histedit, rebase), тоді як git робить це поза вільним кодом (і це схоже на частину спільноти навіть заохочує це).
tonfa

80
Я думаю, що "переписування історії" є зайвим негативним звучанням. Що я заохочую в git - це люди розглянути історію, яку вони публікують. Інші люди повинні споживати цю історію. Ніхто (навіть ти) не цікавиться усіма твоїми "ой, забув файл". Також ніхто не дбає про серію вхідних злиттів, які ви пройшли, поки ви відстежували гілку вище за течією, працюючи над новою функцією. Такий матеріал робить історію (та пов'язані з нею інструменти) набагато складнішими для розуміння та не надає ніякої цінності.
Дастін

5
@Jakub: названі гілки - це те, чого не існує в git. Це просто поле в описі cset (і це частина історії, тому воно незмінне, якщо ви не змінюєте хеші тощо). Щось на зразок гілок git - це закладки ("названі голови"), але вони наразі не віддалено передаються (ви не імпортуєте віддалені закладки під час потягування). stevelosh.com/blog/entry/2009/8/30/… пояснює це дуже добре.
tonfa

28
"Mercurial спочатку підтримував лише одну гілку на робочий процес сховища, і це показує." Ні, ні. Mercurial спочатку не підтримував названі гілки, але ви завжди мали змогу мати стільки анонімних гілок, скільки вам хочеться за одне репо. На противагу цьому з git, який робить анонімне розгалуження величезним болем. Ви, мабуть, повинні придумати назву кожної маленької гілки, якщо хочете щось зробити (і уникати того, щоб ваш робочий сміття збирався).
Стів Лош

17
@SteveLosh: ти, здається, вважаєш, що в Mercurial багато анонімних гілок - це добре, але мені це здається жахливим. Як ти розказуєш їх усім? І вам здається, що називати гілки в Git - це величезна складність, але якщо у вас є мета створення гілки, то у вас є вже готове ім’я. Якщо у вас немає мети, тоді не слідкуйте. Я не бачу, як Mercurial пропонує тут будь-яку вигоду. Я бачу лише біль і розгубленість.
іконоборство

57

Я думаю, що ви можете відчути, на що ці системи схожі чи відрізняються, за допомогою того, що ці два відео:

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


8
Я рекомендую прочитати всі коментарі на цій кодовій сторінці google. Інформація відчуває себе дещо упередженою і не відповідає моєму досвіду. Я як рт.ст., і використовував його екстенсивно в протягом року або близько того . Я зараз використовую git майже виключно. Мені потрібно зробити те, що git робить легким, а hg робить майже неможливим (хоча деякі люблять називати це за допомогою "ускладнення".) Basic git такий же простий, як базовий hg.
Дастін

11
Дастін, може, перерахуй деякі з тих випадків, коли "git easy, hg не так багато"?
Грегг Лінд

1
@knittl ні, ні. Головним чином, тому, що для них було б боляче розгортати, оскільки у git не вистачає смарт-протоколу http (більшість фронтальних сторінок Google базуються на http).
tonfa

2
@tonfa: Наразі розробляється смарт-протокол HTTP для Git (як і в: у списку розсилки git є виправлення, і вони знаходяться у 'pu' = пропонована гілка оновлень у сховищі git.git).
Якуб Нарбський

4
На сьогодні Google Code також підтримує Git.
Andrej Kirejeŭ

30

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


@Steve Losh: Я хотів прокоментувати цю запис у блозі (про неназвану гілку, відокремлену HEAD, і про git-fetch, що отримує всі гілки, не одну), але я отримав помилку на сервері 500.
Якуб Нарбський

1
@Jakub Narębski Сподіваюся, що проблема полягає у символі, який не належить до ASCII у вашому імені. Я майже впевнений, що я зіткнувся з тією ж проблемою на іншому сайті, і виявилося, що зв'язувальні дроти Python Askimet на Unicode. Я погляну.
Стів Лош

@Steve Losh: Дякую за інформацію, після "unidecoding" мого імені я зміг написати коментар. Дуже хороший опис розгалуження в Mercurial (але я все ще думаю, що він неповноцінний ;-))
Якуб Нарбскі

@SteveLosh Я заохочую вас розширити цю відповідь на більш повний огляд меркуріалу. На даний момент, головна відповідь, на жаль, значною мірою є рекламою для git, оскільки його автор не використовував велику кількість меркуріалу і не розуміє, як його ефективно використовувати. Було б непогано ще однією відповіддю надати меркурійну точку зору, так би мовити.
Warren Dew

25

Я використовую обидва досить регулярно. Основна функціональна відмінність полягає в тому, як гіт і ім'я Меркуріалу розгалужуються в сховищах. За допомогою Mercurial назви філій клонуються та витягуються разом із їх набором змін. Коли ви додаєте зміни до нової гілки в Mercurial і переходите до іншого сховища, ім'я гілки одночасно висувається. Отже, імена гілок є більш-менш глобальними в Mercurial, і ви повинні використовувати розширення Bookmark, щоб мати лише локальні імена (якщо ви хочете їх; Mercurial за замовчуванням використовує анонімні полегшені коди, які за своєю термінологією є називаються «голови»). У Git назви гілок та їх ін’єктивне відображення до віддалених гілок зберігаються локально, і ви повинні керувати ними явно, а це означає знати, як це зробити.

Як зазначають інші, тут є багато і багато незначних відмінностей. Справа з гілками - великий диференціатор.


2
Дивіться також цей пост, щоб добре пояснити чотири види філій в Mercurial: stevelosh.com/blog/entry/2009/8/30/…
Мартін Гейслер,


11

Меркуріал майже повністю написаний пітоном. Ядро 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.


9
Меркуріальне ядро ​​написано на С занадто FYI (але це, мабуть, менше ядро, ніж git).
tonfa

1
Я без проблем використовую git-svn у Windows. Це використання Cygwin (єдиний правильний спосіб використання git в Windows, якщо ви запитаєте мене). Не можу говорити за msysgit.
Dan Molding

@Dan Molding: Так, у мене виникли проблеми з msysgit. Можливо, потрібно спробувати порту cygwin (у мене був поганий досвід використання cygwin раніше, тому я цього уникав). Дякую за пораду!
старший_геордж

Мені особисто не подобається вторгнення cygwin в реєстр для зберігання даних користувачів. Це PITA - це змусити його запускати USB-ключ і зберігати локальну копію диска c: \ диск, коли я хочу працювати швидше, ніж мій ключ USB. : - /
Кріс К

1
Я використовую плагін Git для згаданої вище Visual Studio, і продуктивність поточної версії хороша. Він надає інструменти командного рядка для виконання роботи, тому я не думаю, що це значно втратить результативність у великих проектах.
Стюарт Елліс

11

Якщо вам потрібна хороша підтримка Windows, ви можете віддати перевагу Mercurial. TortoiseHg (плагін Windows Explorer) вдається запропонувати простий у використанні графічний інтерфейс досить складного інструменту. Як зазначено тут, у вас також буде плагін Visual Studio . Однак останній раз, коли я намагався, інтерфейс SVN не так добре працював у Windows.

Якщо ви не заперечуєте проти інтерфейсу командного рядка, я рекомендую Git. Не з технічної причини, а з стратегічної. Швидкість прийняття git набагато вище. Подивіться, скільки відомих проектів з відкритим кодом переходить з cvs / svn на Mercurial і скільки переходить на Git. Подивіться, скільки провайдерів хостингу коду / проекту ви можете знайти за підтримки git порівняно з хостинг Mercurial.


Також є TortoiseGit, якщо вам не подобається використовувати командний рядок. (Але для цього потрібно встановити msysgit.)
Бен Джеймс

2
Наша компанія закінчила вибір git завдяки чудовій підтримці Windows - перевірити Git Extensions . Я упереджений, тому що зараз я працюю, але я не був, коли ми почали його використовувати.
Джейкоб Стенлі

11

Прочитавши все, що 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 має субрепости, але це не зовсім підмодуль Git.

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

У кожного є свої переваги і недоліки, жоден з яких ви не збираєтеся втрачати.


8

Ознайомтеся з повідомленням Скотта Чейкона з часом.

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

Це не тільки мій досвід, що git не більш заплутаний, ніж меркурійний. Я б рекомендував ще раз прочитати цю публікацію в блозі від Скотта Чакона з цього питання.


1
Меркуріальна модель насправді майже однакова: зміни журналу вказують на перегляд файлів / перегляд файлів ... зроблено. Якщо ви порівнювали формат на диску, ви, ймовірно, не брали до уваги файл пакунків, який пояснюється складніше, ніж простий формат revlog від hg.
tonfa

Що ж, ця спрощена модель ігнорує теги, що значно незграбніше на практиці в hg (хоча я стверджую, що тег git трохи заплутаний, оскільки він не створює об’єкт тегу за замовчуванням). Формат диска був особливо дорогим для обох проектів, в яких було багато імен файлів.
Дастін

1
Я не думаю, що модель не ігнорує тегування: тегування в Mercurial є тривіальним - як ви знаєте, це лише файл, який дає імена хешам SHA-1 Немає здогадок про те, як теги об’їжджаються в системі: вони рухаються разом із натисканнями та тягненнями. І якщо є конфлікт з тегами, то тоді це також банально вирішити: ви вирішите його, як і будь-який інший конфлікт. Зрештою, це лише рядок у текстовому файлі. Я думаю, що простота цієї моделі - дуже приємна особливість.
Мартін Гейслер

Дастін: Так, користувачів часто бентежить те, що ви не можете бачити тег 1.0, .hgtagsколи ви перевірили версію 1.0. Однак вам не потрібно заглядати всередину, .hgtagsі ви побачите, що hg tagsвсе ще перелічені всі теги. Крім того, така поведінка є простим наслідком зберігання тегів у файлі, керованому версією - знову ж модель легко зрозуміти і дуже передбачувана .
Мартін Гейслер

1
Мартін Гейслер Я б заперечував, що правила для тегів у Mercurial, необхідні, оскільки для транспортування використовується контрольований версією файл із шаром спеціальних правил, щоб зробити теги неперевершеними, зрозуміти все просто.
Якуб Нарбський

5

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

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

Однак існують також істотні відмінності між Git та Mercurial, які роблять кожного краще для власного підмножини випадків використання.

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

Почасти це тому, що Mercurial - просто очищувач. Вам рідко доводиться гілкуватися вручну в Mercurial; Mercurial автоматично створить анонімну гілку для вас, якщо і коли вам це потрібно. Меркуріальна номенклатура є більш інтуїтивно зрозумілою; вам не доведеться турбуватися про різницю між "добутком" і "тягненням", як це робиться з Git. Mercurial трохи менше баггі. Є проблеми з чутливістю до імен файлів, які використовувались для виникнення проблем під час передачі проектів на платформах як із Git, так і з Mercurial; це було виправлено в Mercurial деякий час тому, поки вони не були виправлені в Git востаннє я перевірив. Ви можете повідомити Mercurial про перейменування файлів; з Git, якщо він не визначає перейменування автоматично - дуже вражений або пропущений пропозицією, на мій досвід - перейменування взагалі не можна відстежувати.

Іншою причиною додаткового ускладнення Гіта є те, що багато чого потрібно для підтримки додаткових функцій та потужності. Так, складніше обробляти розгалуження в Git - але, з іншого боку, коли ти маєш гілки, зробити це з тими гілками, які практично неможливі в Mercurial, не так вже й складно. Звільнення гілок - це одна з таких речей: ви можете перемістити свою гілку таким чином, що її основа, замість того, щоб бути станком, коли ви розгалужувались, зараз - стан стовбура; це значно спрощує історію версій, коли на одній базі коду працює багато людей, оскільки кожен з поштовхів до магістралі може бути зроблений послідовним, а не переплетеним. Аналогічно, набагато простіше згортати кілька комісій у вашій гілці на одну комісію,

Зрештою, я думаю, що вибір між Mercurial та Git повинен залежати від того, наскільки великі ваші проекти контролю версій, виміряні з огляду на кількість людей, які працюють над ними одночасно. Якщо у вас є група з десятків і більше, які працюють над однією монолітною веб-програмою, наприклад, більш потужні інструменти управління гілками Git зробить її набагато кращою для вашого проекту. З іншого боку, якщо ваша команда розробляє неоднорідну розподілену систему, і лише один або два розробники працюють над будь-яким компонентом у будь-який час, використання репозиторію Mercurial для кожного з компонентних проектів дозволить розробки протікати більш плавно з меншими управління сховищами накладні витрати.

Підсумок: якщо у вас є велика команда, яка розробляє єдине величезне додаток, використовуйте Git; якщо ваші окремі додатки невеликі, будь-який масштаб виходить із числа, а не від розміру таких програм, використовуйте Mercurial.


4

Одна різниця, абсолютно не пов'язана з самими DVCS:

Здається, Git користується великою популярністю у розробників C. Git - це фактичне сховище для Linux Kernel, і це може бути причиною, чому він настільки популярний серед розробників C. Особливо це стосується тих, хто має розкіш лише працювати у світі Linux / Unix.

Розробники Java, схоже, віддають перевагу Mercurial над Git. Можливо, є дві причини для цього: Одна полягає в тому, що на Mercurial розміщується ряд дуже великих Java-проектів, в тому числі і сам JDK. Інше полягає в тому, що структура та чиста документація Mercurial звертається до людей, що приїжджають з табору Java, тоді як такі люди вважають, що Git не відповідає послідовним іменам wrt і не має документації. Я не кажу, що це насправді правда, я кажу, що люди звикли до чогось із звичного місця проживання, і тоді вони, як правило, обирають DVCS з цього.

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

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

.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.