Честно признаюсь, что долго не понимал, о чем идет речь, когда Subversion ругают за проблемы со слияниями бранчей. До сегодняшнего дня, когда мы на работе огребли довольно объемную проблемку. Хочу поделиться подробностями.

Задачка

Есть у нас средних размеров джанговский проект — "Куда Все Идут". В нем изначально, из-за нежелания плодить без надобности сущности, было одно глобальное приложение под неоригинальным названием "core". Недавно из-за разрастающихся планируемых фич нам захотелось разделить код на три приложения. Два со специфичной логикой — "social" и "content" — и одно с общей для всего проекта логикой — все тот же "core". Причем прямо сейчас часть "content" будет практически пустой, и по сути весь процесс заключается в отпочковывании части "social" от части "core".

При это мы находимся в такой ситуации, когда заморозить текущую разработку на месяц-другой нельзя, и поэтому мы решили сделать это разделение в отдельном бранче.

Бранчи

У нас получается, в итоге, два бранча:

Бранчи, безусловно, обязаны сильно разойтись, но ведь на то нам и нужна система контроля версий, чтобы это разруливать.

Слияние

И вот сегодня под вечер, когда magicsplit достиг своего работоспособного состояния, мы решили его влить в транк.

offline/trunk$ svn merge -r1489:HEAD https://.../magicsplit/ .

И накнулись на интересные, но от того не менее больно бьющие по лбу грабли.

Практически первое, что было сделано в magicsplit — это рядом с "core" была создана папка для нового приложения ("social"), в которую тут же был унесен практически весь код, который к этому приложению по логике относился. В частности, некоторые модели данных, практически все view'хи и шаблонные теги переехали в эту новую директорию. Дальше там происходила практически только отладка. А в это время в транке этот же самый код активно правился. Но в старых файлах внутри core.

Так вот, засада заключается в том, что Subversion, хоть и номинально знает, что, например, social/views.py переехал туда из core/views.py, никак эту информацию при слиянии не использует. И поэтому у нас слияние бранча оказалось практически пустым: изменения из транка влились в оставшуюся core/* и никак не слились с бранчевыми изменениями в social/*.

Варианты

Теперь, вот, не знаем, что делать. Варианты пока такие:

Что посоветует уважаемое сообщество?

Комментарии: 40

  1. Oleg Andreev

    Базаар - весьма глючная и тормозная хрень. Бери git, он специально для такого и создавался (трекает контент вцелом, а не пофайлово, т.е. знает что файл переехал в другую папку и сумеет примерджить изменения).
    Или Hg/mercurial (который, вроде, слизан с гита, но, говорят, медленнее и сложнее в использовании).

  2. Иван Сагалаев

    Базаар - весьма глючная и тормозная хрень.

    Олег, у тебя наверное данные примерно годовалой давности. Он сильно изменился с того времени. Кроме того, мне нужна от него вот эта одна конкретная вещь.

    Бери git

    Думал про это. Пока меня пугает то, что его надо долго изучать, чтобы начать пользоваться. А нам, по сути, это надо завтра :-). Кроме того, слышал, что ммпортом из svn у него какой-то убогий. Или нет?

  3. Всеволод Соловьёв

    Или Hg/mercurial (который, вроде, слизан с гита, но, говорят, медленнее и сложнее в использовании)

    Оба утверждения убивают наповал.

  4. Vooon

    Mercurial, как и Bazaar, написан на питоне, поэтому нет ничего странного что git быстрее примерно в два раза. Но велика ли разница длится коммит 1 секунду или 2-е? :)

    У меркуриала мне нравится что ссылка на репозитарий и веб-морду одна.

  5. DM

    Я бы попробовал на скорую руку посмотреть на результат применения bzr.

    Насчет быстродействия: если я правильно помню, то ставка у bzr была именно на юзабилити (и таки да, использовать его из консоли оказалось приятнее чем тот же svn), а потом догонялась скорость (начиная с версии 0.9 она заметно выросла; текущая - 1.6). Но скорость операций для проектов (в моем случае - на rails) меня устраивает более чем.

    Насчет скорости - сравнение.

  6. Роман Беликин

    Попробуй git-svn -ом выгрузить весь свой репозитарий и сделать слияние уже гитом. git должен корректно разрулить все перемещения файлов и смердживание бранчей даст то, что нужно.
    На всякий случай уточню: git от svn отличается помимо прочего еще и тем, что работает не с "рабочей папкой", а с локальной версией репозитария, т.е. вся история изменений доступна локально без сервера. А git-svn умеет выгружать и загружать все это с/на сервер svn.

  7. z-virus-z.ya.ru

    Попробуйте у народа с reactos.org спросить, они периодически с бранчами балуются.

  8. Всеволод Соловьёв

    Mercurial, как и Bazaar, написан на питоне, поэтому нет ничего странного что git быстрее примерно в два раза

    В два раза - это вы сами придумали? Тесты говорят совершенно о другом.

  9. Roman
        <p>Ситуация вообще очень неприятная. Кстати, о проблемах, которые возникнут у тех, кто захочет переименовывать и перемещать файлы в ветке, предупреждают и сами разработчики subversion  вот тут: [http://svnbook.red-bean.com/](http://svnbook.red-bean.com/) в главе 4, в п. "Merges and Moves"</p>
    

    The moral of this story is that until Subversion improves, be very careful about merging copies and renames from one branch to another.

    Получается, в рамках subversion нет другого способа, кроме как вручную перенести все изменения. Конечно, не совсем вручную ...

    Если бы меня заставили заниматься такими вещами, то я бы сделал примерно так:

    1. Перенес все изменения, сделанные в trunk-е, в ветвь. Упростить себе жизнь можно, воспользовавшись svn merge для каждого файла или каталога в отдельности, для чего перейти в каталог branches/magicsplit/social рабочей копии и выполнить в ней svn merge svn://.../trunk/core@START svn://.../trunk/core@END. Это сделает diff для изменении и применит его к текущему каталогу.

    2. Перенес все изменения (вместе с изменениями, сделаннами в ветви) обратно в trunk. Перейдя в trunk рабочей копии, выполнить
      svn merge svn://.../branches/magicsplit@START svn://.../branches/magicsplit@HEAD. Здесь START - это номер ревизии, начиная с которой произошло отпочкование.

    Я совсем не уверен, что этот способ будет наилучшим или вообще подходящим для вашего случая.

  10. dvk

    А можно попробовать svn 1.5 — там сильно починили merge-tracking и branch-merging.
    Вообще, перемещения файлов должны учитываться в svn при мерже. По крайней мере, у меня учитывались.

  11. Константин Коломеец

    Что посоветует уважаемое сообщество?

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

  12. Alexander Artemenko

    Могу попробовать сделать это через GIT. Поставил выкачиваться репозиторий :)

  13. ods

    Mercurial, на мой взгляд, с задачей вполне справляется.

  14. sin

    Я как-то делал слияние веток в SVN под Windows с помощью TortoiseSVN. Там неплохой мануал как это лучше делать: http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-merge.html

    Там два способа в зависимости от особенностей организации репозитария (портируются ли изменения транка в бранч). Оба основаны на получении патча с изменениями бранча, применения его к коду транка локально, фикса конфликтов и тестирования, а потом коммита в транк. В TortioseSVN это делается легко, как описано по ссылке. И т.к. пути можно указывать произвольные при создании дифа и при применении патча к локальной копии транка, то можно разбить задачу на части — для каждой перемещенной папки или файла, если их путь поменялся.

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

  15. Иван Сагалаев

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

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

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

    Я бы не согласился с однозначностью вывода. Если система контроля версий может это сделать надежно и предсказуемо, то пусть делает. Никакой особенной rocket science я тут, признаться, не чувствую. Это просто вопрос аккуратного программирования логики.

    Собственно, как написал выше ods, Меркуриал с этим справляется, по крайней мере в простых случаях.

  16. sin

    Про способ Романа... Я так понимаю, если изменения транка портированы в бранч (один из способов по ссылке), то потом надо сделать дифф между текущим транком и текущим бранчем и применить его к транку, но не диф между точкой отпочкования и текущим бранчем т.к. он будет содержать уже содержащиеся в транке изменения.

  17. sin

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

    На части разбивать, с учетом переноса файлов.

    Собственно, как написал выше ods, Меркуриал с этим справляется, по крайней мере в простых случаях.

    Да, уже почитал, интересно работает ли это в реальной жизни у кого-нибудь.

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

  18. der Igel

    Посмотрите svnmerge.py (http://www.orcaware.com/svn/wiki/Svnmerge.py)).
    Или сразу svn 1.5 (у которого сейчас RC8) - там со слиянием намного лучше (уж перемещаемые файлы в бранчах он точно отслеживает), но почти все тоже самое можно делать и с svnmerge.py в 1.4.

  19. Roman

    наверно предлагается полностью заменить транк бранчем. Но тогда второй шаг все равно странно выглядит.

    Спасибо за замечания. Действительно, предлагалось именно перенести все изменения в бранч, а потом просто заменить trunk. И действительно, второй шаг делает совсем не то, что нужно. Вместо этого ...

    надо сделать дифф между текущим транком и текущим бранчем и применить его к транку,

    или сказать

    svn move svn://.../branches/magicsplit/ svn://.../trunk/
    
  20. sin

    Мне в свое время, чтобы не попадать в такие ситуации, очень помог совет в конце http://svnbook.red-bean.com/en/1.1/ch04s04.html#svn-ch-4-sect-4.4, когда бранч какой-то фичи долго разрабатывается, то установить в команде период а лучше день, скажем раз в неделю, когда все изменения транка портируются в бранчи. Тогда по завершению жизни бранча вообще нет проблем, сразу шаг 2.

  21. Иван Сагалаев

    Я боюсь, что нам бы это не помогло. Проблему вызывает не то, что бранч долго разрабатывается (сами изменения кода там как раз не конфликтуют почти), а то, что в бранче основной код переехал в другие файлы. Поэтому как только это переименование случилось — все, никакие изменения из транка автоматически в бранч попадать не будут.

    А если рассуждать о том, как надо было, то надо было сделать максимум изменений без двигания структуры файлов, потому на день прекратить разработку в транке, сделать все переносы и тут же слить.

  22. sin

    А тут автоматически и не получится в общем случае. Чтобы начать портировать коммит из транка, можно его выгрузить как контекстный дифф для каждого измененного файла, а потом применить полученные патчи к файлам бранча, в которые соответствующий код переехал. Не совсем автоматически, но и не в ручную.

  23. Иван Сагалаев

    Угу. Вот похоже (после сегодняшних проб), так и придется сделать. Я еще напишу результаты отдельным постом.

  24. Леонид Швечиков

    Разве не проще было сделать SVN -> GIT -> merge -> SVN?

  25. Sam

    У нас на проектах сливались обе ветки к себе на локальную машину и каждый мёржил своё код в Araxis Merge. Да, не очень быстро, зато потом баги фиксить меньше. С автоматикой перед этим натерпелись…

  26. Александр Соловьёв

    Кроме того, слышал, что ммпортом из svn у него какой-то убогий. Или нет?

    У гита сейчас лучший импорт (и заодно экспорт) из svn.

    Или Hg/mercurial (который, вроде, слизан с гита

    Просто хочется плакать... :'( Читайте и просвещайтесь.

  27. Сергей Шепелев

    Посоветую изначально пользоваться SCM, которые понимают, что такое бранчи. В противовес SVN, который думает, что бранч это другой проект в директории рядом.

    То есть git/Mercurial. Про Bazaar/darcs/arch ничего не скажу, не пользовался, не слышал.

    У git кривой импорт из svn. Бред.

    Да, Mercurial медленнее, чем git, ибо писан не полностью на Си, а на Python с небольшой вставкой Си по поводу диффа. А вы разницу заметите? Вместо 380 ms оно будет мержится 540. Тоже мне проблема. Конечно, цифры писать глупо, но порядок именно такой.

    P.S.: реалтайм предпросмотр сообщения — это 5.

  28. Сергей Сергеев

    Есть предложение другое: попробовать использовать в branches svn:externals с фиксом до нужной ревизии (например, core -r4545, DAOs -r5000) на базовые или core части trunk'а.

  29. Азат Разетдинов

    Уточню ссылку Романа про Merges and Moves: http://tinyurl.com/36lt5n

  30. Ежики

    Аналогично пытался объединять с помощью toroiseSvn две разные. В принципе слил. В принципе без косяков. Но было очень много ручных операций и после мержа при попытке сделать update/commit svn сказал что эти файлы уже есть в основной ветке. Для меня это было сюрпризов ) Надо потренироваться на кошечках )

  31. Антон

    иван, чем закончилась эпопея?

  32. Иван Сагалаев

    Я пока не знаю даже, закончилась ли она. Потому как ушел в отпуск :-). Но я не забуду позже написать, в любом случае.

  33. Stoune

    Не знаю для меня merge в SVN самое больное место. После нескольких засад, делаю по следующему алгоритму.
    Делаю checkout в пустую папку, и ручками с помощью WinMerge утверждаю изменения, потому как достало его автоматическое слияние, которое кроме проблем ничего хорошего не делает. Хотелось чтобы тортилка сам спрашивала как мерджить без попыток сделать самой, но как это сделать пока не нашол.
    Вот такой велосипед.

  34. GiNeR

    Попробуй SVK - это VCS работающий с репозиторием Subversion, но децентрализованый и с более продвинутым merge.

  35. Ежики

    Вышло 1.5 ) Пока не пробовал, но судя по комментариям, тама ситуация с мержом исправлена ) Пока делаю попытки установить 1.5

  36. Deepwalker

    В 1.5 наконец то используется сторонняя SASL библиотека, и это счастье. Всем разработчикам так желаю делать изначально, а не впаривать CRAM-MD5 ибо остальное было делать лениво. Про мержи, правда, ничего сказать не могу : )

  37. Иван Сагалаев

    Итак, я обещал написать, чем все дело кончилось. Кончилось благополучно, мы живем с новым транком, но в итоге пришлось все сливать вручную. А именно: делать diff'ы по одним кускам кода и применять их к тем же кускам кода, которые в бранче переехали на новое место.

    Пробовали сначала сливать автоматически, импортировав историю из svn в git и в bzr. Первый отказался сливать бранч совсем, сказав про множество переименованных файлов что-то в духе "файл перемещен, поэтому мерджить в него ничего не могу". Bzr сделал попытку все смерджить, но результатом стали обширные конфликты на весь файл в духе "а вот тут весь файл стерт был у вас в бранче, а в транке в него что-то добавлялось". Есть теория, что ни тот, ни другой не справились с задачей, потому что зависели от истории svn, где переименование не настоящая операция. Возможно, что если бы что-то такое делалось сразу под управлением git/bzr/hg, то проблемы бы не было (как тут в комментариях и показывали уже).

    В сухом остатке — выработанные правила гигиены работы с бранчами в svn: если задумали менять структуру директорий, заморозьте ненадолго разработку в транке, поменяйте структуру, а уже потом бранчуйтесь и меняйте код в файлах на новых местах. Иначе оно не сольется.

  38. Dreel

    После всех этих приключений вы так и остались на svn?
    У меня ща примерно такие же проблемы возникли, нужно слить 2 сильно разошедшиеся ветки в ствол. Svn первый год только используем, всех заковык не знали, особо про синхронизацию со стволом! Делали, отпочковали ветку и давай в ней работать а на ствол забили, естественно в другой ветке изменения тоже никто не синхронизировал.

    Вот вопрос у меня, может перейти на git/bzr/hg? или оно того не стоит, раз уже в svn засели?

  39. Иван Сагалаев

    Да, мы на svn. По сути-то получается, что те изменения, которые мы делали, не могла бы автоматически слить наверное ни одна система контроля версий. Хотя, возможно, и было бы полегче.

    На самом деле многие разработчики у нас активно сидят внутри своих команд на bzr и git (про эти точно слышал, про hg еще нет). Но в корпоративный svn все равно все должно попадать.

  40. rety84nm

    А по какой логике должна обрабатываться такая ситуация?

    trunk/ lib

    branche/ lib -> lib1

    modif trunk/lib/

    merge trunk > branche => modif branche/lib1 ???

    А если в следующей ветке lib1 станет /lib/modules/ , то необходимо будет вводить понятие о дочерних и родительских перемещениях, вводить опционально наследование изменений и т д. И простой как топор svn превратится в какой нибудь луноход.

    А такой вариант если пробовали к чему приводит?

    Переносятся новые изменения из core в social. svn merge -rXX:HEAD svn://...trunk/core/ svn://...branches/social/ Тут чекаем конфликты, удаляем сненужные файли и т д.

    Потом обратно: svn merge -rXX:HEAD svn://...branches/ svn://...trunk/

Добавить комментарий