Используя git -svn (или аналогичный) * just *, чтобы помочь с слиянием svn?

В моем проекте возникают сложные слияния с субверсиями: большие ветки, которые давно разлучены. Svn дает слишком много конфликтов - и некоторые из них кажутся ложными.


Учитывая, что git хвалит за опыт суперярного слияния, Будет ли полезно использовать git-svn только для того, чтобы сделать слияние более управляемым?


Можете ли вы порекомендовать другие альтернативы (например, svk, hgsvn), чтобы уменьшить боль при слиянии?

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

Полный переход на DVCS может произойти в будущем (некоторым из нас это понравится), но не сейчас. (ОБНОВЛЕНИЕ: это уже не так - команда совсем недавно переключилась и довольна этим).

Спасибо заранее.

PS: есть сообщения, которые, похоже, связаны между собой (например, git -svn merge 2 svn ветки), но они не полностью отвечают на этот вопрос.

Обновление: см. мой -novice-answer после спуска (и вверх:) этой дороги.

Ответ 1

Попытка ответить на мой вопрос: использование git для слияний svn кажется многообещающим.

Обновление: это не просто обещание, это большой успех. Короче говоря, Линус был прав.

Только что завершилось огромное слияние двух svn-ветвей, которые были разделены на 1,5 года; 3k файлы были изменены, получили тонны конфликтов в svn (~ 800, я думаю).

Я нашел git и git -svn спасатель жизни:

  • автоконфликтное разрешение: для начала он дал намного меньше противоречивых файлов (~ половина, я думаю)
  • невероятная производительность
  • отлично модель репо/ветвление, гибкие рабочие процессы: простое экспериментирование с различными подходами, такими как слияние блоков по времени (по времени) всегда делать проверки здравомыслия (компиляция и т.д.); всякий раз, когда неприятности попадают: просто назад. Вы всегда можете сделать шаг назад, когда это необходимо.
  • удобство использования, отличное оснащение:
    • git-log (и базовые опции git-rev-parse), ничто не может быть более мощным, чем это. Это также полезно: -p дает вам разницу за один раз; в svn вы получите журнал, затем найдите diff для этой "ревизии-1: ревизия" или используйте неуклюжие пользовательские интерфейсы. Найти, когда строка была добавлена ​​/удалена в репо, поиск нескольких ветвей одновременно
    • gitk: чрезвычайно полезно для визуализации истории веток в сочетании с отличными возможностями поиска. Не видели ничего подобного в других инструментах, особенно не так быстро, как это. Nevermind это в Tk, это просто блестяще
    • git gui: отлично работает, даже если не самый сексуальный - отличная помощь для новичков, чтобы обнаружить вещи.
    • blame: чудо. Да, он обнаруживает, откуда приходит исходный сегмент (копия, вставка и т.д.).
    • mergetool: гораздо приятнее, чем начинать большой svn merge, который затем останавливается каждый раз (т.е. каждые 5 минут), он сталкивается с конфликтом, нажимает '(p) ostpone', а не на ручную охоту за конфликтующими файлами позже. Предпочтительный аромат этого интегрированного в git gui (для этого нужен крошечный патч). Найдены интегрированные инструменты внешней диффе- ренции, которые лучше конфигурируются, чем в svn.
    • подключаемые драйверы слияния и мелкозернистый контроль над ними.
    • rebase разрешено отфильтровывать более грязные части истории svn
  • Распространение: нет необходимости приходить в офис при работе над этим, может приостанавливаться и прогрессировать шаг за шагом на поезде/самолете и т.д.
    • USB-накопитель с Unison заставил синхронизировать работу ↔ домой кусок торта
    • это было бы невозможно без git сумасшедшего сжатия (5-летний проект с фиксацией 26 тыс., тонны ветвей и двоичных файлов, trunk svn checkout: 1.9Gb = > все это в полном репозитории git: 1.4Gb!)

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

Даже если я не могу заставить всех в компании немедленно переключиться - я действительно не собирался на самом деле. Опять же, git-svn сэкономит нас на "окунании носком". Но, увидев реакции коллег, коммутатор может произойти намного раньше, чем кто-либо ожидал:)

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

Протест:

"Не выполнять dcommit git merge совершает репозиторий Subversion. диверсия не обрабатывает слияния таким же образом как Git, и это вызовет проблемы. Это означает, что вы должны сохранить свой Gitистория развития линейная (т.е. нет сливаясь с другими отраслями, просто перебазирования)". (последний абзац http://learn.github.com/p/git-svn.html)

Другим отличным источником является Pro git book, раздел "Переключение активных ветвей" в основном говорит о том, что слияние действительно работает, но dcommit будет хранить содержимое слияния, но история будет скомпрометирована (что приведет к разрыву последующих слияний), поэтому вам следует отказаться от рабочей ветки после слияния. В любом случае, это имеет смысл в конце концов, и на практике легко избежать ловушек здесь. В svn я обнаружил, что люди обычно не сливаются воедино, так что это можно было бы рассматривать только как шаг назад, если вы пришли из мира git первое место.

Во всяком случае, dcommit просто работал у меня. Я сделал это на своем собственном svn workbranch, который я сохранил только для этого, поэтому избегал любых дополнительных конфликтов в то время. Тем не менее, я решил сделать окончательное слияние с этой рабочей ветки на svn trunk в svn (после синхронизации всего в git); --ignore-ancestry дал наилучшие результаты.

Обновление: как я узнал позже, последние несколько шагов выше (дополнительная ветвь svn и merge - ignore-ancestry) легко избежать, просто удерживая ветку, которую вы выполняете с линейной. Как говорит Гейб ниже, merge --squash просто создает просто тупое svn-friendly commit. Когда вы будете готовы с огромным слиянием (-ами) на моей локальной ветке (которая может занять несколько дней/недель), я теперь просто:

git checkout -b dcommit_helper_for_svnbranch  svnbranch
git merge --squash huge_merge_work_with_messy_nonlinear_history
git commit 'nice merge summary' # single parent, straight from the fresh svnbranch
git dcommit

Я знаю, что отслеживание слияния не будет отлично работать с svn-side, пока мы полностью не переключимся. Я не могу дождаться этого.


ОБНОВЛЕНИЕ: @Kevin запросил более подробную информацию о процессе слияния ветвей svn. Есть много статей, сообщений там, но в качестве новичков я нашел некоторые из запутывающих/вводящих в заблуждение/устаревший. Во всяком случае, как я это делаю в эти дни (конечно, застрял с git -svn после этого дела слияния, как и некоторые недавно инфицированные коллеги).

git svn clone -s http://svn/path/to/just-above-trunk  # the slowest part, but needed only once ever..you can every single branch from the svn repo since revision #1. 2) 
git svn fetch          # later, anytime: keep it up to date, talking to svn server to grab new revisions. Again: all branches - and yet it usually a faster for me than a simple 'svn up' on the trunk:)    
# Take a look, sniff around - some optional but handy commands:
git gui   &    # I usually keep this running, press F5 to refresh
gitk --all     # graph showing all branches
gitk my-svn-target-branch svn-branch-to-merge    # look at only the branches in question
git checkout -b my-merge-fun my-svn-target-branch  # this creates a local branch based on the svn one and switches to it..before you notice :)
# Some handy config, giving more context for conflicts
git config merge.conflictstyle diff3
# The actual merge.. 
git merge  svn-branch-to-merge    # the normal case, with managable amount of conflicts
# For the monster merge, this was actually a loop for me: due to the sheer size, I split up the 2 year period into reasonable chunks, eg. ~1 months, tagged those versions ma1..ma25 and mb1..mb25 on each branch using gitk, and then repeated these for all of them
git merge ma1   # through ma25
git merge mb1   # through mb25
# When running into conflicts, just resolve them.. low tech way: keep the wanted parts, then "git add file" but you can
git mergetool   # loops through each conflicted file, open your GUI mergetool of choice..when successful, add the file automatically.
git mergetool  my-interesting-path # limit scope to that path

На самом деле я предпочел использовать 'git gui встроенную интеграцию mergetool (щелкните правой кнопкой мыши на конфликтующий файл). Это немного ограничено, так что см. Мой маленький патч выше, который позволяет вам подключать оболочку script, где вы можете ссылаться на любые слияния, которые вы предпочитаете (я пробовал различные из них иногда параллельно, поскольку они вызывали удивительное количество горя. но обычно я застрял с kdiff3..

Когда шаг слияния идет хорошо (без конфликтов), фиксация слияния выполняется автоматически; в противном случае вы разрешаете конфликты, а затем

git commit  # am usually doing this in the git gui as well.. again, lightning fast.

Последняя фаза. Заметим, что до сих пор у нас были только локальные коммиты, а не разговоры с сервером svn. Если вы не использовали -squash или другие трюки, теперь у вас есть график, в котором у вашего слияния есть 2 родителя: советы ваших ветвей svn-mirror. Теперь это обычная gotcha: svn может брать только линейную историю.. поэтому 'git -svn' упрощает ее, просто отбрасывая второго родителя (svn-branch-to-merge в вышеприведенном случае).. так что реальное слияние отслеживание пропадает на стороне svn. но в противном случае это будет хорошо в этом случае.

Если вы хотите более безопасный/более чистый способ, то сюда приходит мой предыдущий фрагмент: просто выполните окончательное слияние с -squash. Адаптировался ранее к этому потоку:

git checkout -b dcommit_helper_for_svnbranch my-svn-target-branch  # another local workbranch.. basically needed as svn branches (as any other remote branch) are read-only
git merge --squash my-merge-fun  
git commit 'nice merge summary' # single parent, straight from the fresh svn branch
git dcommit  # this will result in a 'svn commit' on the my-svn-target-branch

Упс, это слишком длинное, останавливаясь до слишком поздно.. Удачи.

Ответ 2

Я только что справился с этим. A более простой метод - передать git merge параметр --squash, который будет выполнять слияние без записи слияния, сохраняя линейную историю, чтобы не путать git -svn.

Мое слияние также было очень большим, и мне пришлось установить git config diff.renamelimit 0, чтобы git правильно нашел все переименования.

Ответ 3

Появились новые инструменты, которые устраняют многие проблемы git -svn и обеспечивают гораздо лучший опыт использования как Subversion, так и Git.

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

  • git -svn

    Из документации:

    ПРЕДОСТЕРЕЖЕНИЯ

    ...

    Запуск git merge или git pull не рекомендуется в ветке, из которой вы планируете dcommit. Subversion не представляет собой слияние каким-либо разумным или полезным способом; поэтому пользователи, использующие Subversion, не видят никаких слияний, которые вы сделали. Кроме того, если вы слились или вытащили из ветки git, которая является зеркалом ветки SVN, dcommit может передать неверную ветку.

    В основном есть три причины не компрометировать слияние:

    • git -svn автоматически не отправляет свойство svn: mergeinfo для объединенных ветвей. В результате Subversion не может отслеживать те слияния, которые выполняются с помощью Git. Это включает в себя обычные git слияния и вишни.

    • как git -svn не преобразует svn: ignore, svn: eol-стиль и другие свойства SVN автоматически, слияние commit не имеет соответствующих метаданных в Git. В результате dcommit не отправляет эти свойства в репозиторий SVN, поэтому они теряются.

    • dcommit всегда отправляет изменения в ветку, на которые ссылается первый родитель слияния. Иногда появляются изменения, когда пользователь их не ожидает.

  • SubGit

    SubGit - это двунаправленное серверное зеркало git -SVN.

    Если у вас есть локальный доступ к репозиторию Subversion, в него можно установить SubGit:

    $ subgit configure $SVN_REPOS
    # Adjust $SVN_REPOS/conf/subgit.conf to specify your branches and tags
    # Adjust $SVN_REPOS/conf/authors.txt to specify git & svn authors mapping
    $ subgit install $SVN_REPOS
    ...
    $ INSTALLATION SUCCESSFUL
    

    В данный момент SubGit преобразует репозиторий Subversion в git (он работает и в противоположном направлении) и устанавливает SVN и git hooks. В результате репозитории Subversion и git синхронизируются: каждый фиксатор и push запускают перехватчики, которые немедленно конвертируют входящие изменения.

    SubGit преобразует svn: игнорирует свойства в .gitignore файлы, svn: eol-style и svn: свойства mime-типа в .gitattributes, поэтому объединение завершает в git сохранение этих метаданных.

    Когда кто-то подталкивает фиксацию слияния, SubGit преобразует все новые коммиты в ревизии Subversion. Он отличает свойство svn: mergeinfo, поэтому после этого операция слияния корректно отслеживается SVN.

    Даже если пользователь создает очень сложную историю git, SubGit преобразует все фиксации, сохраняя данные отслеживания слияния действительными. Мы как-то полностью нажали всю историю репозитория Git.git, и он был правильно преобразован в SVN.

    SubGit - это коммерческий продукт. Он бесплатный для открытых и академических проектов, а также для проектов с участием до 10 коммиттеров.

    Подробнее см. Документация SubGit и git - svn.

  • SmartGit

    SmartGit является альтернативой для клиента git -svn.

    SmartGit также поддерживает преобразование свойств svn: ignore, svn: eol-style и svn: mime-type. И он также устанавливает свойство svn: mergeinfo для коммандов слияния. Он даже обновляет необходимые данные отслеживания слияния для фиксации вишни.

    SmartGit является коммерческим клиентом git и Mercurial. Он бесплатный для некоммерческого использования.

Полное раскрытие: Я один из разработчиков SubGit.