Отделение от филиала, реинтеграция слияния и слияния

У меня есть ветвь A, запущенная из магистрали, и ветвь B, начатая из A. Периодически выполняется слияние из магистрали в A, а затем также выполняется слияние из A в B. Когда я хочу объединить A и B в магистраль, я думаю, что следовать следующим образом:

  • реинтегрировать слияние из B в A
  • реинтегрировать слияние от А до ствола

Это правильно? Или это может вызвать проблемы с Mergeinfo или другие проблемы? Какова лучшая практика в этом случае?

1 ответ

Решение

Subversion была (иногда несправедливо) подвергнута критике за плохое слияние. По правде говоря, Subversion действительно хорош в слиянии. Чтобы понять, что вам нужно сделать, вам нужно понять, как Subversion выполняет слияние.

Обычно Subversion, вроде (что я объясню позже), выполняет стандартное трехстороннее слияние. Он сравнивает два файла, которые были объединены с последним предком этих двух файлов. Таким образом, он может сказать, какие изменения в файле произошли из ветви, в которой он находится, и какие изменения произошли из другой ветви.

Потому что ветвь "B" происходит от ветки "A", которая пришла из ствола. Вы можете слить из транка в B или транка в A. Эти слияния должны работать очень хорошо. Если вы объединяете определенный набор изменений из ветки B или A в транк или в другую ветку, все должно работать нормально.

Теперь я сказал (вроде) выполняет стандартное трехстороннее слияние. Subversion была написана, чтобы позволить вам указать конкретный набор изменений, которые вы сделали в одной ветви, чтобы объединить с другой. Когда вы объединяете, Subversion не смотрит на файл, который вы объединяете, он начинает с базы, последнего общего предка, затем применяет те изменения, которые рассматриваются для объединения. В этих условиях, когда вы указываете, что именно вы хотите объединить, Subversion делает замечательную работу по слиянию.

Поэтому, если вы указываете, что у ветви "A" есть конкретное изменение, и вы хотите объединить это изменение с веткой "B" или с внешней линией, Subversion прекрасно справляется с объединением.

Ситуация начала меняться в Subversion 1.5, когда Subversion начала отслеживать ревизии репозитория, которые ранее были объединены в ветку или транк. Это не позволило мне объединить изменения, ранее слитые с веткой, но также позволило мне быть ленивым. Нет ничего плохого в том, чтобы быть ленивым. Я очень одобряю это.

Представьте, что я делаю функциональную ветку на ревизии 100 из ствола. Я делаю ветку на ревизии 100. Допустим, это список ревизий, сделанных в моем репо:

  • Филиал: 103 105 108
  • Багажник: 101 102 104 105 106 107

Когда я сливаюсь из транка в свою ветку компонентов и не указываю, какие ревизии я хочу слить, Subversion делает выбор вишни для меня. Он знает, что последним общим предком была ревизия 100. Затем он смотрит и видит, что изменения в стволе ревизии 101, 102, 104, 105, 106 и 107 не были применены к моей ветви. Затем вишня выбирает эти конкретные изменения и объединяет их с моей веткой.

  • Филиал: 103 105 108 109
  • Багажник: 101 102 104 105 106 107

Редакция 109 - результат моего слияния. Для отслеживания изменений Subversion помещает в Revision 109 a svn:mergeinfo свойство, которое говорит ствол: 101-107 были объединены на ветви:. Давайте сделаем больше работы:

  • Филиал: 103 105 108 109 110 111
  • Багажник: 101 102 104 105 106 107 112 113

Я хочу снова слиться из моего ствола в мою ветку. Если бы я не был ленивым, я бы указал, что хочу, чтобы редакции 112 и 113 были объединены с моей веткой. Однако, будучи ленивым, я позволил Subversion сделать работу. Subversion видит из svn:mergeinfo что все ревизии магистрали от 101 до 107 уже слиты в мою ветку. Поэтому Subversion выбирает для меня ревизии 112 и 113:

  • Филиал: 103 105 108 109 110 111 114
  • Багажник: 101 102 104 105 106 107 112 113

И Subversion создает ревизию 114 и устанавливает svn:mergeinfo сказать, что все изменения в стволе от ревизии 101 до ревизии 113 были объединены с моей веткой.

Теперь я закончил свою функцию, и я хочу объединить все свои изменения, которые я сделал в моей ветви, обратно в мой ствол. Если бы я не был таким ленивым задом, я бы уточнил, что я хочу, чтобы ревизии 103, 105, 108, 110 и 111 были объединены с моим стволом. Если бы я это сделал, проблем не было бы совсем. Subversion прекрасно справляется со слиянием.

Обратите внимание, что я не указал, что я хочу, чтобы изменения 109 и 114 были объединены (два изменения выделены жирным шрифтом). Зачем? Поскольку это не были изменения в моей ветке, это были изменения ствола, которые я слил в свою ветку. Если бы я указал эти две ревизии, я бы снова применил свои изменения в сундуке обратно на мой сундук.

Но я ленивый и хочу, чтобы Subversion сделала всю работу за меня. Subversion смотрит на мою ветку и видит все эти изменения, включая изменения 109 и 114, и хочет объединить их с моим стволом. Нехорошо.

Итак, Subversion делает что-то особенное здесь. Если мы рассматриваем файл и ревизии как наборы изменений для применения к файлу, я в основном применяю все изменения, которые произошли в моей стволе, к моей ветви и все эти изменения в моей ветви к моей стволу. Другими словами, когда я завершу слияние этой ветви с магистралью, моя ветвь и моя магистраль будут совпадать.

Это то, что делает слияние реинтеграции. В отличие от обычного слияния, когда изменения из моих двух файлов сравниваются с базовой ревизией и затем тщательно применяются, все изменения в моей ветви будут применены к моей стволу, не сравнивая его с базовой ревизией. Слияние с реинтеграцией - это двустороннее слияние. Любая разница между веткой и стволом будет перезаписана.

Давайте посмотрим, что происходит:

До слияния реинтеграции

  • Филиал: 103 105 108 109 110 111 114
  • Багажник: 101 102 104 105 106 107 112 113

  • svn:mergeinfo на ветке сейчас говорит trunk:101-113

После реинтеграции слияния

  • Филиал: 103 105 108 109 110 111 114
  • Багажник: 101 102 104 105 106 107 112 113 115

  • svn:mergeinfo на ветке сейчас говорит trunk:101-113

  • svn:mergeinfo на стволе сейчас говорит branch:103-114

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

  • Филиал: 103 105 108 109 110 111 114
  • Багажник: 101 102 104 105 106 107 112 113 115 116 117

  • svn:mergeinfo на ветке сейчас говорит trunk:101-113

  • svn:mergeinfo на стволе сейчас говорит branch:103-114

Теперь я хочу объединить эти изменения с моей веткой функций. Если бы я сам собирал вишню, я бы указал, что я хочу, чтобы редакции 116 и 117 были на моей ветке, потому что это были те два изменения, которые я только что сделал. Опять же, если бы я был прилежным и трудолюбивым, слияние Subversion было бы хорошо. Тем не менее, я ленив и позволю Subversion сделать сбор вишни.

Subversion смотрит на svn:mergeinfo и видит, что я применил изменения 103 к 114 на свою ветку. Теперь он видит три новых изменения в моем стволе: изменения 115, 116 и 117. Однако изменение 115 является результатом моего слияния реинтеграции! Все изменения в 115 уже на ветке. Если позволить Subversion сделать сбор, это приведет к катастрофе.

Вот почему вам сказали не использовать ветку после ее реинтеграции. Способ обойти это сделать svn merge --record-only -c 115 из ствола на мою ветку. На самом деле никакого объединения не произойдет, но теперь Subversion будет записывать, что изменения с 101 по 115 находятся в моей ветке. Если бы я сделал это, а затем произвел слияние из транка в ветку, Subversion пропустил бы выбор изменения 115 и сделал бы только изменения 116 и 117.


Теперь, когда вы понимаете, как Subversion осуществляет отслеживание слияний и что такое слияние реинтеграции, мы можем рассмотреть вашу ситуацию:

  • Вы разветвились от ствола до ответвления А
  • Вы разветвились от ветви A до ветви B
  • Вы сливаетесь из магистрали в ветвь А
  • Вы сливаетесь из ветви A в ветку B

Если вы трудолюбивый молодой программист, который просыпается каждое утро в 5 часов утра, чтобы пробежать 5 миль, просто чтобы поднять вам настроение на работу, вы укажете, какие ревизии из каждой ветви вы хотите объединить с другими ветками или стволом. Если вы это сделали, проблем нет вообще, вы выполняете стандартное слияние и готовитесь к ежедневной 100-километровой поездке на велосипеде, которую вы делаете после энергичной тренировки в тренажерном зале.

Если вы типичный технический работник (то есть ленивый) и хотите, чтобы Subversion управлял выбором ревизий для вас, все немного иначе:

  • Вы объединяете все свои изменения из ветви A в ветку B. Теперь ваша ветка B будет включать все ревизии в ветке A.
  • Вы выполняете слияние реинтеграции ветви B обратно в ветку A. Теперь все ваши изменения в ветке A и ветке B будут в обеих ветках.
  • Вы выполняете регулярное слияние своей соединительной линии с ответвлением А. В ответвлении А содержатся все ваши изменения, внесенные в ответвлении А. Плюс, все изменения в ответвлении В и соединительной линии.
  • Вы выполняете слияние реинтеграции ветви A (которая уже содержит изменения вашего филиала B) в ствол. Теперь магистраль, ветвь A и ветвь B содержат одинаковый набор изменений, и все три должны совпадать.
  • Теперь вы никогда не должны снова использовать Ветвь А или Ветвь Б, если только svn merge --record-only записать это изменение реинтеграции из ветви B в ветвь A в ветвь B, а изменение из ответвления A в магистраль в ветвь A.

Важное изменение в Subversion 1.8

Знание, делать ли регулярное слияние или слияние реинтеграции в Subversion, может быть немного подвержено ошибкам. Это ручной процесс, который может привести к катастрофе, если я, будучи нормальным человеком, совершу ошибку (что я сделаю в самый худший момент).

В Subversion 1.8 Subversion теперь пытается определить, посмотрев на svn:mergeinfo каким образом вы выполняете свое слияние и когда вам нужно сделать слияние реинтеграции. Таким образом, вам больше не нужно указывать --reintegration флаг при слиянии. Subversion также позаботится о том, чтобы, если вы повторно используете ветку после ее реинтеграции в другую ветку или ствол, не применять изменения, которые произошли во время реинтеграции.

Если вам нравится делать много ветвлений функций, вы должны использовать Subversion 1.8, которая будет обрабатывать большую часть ошибок в отслеживании слияний для вас. Если вы используете Subversion 1.8, вы должны иметь возможность выполнять слияния из ветви B в ветку A и в транк без каких-либо проблем.

Другие вопросы по тегам