Что делает объединение в DVCS простым?
Я прочитал в Джоэл о программном обеспечении:
С распределенным контролем версий распределенная часть на самом деле не самая интересная часть.
Интересно то, что эти системы думают с точки зрения изменений, а не с точки зрения версий.
и в HgInit:
Когда нам нужно объединить, Subversion пытается просмотреть обе ревизии - мой измененный код и ваш измененный код - и пытается угадать, как их объединить в одну большую нечестивую путаницу. Обычно это дает сбой, создавая страницы и страницы "конфликтов слияния", которые на самом деле не являются конфликтами, просто места, где Subversion не удалось выяснить, что мы сделали.
Напротив, пока мы работали отдельно в Mercurial, Mercurial был занят сохранением серии изменений. И поэтому, когда мы хотим объединить наш код, Mercurial на самом деле имеет гораздо больше информации: он знает, что каждый из нас изменил и может применить эти изменения, а не просто смотрит на конечный продукт и пытается угадать, как его поместить. все вместе.
Глядя на папку репозитория SVN, у меня складывается впечатление, что Subversion поддерживает каждую ревизию как набор изменений. И насколько я знаю, Hg использует и changeset, и snapshot, а Git использует только snapshot для хранения данных.
Если мое предположение верно, то должны быть другие способы, которые облегчают объединение в DVCS. Что это такое?
* Обновить:
- Меня больше интересует техническая перспектива, но ответы с нетехнической точки зрения приемлемы
- исправления:
- Концептуальная модель Git основана исключительно на снимках. Снимки могут быть сохранены в виде различий других снимков, просто они предназначены только для оптимизации хранения. - Комментарий Rafał Dowgird
- С нетехнической точки зрения:
- Это просто культурно: DVCS не будет работать вообще, если объединение будет сложным, поэтому разработчики DVCS вкладывают много времени и усилий в облегчение объединения. Пользователи CVCS OTOH привыкли к дурацкому слиянию, поэтому у разработчиков нет стимула заставить его работать. (Зачем делать что-то хорошее, когда ваши пользователи платят вам одинаково хорошо за что-то дерьмо?)
...
Напомним: весь смысл DVCS состоит в том, чтобы иметь много децентрализованных репозиториев и постоянно объединять изменения назад и вперед. Без хорошего слияния DVCS просто бесполезен. CVCS, однако, все еще может выжить с дерьмовым слиянием, особенно если поставщик может заставить своих пользователей избегать ветвления. - Jörg W Mittag 's ответ
- Это просто культурно: DVCS не будет работать вообще, если объединение будет сложным, поэтому разработчики DVCS вкладывают много времени и усилий в облегчение объединения. Пользователи CVCS OTOH привыкли к дурацкому слиянию, поэтому у разработчиков нет стимула заставить его работать. (Зачем делать что-то хорошее, когда ваши пользователи платят вам одинаково хорошо за что-то дерьмо?)
- С технической точки зрения:
- запись реального DAG истории действительно помогает! Я думаю, что главное отличие состоит в том, что CVCS не всегда регистрирует слияние как набор изменений с несколькими родителями, теряя некоторую информацию. - комментарий tonfa
- из-за отслеживания слияния и более фундаментального факта, что каждая ревизия знает своих родителей.... Когда каждая ревизия (каждая фиксация), включая коммиты слияния, знают своих родителей (для коммитов слияния, которые означают наличие / запоминание более одного родителя, т.е. отслеживание слияния), вы можете восстановить диаграмму (DAG = прямой ациклический график) ревизии история. Если вы знаете график ревизий, вы можете найти общего предка коммитов, которые вы хотите объединить. И когда ваша DVCS знает, как найти общего предка, вам не нужно предоставлять его в качестве аргумента, как, например, в CVS.
,
Обратите внимание, что может быть более одного общего предка двух (или более) коммитов. Git использует так называемую "рекурсивную" стратегию слияния, которая объединяет базы слияния (общий предок), пока у вас не останется один виртуальный / эффективный общий предок (в некотором упрощении) и может выполнить простое трехстороннее слияние. - ответ Jakub Narębski
Проверьте также, как и / или почему слияние в Git лучше, чем в SVN?
9 ответов
В Git и других DVCS слияния не просты не из-за какой-то мистической серии представлений наборов изменений (если только вы не используете Darcs с его теорией исправлений или некоторыми вдохновленными Darcs DVCS; хотя они и являются меньшинством), о которых Джоэл спотыкается, а потому что отслеживания слияний, и более фундаментальный факт, что каждая ревизия знает своих родителей. Для этого вам нужны (я думаю) коммиты из целого дерева / полного репозитория... которые, к сожалению, ограничивают возможность делать частичные проверки и делать коммит только с подмножеством файлов.
Когда каждая ревизия (каждая фиксация), включая коммиты слияния, знают своих родителей (для коммитов слияния, которые означают наличие / запоминание более одного родителя, т.е. отслеживание слияния), вы можете восстановить диаграмму (DAG = прямой ациклический график) истории ревизий. Если вы знаете график ревизий, вы можете найти общего предка коммитов, которые вы хотите объединить. И когда ваша DVCS знает, как найти общего предка, вам не нужно предоставлять его в качестве аргумента, как, например, в CVS.
Обратите внимание, что может быть более одного общего предка двух (или более) коммитов. Git использует так называемую "рекурсивную" стратегию слияния, которая объединяет базы слияния (общий предок), пока у вас не останется один виртуальный / эффективный общий предок (в некотором упрощении) и может выполнить простое трехстороннее слияние.
Git использовало обнаружение переименования, чтобы иметь дело с объединениями, включающими переименования файлов. (Это поддерживает аргумент Jörg W Mittag о том, что DVCS имеет лучшую поддержку слияний, потому что они должны были иметь это, поскольку слияния встречаются гораздо чаще, чем в CVCS с его слиянием, скрытым в команде "update", в рабочем процессе update-then-commit, cf Понимание версии Контроль (WIP) Эрик С. Раймонд).
В DVCS нет ничего особенного, что облегчает слияние. Это просто культурно: DVCS не будет работать вообще, если объединение будет сложным, поэтому разработчики DVCS вкладывают много времени и усилий в облегчение объединения. Пользователи CVCS OTOH привыкли к дурацкому слиянию, поэтому у разработчиков нет стимула заставить его работать. (Зачем делать что-то хорошее, когда ваши пользователи платят вам одинаково хорошо за что-то дерьмо?)
Линус Торвальдс сказал в одном из своих выступлений на Git, что когда он использовал CVS в Transmeta, они отводили целую неделю в течение цикла разработки для слияния. И все просто приняли это как нормальное положение дел. В настоящее время, во время окна слияния, Линус выполняет сотни слияний всего за несколько часов.
CVCS могли бы иметь такие же хорошие возможности слияния, как DVCS, если бы пользователи CVCS просто обращались к своим поставщикам и говорили, что это дерьмо неприемлемо. Но они застряли в парадоксе Blub: они просто не знают, что это неприемлемо, потому что они никогда не видели работающей системы слияния. Они не знают, что там что-то лучше.
И когда они действительно пробуют DVCS, они волшебным образом приписывают все добро части "D".
Теоретически, из-за централизованного характера, CVCS должна иметь лучшие возможности слияния, потому что они имеют глобальное представление всей истории, в отличие от DVCS, где каждое хранилище имеет только крошечный фрагмент.
Напомним: весь смысл DVCS состоит в том, чтобы иметь много децентрализованных репозиториев и постоянно объединять изменения назад и вперед. Без хорошего слияния DVCS просто бесполезен. CVCS, однако, все еще может выжить с дерьмовым слиянием, особенно если поставщик может заставить своих пользователей избегать ветвления.
Так что, как и все остальное в разработке программного обеспечения, это вопрос усилий.
Частично причиной является, конечно, технический аргумент, что DVCS хранят больше информации, чем SVN (DAG, копии), а также имеют более простую внутреннюю модель, поэтому она способна выполнять более точные слияния, как упоминалось в других ответах.,
Однако, вероятно, еще более важное отличие состоит в том, что, поскольку у вас есть локальный репозиторий, вы можете делать частые небольшие коммиты, а также часто извлекать и объединять входящие изменения. Это вызвано в большей степени "человеческим фактором", различиями в том, как человек работает с централизованной VCS по сравнению с DVCS.
С SVN, если вы обновляете и возникают конфликты, SVN объединит то, что может, и вставит маркеры в ваш код там, где это невозможно. Большая большая проблема в том, что ваш код больше не будет в работоспособном состоянии, пока вы не разрешите все конфликты.
Это отвлекает вас от работы, которую вы пытаетесь достичь, поэтому обычно пользователи SVN не объединяются, когда работают над задачей. Объедините это с тем фактом, что пользователи SVN также склонны позволять изменениям накапливаться в одном большом коммите из-за боязни взломать рабочие копии других людей, и между веткой и слиянием будут большие промежутки времени.
С Mercurial вы можете объединяться с входящими изменениями гораздо чаще между вашими небольшими добавочными коммитами. Это по определению приведет к меньшему количеству конфликтов слияния, потому что вы будете работать над более современной кодовой базой.
И если окажется, что возникнет конфликт, вы можете отложить слияние и сделать это на досуге. Это, в частности, делает слияние намного менее раздражающим.
Вау, атака из 5 пунктов эссе!
Короче говоря, ничто не облегчает. Это сложно, и мой опыт показывает, что ошибки все же случаются. Но:
DVCS вынуждает вас заниматься слиянием, а это значит, что вам потребуется несколько минут, чтобы ознакомиться с инструментами, которые существуют, чтобы помочь вам. Это само по себе помогает.
DVCS призывает вас часто объединяться, что тоже помогает.
Фрагмент hginit, который вы процитировали, утверждая, что Subversion не может выполнить трехсторонние слияния и что Mercurial объединяется, просматривая все наборы изменений в обеих ветвях, просто неверен в обоих случаях.
Суть в том, что слияние SVN слегка нарушено; см. http://blogs.open.collab.net/svn/2008/07/subversion-merg.html Я подозреваю, что это связано с svn, записывающим mergeinfo даже при слияниях по сбору вишни. Добавьте несколько простых ошибок в обработке граничных случаев, и svn как текущий дочерний элемент CVCS заставляет их выглядеть плохо, в отличие от всех DVCS, которые только что поняли это правильно.
Одна вещь, которую я нахожу проще с DVCS, состоит в том, что каждый разработчик может объединить свои собственные изменения в любое хранилище, которое они желают. Гораздо проще обрабатывать конфликты слияния, когда вы объединяете свой собственный код. Я работал в местах, где какая-то бедная душа исправляла конфликты слияний, находя каждого вовлеченного разработчика.
Также с DVCS вы можете делать такие вещи, как клонировать репозиторий, объединять работу двух разработчиков в клон, тестировать изменения, а затем сливать из клона обратно в основной репозиторий.
Довольно классные вещи.
Я думаю, что DAG наборов изменений, как уже упоминалось другими, имеет большое значение. Для DVCS:es требуется разделить историю (и слияния) на фундаментальном уровне, тогда как я предполагаю, что CVCS:es (более старые) были созданы с первого дня для отслеживания изменений и файлов в первую очередь, с поддержкой слияния, добавленной в качестве запоздалой мысли.
Так:
- Объединение легко выполнить и отслеживать, когда теги / ветви отслеживаются отдельно от дерева каталогов источников, поэтому весь репозиторий можно объединить за один раз.
- Поскольку DVCS:es имеют локальные репо, их легко создавать, поэтому оказывается, что легко хранить разные модули в разных репо, а не отслеживать их все в большом репо. (поэтому слияния всей репо не вызывают такие же сбои, как это было бы в svn/cvs, где одно репо часто содержит много не связанных модулей, которые должны иметь отдельную историю слияний.)
- CVS / SVN позволяет различным файлам в рабочем каталоге поступать из разных ревизий, в то время как DVCS: всегда имеет одну ревизию для всего WC, всегда (т.е. даже если файл будет возвращен к более ранней версии, он будет показан как измененный в статус, поскольку он отличается от файла в извлеченной ревизии. SVN/CVS не показывает это всегда.)
Я считаю, что смешивать эти понятия (как это делает Subversion) - большая ошибка. Например, имеет ветви / теги внутри исходного дерева, так что там вы должны отслеживать, какие версии файлов были объединены с другими файлами. Это явно сложнее, чем просто отслеживать, какие ревизии были объединены.
Итак, подведем итоги:
- DVCS: они нуждаются в простых слияниях, у них есть набор функций, основанный на этом. Решение принимается таким образом, чтобы эти слияния было легко выполнять и отслеживать (с помощью DAG), а другие функции (ветви / теги / подмодули) реализованы в соответствии с этим, а не наоборот.
- CVCS: es с самого начала имели некоторые функции (например, модули), которые упростили некоторые вещи, но сделали слияние в репо очень сложным для реализации.
По крайней мере, это то, что я чувствую из своего опыта с cvs, svn, git и hg. (Возможно, есть и другие CVCS: es, которые тоже правильно поняли)
Как историческая справка, ныне архаичная система PRCS также знает об общих предках и может эффективно объединяться, хотя она не была распределена (она была построена поверх файлов RCS!). Это означало, что его можно было эффективно перенести в git, сохранив при этом историю.
Возможно, пользователи DVCS просто никогда не делают вещи, которые затрудняют объединение, такие как рефакторинг, который изменяет и переименовывает / копирует большинство файлов в проекте, или редизайн из API-интерфейсов, которые используются в сотнях файлов.