Я читал в Joel на программном обеспечении:
С распределенным управлением версиями распределенная часть является на самом деле не самой интересной частью.
Интересная часть - то, что эти системы думают с точки зрения изменений, не с точки зрения версий.
и в HgInit:
Когда мы должны объединиться, Подверсия пытается посмотреть на оба изменения — мой измененный код и Ваш измененный код — и она пытается предположить, как разбить их вместе в одной большой безобразной путанице. Это обычно перестало работать, производя страницы и страницы “конфликтов слияния”, которые не являются действительно конфликтами, просто места, где Подверсии не удалось выяснить то, что мы сделали.
В отличие от этого, в то время как мы работали отдельно в Подвижном, Подвижное было занято, сохранив серию changesets. И так, то, когда мы хотим объединить наш код вместе, Подвижный на самом деле, имеет намного больше информации: это знает то, что каждого из нас измененный и может повторно применить те изменения, вместо того, чтобы просто смотреть на конечный продукт и пытаться предположить, как соединить его.
Путем рассмотрения папки репозитория SVN у меня есть впечатление, что Подверсия поддерживает каждого изменения как changeset. И от того, что я знаю, Hg использует и changeset и снимок, в то время как Мерзавец просто использует снимок, чтобы хранить данные.
Если мое предположение корректно, то должны быть другие пути, которые делают слияние в DVCS легким. Что это?
* обновление:
Проверьте также, Как и/или почему объединяется в Мерзавце лучше, чем в SVN?
В Git и других DVCS слияние легко не из-за мистической серии наборов изменений (если только вы не используете Darcs с его теорией патчей или какую-нибудь DVCS, вдохновленную Darcs; их, правда, меньшинство), о которой рассказывает Джоэл, а из-за отслеживания слияний и более фундаментального факта, что каждая ревизия знает своих родителей. Для этого вам нужны (я думаю) коммиты по всему дереву / всему хранилищу... что, к сожалению, ограничивает возможность делать частичные проверки и делать коммит только для подмножества файлов.
Когда каждая ревизия (каждый коммит), включая коммиты слияния, знает своих родителей (для коммитов слияния это означает иметь/помнить более одного родителя, т.е. merge tracking), вы можете построить диаграмму (DAG = Direct Acyclic Graph) истории ревизий. Если вы знаете граф ревизий, вы можете найти общего предка коммитов, которые вы хотите объединить. А когда ваш DVCS сам знает, как найти общего предка, вам не нужно указывать его в качестве аргумента, как, например, в CVS.
Обратите внимание, что у двух (или более) коммитов может быть более одного общего предка. Git использует так называемую "рекурсивную" стратегию слияния, которая объединяет базы слияния (общего предка), пока не останется один виртуальный / эффективный общий предок (в некотором упрощении), и вы сможете выполнить простое трёхстороннее слияние.
Git использует обнаружение переименований было создано для того, чтобы иметь возможность работать со слияниями, включающими переименования файлов. (Это поддерживает аргумент Jörg W Mittag, что DVCS имеют лучшую поддержку слияния, потому что они должны были иметь её, так как слияния происходят гораздо чаще, чем в CVCS с её слиянием, скрытым в команде 'update', в рабочем процессе update-then-commit, например Understanding Version Control (WIP) Eric S. Raymond).
В DVCS нет ничего особенного, что облегчало бы слияние. Это просто культурно: DVCS вообще не работал бы , если бы слияние было трудным, поэтому разработчики DVCS вкладывают много времени и усилий, чтобы упростить слияние. Пользователи CVCS OTOH привыкли к дерьмовому слиянию, поэтому у разработчиков нет стимула заставить его работать. (Зачем делать что-то хорошее, если ваши пользователи одинаково хорошо платят вам за что-то дерьмо?)
Линус Торвальдс сказал в одном из своих выступлений на Git, что, когда он использовал CVS в Transmeta, они выделяли целую неделю во время цикла разработки для слияния. И все просто восприняли это как нормальное положение вещей. В настоящее время во время окна слияния Линус выполняет сотни слияний всего за несколько часов.
CVCS могли бы иметь такие же хорошие возможности слияния, как и DVCS, если бы пользователи CVCS просто обратились к своим поставщикам и сказали, что эта чушь неприемлема. Но они пойманы парадоксом Блаба: они просто не знают , что это неприемлемо, потому что они никогда не видели работающей системы слияния. Они не знают, что есть что-то лучшее.
И когда они действительно пробуют DVCS, они волшебным образом приписывают все достоинства части "D".
Теоретически, из-за централизованного характера, CVCS должна иметь лучшие возможности слияния, потому что они имеют глобальное представление всей истории , в отличие от DVCS, где у каждого репозитория есть только крошечный фрагмент.
Напомним: весь смысл DVCS состоит в том, чтобы иметь много децентрализованных репозиториев и постоянно объединять изменения туда и обратно. Без хорошего слияния DVCS просто бесполезен. Однако CVCS все еще может выжить при неудачном слиянии, особенно если поставщик может заставить своих пользователей избегать ветвления.
Так что, как и все остальное в программной инженерии, это вопрос усилий.
Возможно, пользователи DVCS просто никогда не делают вещи, которые усложняют слияние, например рефакторинги, которые изменяют и переименовывают / копируют большинство файлов в проекте, или перепроектируют из stratch API, которые используются в сотнях файлов.
Вау, атака эссе из 5 параграфов!
Короче говоря, ничто не облегчает задачу. Это трудно, и мой опыт показывает, что ошибки случаются. Но:
DVCS заставляет вас иметь дело с объединением, а это значит, что вам придется потратить несколько минут на ознакомление с инструментами, которые существуют, чтобы помочь вам. Уже одно это помогает.
DVCS поощряет вас к частому объединению, что тоже помогает.
Фрагмент hginit, который вы процитировали, утверждающий, что Subversion не может делать трехстороннее слияние и что Mercurial делает слияние, просматривая все наборы изменений в обеих ветках, просто неверен по обоим пунктам.
Одна вещь, которую я нахожу более простой в DVCS - это то, что каждый разработчик может сливать свои собственные изменения в любой репозиторий по своему усмотрению. Гораздо проще справляться с конфликтами слияния, когда вы сливаете свой собственный код. Я работал в местах, где какая-то бедная душа исправляла конфликты слияния, находя каждого разработчика, участвовавшего в конфликте.
Также с DVCS вы можете делать такие вещи, как клонирование репозитория, слияние работы двух разработчиков в клоне, тестирование изменений, затем слияние из клона обратно в основной репозиторий.
Довольно крутая штука.
Частично причина, конечно, в техническом аргументе, что DVCSes хранит больше информации, чем SVN (DAG, копирует ), а также имеет более простую внутреннюю модель, поэтому она может выполнять более точные слияния, как упоминалось в других ответах.
Однако, вероятно, еще более важным отличием является то, что, поскольку у вас есть локальный репозиторий, вы можете делать частые небольшие коммиты, а также часто извлекать и объединять входящие изменения. Это вызвано больше «человеческим фактором», различиями в том, как человек работает с централизованной VCS по сравнению с DVCS.
С SVN, если вы обновляете и возникают конфликты, SVN объединяет то, что может, и вставляет маркеры в ваш код, где это невозможно. Большая проблема заключается в том, что ваш код больше не будет находиться в рабочем состоянии, пока вы не разрешите все конфликты.
Это отвлекает вас от работы, которую вы пытаетесь выполнить, поэтому обычно пользователи SVN не объединяются, пока они работают над задачей. Добавьте к этому тот факт, что пользователи SVN также склонны позволять изменениям накапливаться в одном большом коммите из страха сломать рабочие копии других людей, и между ветвлением и слиянием будут большие промежутки времени.
С Mercurial вы можете гораздо чаще объединять входящие изменения между вашими небольшими инкрементными коммитами.Это по определению приведет к меньшему количеству конфликтов слияния, потому что вы будете работать над более современной кодовой базой.
И , если окажется конфликт, вы можете отложить слияние и сделать это на досуге. Это, в частности, делает слияние менее утомительным.
Я думаю, что DAG наборов изменений, как упоминалось другими, имеет большое значение. DVCS: es требует разбиения истории (и слияний) на фундаментальном уровне, тогда как я полагаю, что CVCS: es (которые старше) были созданы с первого дня для отслеживания ревизий и файлов в первую очередь, а поддержка слияния добавляется в качестве запоздалой мысли.
Итак:
Смешивание этих концепций (как это делает Subversion), я полагаю, является большой ошибкой. Например, в исходном дереве есть ветки / теги, поэтому вам нужно отслеживать, какие версии файлов были объединены с другими файлами. Это явно более сложно, чем просто отслеживать, какие ревизии были объединены.
Итак, резюмируя:
По крайней мере, это то, что я чувствую из моего опыта работы с cvs, svn, git и hg. (Вероятно, есть и другие CVCS: es, которые тоже правильно поняли.)
Один момент заключается в том, что слияние svn слегка нарушено; см. http://blogs.open.collab.net/svn/2008/07/subversion-merg.html Я подозреваю, что это связано с svn-записью mergeinfo даже при слиянии с отбором вишен. Добавьте несколько простых ошибок в обработке пограничных случаев, и svn в качестве текущего дочернего элемента CVCS заставляет их выглядеть плохо, в отличие от всех DVCS, которые только что сделали это правильно.