Использование git-svn (или аналогичного) * просто *, чтобы помочь слиянием SVN? - PullRequest
27 голосов
/ 01 июня 2010

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


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


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

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

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

Заранее спасибо.

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

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

Ответы [ 3 ]

34 голосов
/ 05 июня 2010

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

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

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

Я нашел git & git-svn спасателем:

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

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

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

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

Оговорка:

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

Другим отличным источником является книга Pro Git , в разделе «Переключение активных веток» в основном говорится, что слияние работает, но dcommit будет хранить только содержимое слияния, но история будет скомпрометирован (что нарушает последующие слияния), поэтому вы должны отбросить рабочую ветвь после слияния. В любом случае, это имеет смысл, и на практике здесь легко избежать ловушек ... в SVN я обнаружил, что люди обычно вообще не объединяются, так что это можно рассматривать только как шаг назад, если вы пришли из git world в первом место.

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

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

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, пока мы не переключимся полностью. Я не могу ждать этого.


ОБНОВЛЕНИЕ : @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's 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 (щелчок правой кнопкой мыши по файлу в конфликте). Это немного ограничено, поэтому посмотрите мой маленький патч выше, который позволяет вам подключить сценарий оболочки, где вы можете вызывать любые mergetools, которые вы предпочитаете (я пробовал различные из них иногда параллельно, так как они вызывали удивительное количество горя ... но обычно Я застрял с kdiff3 ..

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

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

Последний этап. Обратите внимание, что до сих пор у нас были только локальные коммиты, пока мы не общались с сервером SVN. Если вы не использовали --squash или другие приемы, теперь у вас есть график, на котором у вашего коммита слияния есть 2 родителя: советы ваших веток svn-mirror. Теперь это обычная ошибка: 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

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

3 голосов
/ 06 октября 2012

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

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

  1. ГИТ-SVN

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

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

    ...

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

    Существует в первую очередь три причины не коммитить слияния:

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

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

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

  2. 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. В результате репозитории Subversion и Git синхронизируются: каждый коммит и пуш запускают хуки, которые немедленно преобразуют входящие модификации.

    SubGit преобразует свойства svn: ignore в файлы .gitignore, свойства svn: eol-style и svn: mime-type в .gitattributes, поэтому коммиты слияния в Git сохраняют эти метаданные.

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

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

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

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

  3. SmartGit

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

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

    SmartGit - это коммерческий клиент Git and Mercurial. Это бесплатно для некоммерческого использования.

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

3 голосов
/ 27 августа 2010

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

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

...