Злиття: Hg / Git проти SVN


144

Я часто читаю, що Hg (і Git, і ...) краще поєднуються, ніж SVN, але я ніколи не бачив практичних прикладів того, де Hg / Git може зливатися чимось там, де SVN не працює (або де SVN потребує ручного втручання). Чи можете ви опублікувати кілька покрокових списків операцій відділення / модифікації / фіксації /...-, які показують, де SVN не вдасться, поки Hg / Git щасливо рухається далі? Практичні, не надзвичайно виняткові випадки, будь ласка ...

Деякі відомості: у нас є кілька десятків розробників, які працюють над проектами, що використовують SVN, з кожним проектом (або групою подібних проектів) у своєму сховищі. Ми знаємо, як застосувати гілки випусків та функцій, щоб ми не стикалися з проблемами дуже часто (тобто ми там були, але ми навчилися долати проблеми Джоела "одного програміста, який завдав травму всій команді". або "для реінтеграції філії потрібно шість розробників протягом двох тижнів"). У нас є гілки випуску, які є дуже стабільними і використовуються лише для застосування помилок. У нас є магістралі, які повинні бути досить стабільними, щоб можна було створити реліз протягом одного тижня. І у нас є функції галузей, над якими можуть працювати окремі розробники або групи розробників. Так, вони видаляються після реінтеграції, щоб вони не захаращували сховище. ;)

Тому я все ще намагаюся знайти переваги Hg / Git над SVN. Я хотів би отримати практичний досвід, але немає ще великих проектів, які ми могли б перейти до Hg / Git, тому я застряг у грі з невеликими штучними проектами, які містять лише кілька складених файлів. І я шукаю кілька випадків, коли можна відчути вражаючу силу Hg / Git, оскільки до цих пір я часто читав про них, але не міг їх знайти сам.


2
Я думаю, вам слід звернути увагу на точні дублікати: stackoverflow.com/questions/43995/… stackoverflow.com/questions/459891/…
P Швед,

11
Я вже прочитав перший, другий - новий. Але їм вже 1-2 роки, і, здається, вони здебільшого стосуються проблем, що виникають перед svn-1.5 (де у svn ще не було відстеження об’єднань).
stmax

2
Лише зауваження, що ви також можете збивати Bazaar з git / hg як інший DVCS, який правильно вирішить наведені нижче проблеми. А оскільки ви згадали, намагаючись знайти переваги: ​​одна проста логістична перевага git / hg / bzr полягає в тому, що гілки не є глобальними, як це є у svn. Вам не доведеться бачити 67 відділень, коли до вас звертається лише пара. Усі роблять свою роботу в "приватних" відділеннях, а потім використовують чудову можливість злиття, щоб об'єднатися назад, не потіючи, чи буде злиття працювати в 99% випадків.
Wadesworld

5
@wade: чи бачите ви "приватні" відділення як перевагу у корпоративному середовищі? Я переживаю за резервні копії. У мене часто є гілки, які живуть за 1-2 місяці до реінтеграції ..
stmax

9
@stmax: дійсна проблема. Однак у багатьох корпоративних середовищах із підривниками є те, що люди тримаються на реєстрації, поки їх код не буде ідеальним, і у вас там же експозиція.
wadesworld

Відповіді:


91

Сам я не використовую Subversion, але з приміток до випуску для Subversion 1.5: відстеження злиття (основоположне), схоже, є такі відмінності від того, як працює відстеження злиття в системах управління версіями DAG на зразок Git або Mercurial.

  • Злиття стовбура з гілкою відрізняється від об'єднання гілки до стовбура: чомусь для злиття стовбура з гілкою потрібен --reintegrateваріант для svn merge.

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

  • Вам потрібно надати новий -g( --use-merge-history) варіант для svn logта svn blameврахувати відстеження злиття.

    У Git та Mercurial відстеження злиття автоматично враховується під час відображення історії (журналу) та звинувачення. У Git ви можете попросити слідкувати за першим батьком лише з --first-parent(я думаю, подібний варіант існує і для Mercurial), щоб "відкинути" інформацію про відстеження об'єднання в git log.

  • З я розумію, що svn:mergeinfoвластивості зберігають інформацію про конфлікти на одному шляху (Subversion заснована на наборах змін), тоді як у Git та Mercurial це просто введення об'єктів, у яких може бути більше одного з батьків.

  • Підрозділ "Відомі проблеми" для відстеження злиття в Subversion дозволяє припустити, що повторне / циклічне / відбивне злиття може не працювати належним чином. Це означає, що з наступними історіями друге злиття може не робити правильно ("A" може бути стовбуром або гілкою, а "B" може бути гілкою або стовбуром відповідно):

    * --- * --- x --- * --- y --- * --- * --- * --- M2 <- A
             \ \ /
              - * ---- M1 --- * --- * --- / <- B
    

    У випадку, коли вищезгадане мистецтво ASCII порушується: гілка 'B' створюється (роздвояється) з гілки 'A' при перегляді 'x', потім пізніше гілка 'A' об'єднується при перегляді 'y' у гілку 'B' як злиття 'M1', і, нарешті, гілка 'B' об'єднується у гілку 'A' як злиття 'M2'.

    * --- * --- x --- * ----- M1 - * --- * --- M2 <- A
             \ / / 
              \ - * --- y --- * --- * --- / <- B
    

    У випадку, якщо вищезгадане ASCII-мистецтво буде порушено: гілка 'B' створюється (роздвояється) від гілки 'A' при перегляді 'x', вона об'єднується у гілку 'A' у 'y' як 'M1' та пізніше знову об'єдналися у відділення "A" як "M2".

  • Subversion може не підтримувати розширений випадок перехресного злиття .

    * --- b ----- B1 - M1 - * --- M3
         \ \ / /
          \ X /
           \ / \ /
            \ - B2 - M2 - *
    

    Git вирішує цю ситуацію просто чудово на практиці, використовуючи "рекурсивну" стратегію злиття. Я не впевнений у Меркуріалі.

  • У "Відомих питаннях" є попередження про те, що функція відстеження злиття не працює з перейменами файлів, наприклад, коли одна сторона перейменовує файл (і, можливо, модифікує його), а друга сторона змінює файл без перейменування (під старим іменем).

    І Git, і Mercurial справляються з таким випадком на практиці: Git використовує виявлення перейменувань , Mercurial за допомогою відстеження перейменування .

HTH


якимось чином (помилка в аналізаторі Markdown?) частина після <pre>...</pre>блоку не відступає, як належить ...
Якуб Нарбський

1
+1 для багатьох детальних прикладів. Я ще не розумію, чому приклад у першій мистецтві може спричинити проблеми. це виглядає як стандартний спосіб обробки гілок функцій: припустимо, що A - стовбур, B - галузь функції. ви щотижня зливаєтеся з А в Б, і коли закінчите функцію, ви з’єднаєте все від В до А, а потім видалите Б., який завжди працював на мене. я неправильно зрозумів схему?
stmax

1
Зауважте, що я не знаю (я не перевіряв), що приклади, наведені вище, справді створюють проблеми в Subversion . Перейменування та перехресне злиття - справжня проблема в SVN, я думаю.
Якуб Нарубський

2
реінтегрувати злиття - це особливий варіант, який допоможе вам у найпоширенішому випадку при злитті - технічна різниця між гілками та стовбуром у svn також не існує. Я, як правило, ніколи його не використовую, і дотримуюся стандартного варіанту злиття. Однак єдиною проблемою з svn merge є те, що він розглядає переміщення / перейменування як видалення + додавання.
gbjbaanb

--reintegrateзастаріло.
naught101

120

Я теж шукав випадок, коли, скажімо, Subversion не зможе об'єднати гілку, а Mercurial (і Git, Bazaar, ...) робить все правильно.

У книзі SVN описано, як неправильно об'єднані перейменовані файли . Це стосується Subversion 1.5 , 1.6 , 1.7 та 1.8 ! Я спробував відтворити ситуацію нижче:

cd / tmp
rm - rf svn - repo svn - замовлення
svnadmin create svn - repo
файл замовлення svn : /// tmp / svn - repo svn - замовлення
cd svn - замовлення
mkdir стовбурові гілки
відлуння "Прощавай, світ!" > багажник / привіт . txt 
svn додати стовбурові гілки
svn commit - m 'Початковий імпорт.' 
svn копія '^ / trunk' '^ / гілки / перейменувати' - m 'Створити гілку.' 
svn перемикач '^ / магістраль' . 
відлуння "Привіт, світ!" > привіт . txt    
svn commit - m 'Оновлення на магістралі.' 
svn перемикач '^ / гілки / перейменувати' . 
svn перейменувати привіт . txt привіт . en . txt 
svn commit - m 'Перейменувати на гілку.' 
svn перемикач '^ / магістраль' . 
svn merge - реінтегрувати '^ / гілки / перейменувати' 

Згідно з книгою, злиття має закінчитися чисто, але з неправильними даними в перейменованому файлі, оскільки оновлення на trunkзабуте. Натомість я отримую конфлікт із деревами (це з Subversion 1.6.17, найновішою версією Debian на момент написання):

--- Об’єднання відмінностей між URL-адресами сховища в '.':
A hello.en.txt
   C hello.txt
Короткий зміст конфліктів:
  Конфлікти з дерева: 1

Тут не повинно бути конфліктів - оновлення має бути об'єднано в нове ім'я файлу. Хоча Subversion не працює, Mercurial справляється з цим правильно:

rm -rf /tmp/hg-repo
hg init /tmp/hg-repo
cd /tmp/hg-repo
echo 'Goodbye, World!' > hello.txt
hg add hello.txt
hg commit -m 'Initial import.'
echo 'Hello, World!' > hello.txt
hg commit -m 'Update.'
hg update 0
hg rename hello.txt hello.en.txt
hg commit -m 'Rename.'
hg merge

Перед об'єднанням сховище виглядає так (від hg glog):

@ набір змін: 2: 6502899164cc
| тег: чайові
| батьків: 0: d08bcebadd9e
| користувач: Martin Geisler
| дата: Чет 01 квітня 12:29:19 2010 +0200
| Короткий зміст: Перейменувати.
|
| o зміна: 1: 9d06fa155634
| / користувач: Мартін Гейслер 
| дата: Чет 01 квітня 12:29:18 2010 +0200
| Короткий зміст: оновлення.
|
o зміна: 0: d08bcebadd9e
   користувач: Martin Geisler 
   дата: Чет 01 квітня 12:29:18 2010 +0200
   Короткий зміст: Початковий імпорт.

Вихід злиття:

злиття hello.en.txt та hello.txt до hello.en.txt
0 файлів оновлено, 1 файл об'єднано, 0 файлів видалено, 0 файлів не вирішено
(злиття гілки, не забудьте здійснити)

Іншими словами: Mercurial прийняв зміну з версії 1 і об'єднав її в нове ім'я файлу з версії 2 ( hello.en.txt). Робота з цим випадком, безумовно, важлива для того, щоб підтримувати рефакторинг і рефакторинг - це саме та річ, яку ви хочете зробити на гілці.


+1 для детального прикладу можна натиснути на клавіатуру і побачити, що відбувається. Як Mercurial noob, мені цікаво, чи версія hg цього прикладу дотримується очевидним чином, по черзі?
DarenW

4
@DarenW: Я додав відповідні команди Mercurial, сподіваюся, що це робить ясніше!
Мартін Гейслер

17

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

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

Як ви з’єднаєте лише одну з двох функцій на головній гілці?
Або як ви виділити дві особливості у власних гілках?

Ви можете спробувати створити якісь виправлення, проблема в тому, що ви вже не впевнені у функціональних залежностях, які могли існувати між:

  • коміти (або версії для SVN), які використовуються у ваших виправленнях
  • інший здійснює не частину патча

Git (і Mercurial теж я гадаю) пропонують rebase - до опції перезавантажити (скинути корінь гілки) частини гілки:

З поста Джефромі

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (v2-only) - x - x - x (wss)

ви можете розплутати цю ситуацію, коли у вас є виправлення для v2, а також нова функція wss:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - x - x (v2-only)
           \
             x - x - x (wss)

, що дозволяє:

  • перевірити кожну гілку ізольовано, щоб перевірити, чи все компілюється / працює за призначенням
  • зливай лише те, що ти хочеш головне.

Інша особливість, яка мені подобається (яка впливає на злиття), - це здатність скорочувати коміти (у гілці, ще не висунутій до іншого репо), щоб представити:

  • чистіша історія
  • коміти, які є більш узгодженими (замість команд1 для функції1, коміка2 для функції2, знову команда3 для функції1 ...)

Це забезпечує злиття, що набагато простіше, з меншими конфліктами.


svn не має офлайн-коммітів? rofl? як може хтось навіть віддалено розглянути можливість його використання, якщо це так?
o0 '.

@Lohoris Коли вийшов SVN, широко використовуваних DVCS з відкритим кодом не було; на даний момент, я думаю, що здебільшого за інерцією люди все ще користуються цим.
Макс Нанасі

@MaxNanasy дуже поганий вид інерції ... все-таки вибір її зараз був би просто дурним.
o0 '.

@Lohoris Online (точніше, централізовано) зобов’язання - це не така велика справа в невеликій команді, де сховище може бути просто на спільному локальному сервері. DVCS здебільшого були винайдені для великих географічно розподілених команд (як git, так і mercurial призначені для управління кодом ядра Linux) та проектів з відкритим кодом (звідси популярність GitHub). Інерцію також можна розглядати як оцінку ризиків та переваг від зміни інструменту, що є основним для робочого процесу команди.
IMSoP

1
@Lohoris Я думаю, ви неправильно зрозуміли мою думку про БД, брандмауер тощо: мало сенсу мені бути в змозі здійснити свою домашню машину, якщо я фактично не можу запустити цей код першим. Я міг би працювати незрячим, але той факт, що я не можу десь робити щось, не було б головним, що мене відклало.
IMSoP

8

Нещодавно ми перейшли з SVN в GIT і зіткнулися з цією ж невизначеністю. Було багато анекдотичних доказів того, що GIT кращий, але важко натрапити на будь-які приклади.

Але я можу вам сказати, що GIT - НАЙКРАЩИЙ при злитті, ніж SVN. Це, очевидно, анекдотично, але є таблиця, яку слід слідувати.

Ось деякі з речей, які ми знайшли:

  • SVN використовував для того, щоб викидати безліч конфліктів на дерева в ситуаціях, коли здавалося, що це не повинно. Ми ніколи не доходили до цього, але це не відбувається в GIT.
  • Хоча краще, GIT значно складніше. Витратьте трохи часу на тренування.
  • Ми звикли до черепахового SVN, який нам сподобався. Черепаха GIT не настільки хороша, і це може вас відкласти. Однак зараз я використовую командний рядок GIT, який я більше віддаю перевагу Tortoise SVN або будь-який із графічного інтерфейсу GIT.

Коли ми оцінювали GIT, ми провели наступні тести. Вони показують GIT як переможця, коли справа стосується об'єднання, але не настільки. На практиці різниця набагато більша, але я думаю, що нам не вдалося повторити ситуації, з якими SVN погано справляється.

Оцінка об'єднання GIT проти SVN


5

Інші висвітлювали більш теоретичні аспекти цього. Можливо, я можу надати більш практичну перспективу.

Зараз я працюю в компанії, яка використовує SVN в моделі розвитку "особливої ​​галузі". Це є:

  • Жодна робота не може бути виконана на багажнику
  • Кожен розробник може створити власні відділення
  • Відділення повинні тривати протягом виконання завдання
  • У кожному завданні має бути своя галузь
  • Злиття назад у магістраль потрібно авторизувати (як правило, через bugzilla)
  • У періоди, коли потрібен високий рівень контролю, злиття може здійснювати воротар

Загалом, це працює. SVN можна використовувати для такого потоку, але він не є ідеальним. Є деякі аспекти SVN, які перешкоджають і формують поведінку людини. Це дає йому деякі негативні аспекти.

  • У нас було досить багато проблем з людьми, що розгалужуються на точки нижче ^/trunk . Це засмічення записів інформації про злиття по всьому дереву і врешті-решт порушує відстеження об'єднання. Починають з'являтися помилкові конфлікти, і панує плутанина.
  • Збирання змін зі стовбура у гілку відносно прямо. svn mergeробить те, що ти хочеш. Об’єднання змін назад вимагає (нам сказано) --reintegrateкоманди злиття. Я ніколи по-справжньому не розумів цей перемикач, але це означає, що гілку неможливо знову об'єднати в стовбур. Це означає, що це мертва гілка, і ви повинні створити нову, щоб продовжувати роботу. (Див. Примітку)
  • Вся справа щодо операцій на сервері через URL-адреси при створенні та видаленні гілок дійсно бентежить і лякає людей. Так вони уникають цього.
  • Перемикання між гілками легко помилитися, залишаючи частину дерева дивлячись на гілку А, а іншу частину дивлячись на гілку В. Тож люди вважають за краще робити всю свою роботу в одній гілці.

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

  • Об’єднавши свою довгоживучу гілку назад у стовбур і вирішивши всі конфлікти, і випустити незв'язаний код, який повинен був бути в окремій гілці, але не був.
  • Видалення його відділення
  • Створення нової філії
  • Перехід його робочої копії на нову гілку

... і оскільки інженер робить це якомога менше, вони не можуть згадати "магічну заклик" робити кожен крок. Трапляються помилкові комутатори та URL-адреси, і раптом вони заплутані, і вони йдуть за допомогою "експерта".

Врешті-решт все стихає, і люди вчаться вирішувати недоліки, але кожен новий стартар переживає ті самі проблеми. Можлива реальність (на відміну від того, що я виклала на його початку):

  • На багажнику не виконується жодна робота
  • У кожного розробника є одна основна галузь
  • Відділення тривають до тих пір, поки роботу не потрібно звільнити
  • Виправлені помилки з відмітками, як правило, отримують власну гілку
  • Злиття назад у багажник здійснюється за умови авторизації

... але ...

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

На щастя, команда досить мала, щоб впоратися, але вона не змогла б розширити масштаб. Річ у тому, що нічого з цього не є проблемою з CVCS, але більше того, тому що злиття не так важливі, як у DVCS, вони не такі гладкі. Це "тертя злиття" викликає поведінку, а це означає, що модель "Відділення функції" починає руйнуватися. Хороші злиття повинні бути особливістю всіх VCS, а не лише DVCS.


Відповідно до цього , тепер є --record-onlyперемикач, який можна використовувати для вирішення --reintegrateпроблеми, і, мабуть, v1.8 вибирає, коли робити реінтеграцію автоматично, і це не призводить до того, що гілка згодом буде мертвою.


Як я розумію, параметр --reintegrate повідомляє svn, що ви вже вирішили суперечливі зміни під час об'єднання на гілку функцій. Ефективно, замість того, щоб трактувати його як патч, він перезаписує цілі файли з версією гілки, попередньо перевіривши в історії злиття, що всі ревізії стовбурів були об'єднані у гілку.
IMSoP

@IMSoP: можливо, це має певний сенс. Це не пояснює мені, чому це було потрібно чи чому він зробив неможливим подальше злиття з цією гілкою. Не допомогло і те, що варіант був значною мірою недокументований.
Пол S

Я коли-небудь використовував його через TortoiseSVN, де це завжди було чітко пояснено в інтерфейсі злиття. Я вважаю, що SVN 1.8 автоматично вибирає правильну стратегію і не потребує окремої опції, але я не знаю, чи виправили вони звичайний алгоритм злиття для коректної роботи з гілкою, яка була скинута таким чином.
IMSoP

3

До субверсії 1.5 (якщо я не помиляюсь), підривна дія мала суттєвий недолік у тому, що вона не пам’ятатиме історії злиття.

Давайте розглянемо викладений VonC випадок:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - A - x (v2-only)
           \
             x - B - x (wss)

Помітьте версії A і B. Скажіть, що ви об'єднали зміни з версії A на "wss" гілці до "v2-тільки" гілки в редакції B (з будь-якої причини), але продовжували використовувати обидві гілки. Якщо б ви спробували знову об'єднати дві гілки за допомогою mercurial, це змінило б лише зміни після модифікацій A і B. З підривною дією вам доведеться об'єднати все, як ніби ви раніше не зробили злиття.

Це приклад з мого власного досвіду, коли злиття від B до A зайняло кілька годин через об'єм коду: це було б справжнім болем знову переживати , що було б у випадку з підривною роботою до 1,5.

Ще одна, напевно, більш відповідна відмінність поведінки злиття від Hginit: Subversion Re-Education :

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

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

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

Коротше кажучи, спосіб аналізу різниць Меркуріалу (був?) Перевершує підривний.


5
я читав hginit. занадто погано, що він не показує більш практичних прикладів того, де Hg справляється краще, ніж svn. прості приклади, які він показав, можливо, можна зробити і зі svn. Насправді саме тому я відкрив це питання.
stmax

1
Виходячи з того, як це сказано, на думку нападає наївне питання: що робити, якщо алгоритм злиття Меркуріала було введено в Subversion? Тоді б svn був такий же гарний, як hg? Ні, оскільки перевага hg полягає в організації вищого рівня, а не низькому рівні текстової математики об'єднання рядків з файлів. Це нова ідея, яку ми повинні використати для всіх користувачів.
DarenW

@stmax: Я бачу, що ти маєш на увазі. Однак думка Джоела чи когось іншого насправді не має значення: одна технологія або краща за іншу (для набору випадків використання), або ні. @DarenW та @stmax: з мого власного досвіду Hg виграє руками завдяки розподіленій роботі (я весь час не підключений), продуктивності (безлічі локальних операцій), надзвичайно інтуїтивному розгалуженню, наділеному вищим алгоритмом злиття, hg відкат, шаблонований вихід журналу, hg glog, одиночна .hg папка ... Я міг би просто продовжувати, і вперед, і все, що завгодно, крім, можливо, git та базар відчувають себе прямо.
Томіслав Накіч-Альфіревич

Коментар hg, цитований про "набори змін", здається мені досить неточним. SVN прекрасно знає, які зміни відбувається при злитті (зміна - це в основному різниця між двома знімками, і навпаки, правда?), І може застосовувати кожен із них по черзі, якщо цього забажає; звичайно, нічого не треба «здогадуватися». Якщо це робить "один великий нечесний безлад", то це проблема впровадження, а не нічого принципового для дизайну. Основна проблема, яку важко вирішити поверх поточного дизайну архітектури - це переміщення / копіювання / перейменування файлів.
IMSoP
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.