Есть ли разница между слияниями в svn по сравнению с git или mercurial?

12

Насколько я понимаю, SVN «Легко разветвляться. Сложно объединить ». Это почему? Есть ли разница, как они сливаются?


источник

Ответы:

21

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

Что касается ответа tdammers, то здесь есть ряд недоразумений:

  • Subversion, Mercurial и Git отслеживают моментальные снимки проекта в масштабах репозитория. Называть их версиями , ревизиями или наборами изменений не имеет значения. Все они являются логически атомарными снимками набора файлов.

  • Размер ваших коммитов не имеет значения, когда дело доходит до слияния. Все три системы объединяются с помощью стандартного алгоритма трехстороннего объединения, и входные данные для этого алгоритма

    • версия общего предка
    • версия на одной ветке
    • версия на другой ветке

    Это не имеет значения , как были созданы две версии ветви. Вы можете использовать 1000 небольших коммитов начиная с версии предка, или вы можете использовать 1 коммит. Все, что имеет значение, является окончательной версией файлов. (Да, это удивительно! Да, многие руководства DVCS делают это ужасно неправильно.)

Он также поднимает некоторые хорошие моменты о различиях:

  • В Subversion есть некое «вуду», из которого вы можете слиться /trunk, скажем, в /branches/foo. Mercurial и Git не используют эту модель - вместо этого ветки моделируются непосредственно в истории. Поэтому история становится ориентированным ациклическим графом, а не линейным. Это гораздо более простая модель, чем та, которая используется Subversion, и это отсекает ряд угловых случаев.

  • Вы можете легко отложить слияние или даже позволить кому-то другому справиться с этим. Если у hg mergeвас возникнет масса конфликтов, то вы можете попросить своего сотрудника hg pullот вас, и тогда у него точно такое же состояние. Так что он может hg mergeи, возможно, он лучше разрешает конфликты, чем вы.

    Это очень трудно с Subversion, где вам необходимо обновить, прежде чем вы сможете зафиксировать. Вы не можете просто игнорировать изменения на сервере и продолжать фиксировать в своей собственной анонимной ветке. В общем, Subversion заставляет вас играть с грязной рабочей копией, когда вы svn update. Это довольно рискованно, поскольку вы нигде не хранили свои изменения в безопасности. Git и Mercurial позволяют сначала фиксировать, а затем обновлять и объединять по мере необходимости.

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

Мартин Гайслер
источник
4
отличный ответ! Я бы проголосовал дважды, если бы мог. :) Я бы также добавил, что книга SVN, на которую вы ссылаетесь в SO-ответе, прямо признает, что «функция отслеживания слияний в Subversion имеет чрезвычайно сложную внутреннюю реализацию ...» - это уже одно довольно хорошее свидетельство того, что эта функция ненадежна
Гнат
2
... и даже с такой чрезвычайно сложной реализацией не удается правильно определить общего предка ни в одном, кроме простых случаев.
Ян Худек
О отложенных слияниях - не получайте - с SVN мой коллега может обновить ствол / checkout, а затем слиться с ним из моей ветви.
Джилл Бейтс,
@GillBates: я говорю о ситуации, когда вы еще не создали ветку для своей работы - когда вы работаете trunkв SVN. С DVCS вы можете фиксировать без совместного использования, но в SVN вы svn commitбудете напрямую влиять на тех, кто работает в той же ветке. Даже если мы вдвоем работаем над веткой в ​​SVN, я не могу зафиксировать свою работу без необходимости немедленно сливаться с вашей работой. Это делает коммиты несколько пугающими - а это страшное свойство для системы контроля версий! :-)
Мартин Гайслер
6

Основная проблема заключается в том, как эти системы представляют версионную структуру каталогов.

Основная концепция Subversion, вокруг которой вращается вся система, - это версия (или, в svn lingo, «revision»): снимок файла в определенной точке. Пока история совершенно линейна, все в порядке, но если вам нужно объединить изменения из двух независимых линий разработки, svn должен сравнить текущие версии обеих версий, а затем провести трехстороннее сравнение между последней общей версией и две версии головы. Линии, которые кажутся измененными в одной из голов, но не в другой, могут быть легко решены; линии, которые одинаково отклоняются в обеих головках, более жесткие, но обычно выполнимые; линии, которые отличаются по-разному, заставляют svn сказать: «Я не могу понять это, человек, пожалуйста, разреши это для меня».

Напротив, git и mercurial отслеживают изменения, а не версии. Весь репозиторий представляет собой дерево наборов изменений, каждое из которых зависит от родителя, где родительский набор изменений может иметь любое количество дочерних элементов, а корень дерева представляет собой пустой каталог. Другими словами, git / hg говорит: «сначала у меня ничего не было, затем был применен этот патч, затем этот патч и т. Д.». Когда вам нужно объединить две линии разработки, git / hg не только знает, как выглядит каждая голова в данный момент и как выглядела последняя распространенная версия, но и знает, как произошел переход, что позволяет осуществлять более умное слияние.

Еще одна вещь, которая облегчает объединение в DVCS, является косвенным следствием разделения концепций коммита и толчкаи разрешать всевозможные перекрестные слияния между любыми двумя клонами одного и того же хранилища в любое время. С svn люди, как правило, фиксируют большие наборы изменений с часто не связанными изменениями, потому что фиксация также является обновлением в центральном хранилище, которое затрагивает всех остальных членов команды; если вы совершите испорченную версию, все будут сердиться на вас. Поскольку в большинстве установок используется сетевой svn-сервер, фиксация также включает в себя перекачку данных по сети, что означает, что фиксация вносит значительную задержку в рабочий процесс (особенно, когда ваша рабочая копия устарела, и вы должны сначала извлечь). В git и mercurial фиксация происходит локально, и поскольку обе они очень эффективны при работе с локальными файловыми системами, обычно они завершаются мгновенно. В результате люди (как только они привыкнут к этому) совершают небольшие постепенные изменения, а затем, когда это работает, толкать дюжину или около того совершает за один раз. Затем, когда наступит время слияния, SCM будет иметь гораздо более подробную информацию и сможет лучше и эффективнее решать конфликты безопасно и автоматически.

И еще есть приятные детали, которые делают вещи еще проще:

  • Вы можете иметь несколько голов и при этом совершать коммиты; в отличие от Subversion, вам не нужно объединять pull, update и merge перед повторной фиксацией - несколько голов остаются такими же, пока вы не решите объединить
  • Каталоги не обрабатываются специально; вместо этого путь считается одним большим именем файла, и все ваши каталоги должны всегда иметь одну и ту же ревизию. Это означает, что вы не можете выполнять вуду subversion, когда подпапки проекта находятся в разных ревизиях, но это также означает, что рабочая копия с меньшей вероятностью станет огромным неуправляемым разбитым беспорядком, и что более интересно, шаг не представлен как удаление -and-add (который полностью сломался бы в svn, если бы не метаданные для модификации), но просто как переименование; если вы перемещаете файл, вся его история сохраняется; объединение может даже применить изменения к перемещенному файлу, которые были сделаны в неизмененной версии того же файла после перемещения в другой ветви
  • В большинстве случаев вам даже не нужно выполнять ветвление: вместо этого вы просто клонируете весь репозиторий. Клонирование дешево, особенно если оно выполняется в той же файловой системе, и если вы решите, что хотите избавиться от клона, вы просто удалите каталог, в котором он находится, и все. Вам даже не нужно использовать hg или git для этого.
  • Есть несколько (если таковые имеются) ограничения на то, что вы можете объединить. Вы можете иметь шесть клонов одного и того же хранилища и объединить (или, скорее, push или pull; явное объединение часто не требуется) из A в B, затем из C в B, затем из B в D, затем из C в D, B обратно на A, D на E, в любое время и так часто, как вам нравится.
  • Вы можете проверить слияние, клонировав одно из хранилищ, которое вы хотите слить, и затем вытянув его из другого. Если он делает то, что вы хотите, вы можете вернуться к реальной цели, если это не так, вы выбрасываете клона и начинаете заново.
tdammers
источник
2
Я должен упомянуть некоторые исправления и добавления к ответу: 1. Ревизии SVN являются глобальными для каждого хранилища , ревизии представляют все файлы в репо в какой-то момент 2. Технология слияния в основном распространена в SVN и DVCS - если файл в файлах слияния только изменяет Точно так же слияние вызовет одинаковое количество конфликтов для SVN и DVCS - все SCM по-прежнему работают на строковом уровне, а не на логическом блоке 3. Большие коммиты в SVN не являются результатом слабости архитектуры, а потому, что пользователи часто являются ленивыми идиотами - они игнорируют основные закономерности. Branch | merge работает в SVN, если / dev / brain и / dev / hands работают
Lazy Badger
2
Часть 2: Интеллектуальное слияние в DVCS в основном происходит потому, что, в отличие от Subversion, они отслеживают и обрабатывают перемещения | переименовывает файлы, а SVN вообще не делает этого, поэтому - любая операция, которая обрабатывает файл, изменяется на одной стороне и переименовывается на во-вторых, потерпит неудачу. Ветвление ветвями и клонирование - это просто разные стратегии ветвления с одинаковыми правами на жизнь, которые используют «... зависит от ...»
Ленивый барсук
@LazyBadger: Au противоречит. Subversion делает трек движется / переименовывает, что вызывает ложные конфликты отчасти потому , что это обращение с ними переименований в слиянии просто глючит и отчасти потому , что есть случаи , угловые , которые трудно или невозможно правильно обрабатывать. Последнее объясняет, почему Git (и Mercurial скопировал его) по своему дизайну не отслеживает переименования и угадывает их при слиянии. Что отлично работает, если содержимое все еще достаточно схоже, чтобы его можно было объединить (когда вам это нужно), и не делает глупостей иначе.
Ян Худек
@JanHudec - извините, дескриптор SVN не перемещается | переименовывает в элементарное одно действие (путь DVCS - «переименовать»), но, как «delete + ...», таким образом - создает конфликты дерева, где это не происходит в DVCS ( истинное переименование) ). Mercurial дорожка переименовывает явно ( hg mvили hg addremove --similarity...), в то время как Git использует эвристику, но обе обрабатывают переименования . Я могу получить конфликт дерева даже с разницей в 1 строку в объединенных файлах! Вы должны заново изучить некоторые аспекты Subversion, извините.
Ленивый барсук
5
Теперь мы получаем техническую информацию :-) Копии треков Subversion и Mercurial , а не переименования. Обе системы отслеживают rename a bкак copy a b; remove aи обе делают это за один атомный коммит. Различие в поведении слияния связано с различной обработкой угловых случаев и с Subversion, допускающим больше слияний, чем Mercurial и Git. Наконец, Git обнаруживает переименования во время слияния и регистрации - мы думаем добавить это и в Mercurial.
Мартин Гайслер