Использование git-svn (или аналогичного) * просто *, чтобы помочь слиянием SVN?
В моем проекте возникают сложные слияния подрывной деятельности: большие ветви, которые давно разошлись. Свн дает слишком много конфликтов - и некоторые из них кажутся ложными.
При условии git
хвалят за превосходный опыт слияния, было бы хорошо использовать git-svn
только для того, чтобы сделать слияние более управляемым?
Можете ли вы порекомендовать другие альтернативы (например, svk
, hgsvn
) уменьшить боль слияния?
Некоторые конфликты достаточно легко разрешить (например, импорт Java, пробелы) - поэтому мне также интересно, есть ли какие-либо автоматизированные решения для них.
Полный переход на DVCS может произойти в будущем (некоторым из нас это понравится), но не сейчас. (ОБНОВЛЕНИЕ: это больше не так - команда недавно полностью перешла и рада этому).
Заранее спасибо.
PS: есть сообщения, которые кажутся связанными (например, git-svn merge 2 svn ветки), но они не полностью отвечают на этот вопрос.
Обновление: см. Мой -novice- ответ после перехода вниз (и вверх:) по этой дороге.
3 ответа
Попытка ответить на мой вопрос: использование git для svn merges кажется многообещающим.
Обновление: это не просто перспективно, это большой успех. Короче говоря, Линус был прав.
Только что завершили огромное слияние 2 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. Subversion не обрабатывает слияния так же, как Git, и это вызовет проблемы. Это означает, что вы должны сохранять свою историю разработки Git линейной (то есть, без слияния из других веток, просто перебазировать) (последний абзац http://learn.github.com/p/git-svn.html)
Другой замечательный источник - книга Pro Git, раздел "Переключение активных веток" в основном говорит, что слияние работает, но dcommit
будет только хранить содержимое слияния, но история будет скомпрометирована (что нарушит последующие слияния), поэтому вы должны отбросить рабочую ветвь после слияния. В любом случае это имеет смысл в конце концов, и на практике здесь легко избежать ловушек... в SVN я обнаружил, что люди обычно вообще не объединяются, так что это можно рассматривать только как шаг назад, если вы пришли из git world в первом место.
Во всяком случае, dcommit просто работал для меня. Я сделал это на своем собственном рабочем месте svn, которое сохранил только для этого, поэтому избежал лишних конфликтов в этот раз. Тем не менее, я решил сделать окончательное слияние с этой рабочей ветки на svn trunk в 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
К сожалению, это становится слишком долго, останавливаясь, пока не поздно.. Удачи.
Я только что проработал это сам. Более простой способ - пройти git merge
--squash
опция, которая будет выполнять слияние без записи фиксации слияния, сохраняя историю линейной, чтобы не перепутать git-svn.
Мое слияние было также очень большим, и я должен был установить git config diff.renamelimit 0
чтобы git правильно нашел все переименования.
Доступны новые инструменты, которые исправляют многие проблемы с git-svn и предоставляют гораздо лучший опыт использования Subversion и Git.
Помимо прочего, эти инструменты устраняют некоторые проблемы ветвления и слияния. Вот обзор:
ГИТ-SVN
Из документации:
ПРЕДОСТЕРЕЖЕНИЯ
...
Запускать git merge или git pull НЕ рекомендуется в ветке, из которой вы планируете выполнить. Subversion не представляет слияния каким-либо разумным или полезным способом; таким образом, пользователи, использующие Subversion, не могут видеть сделанные вами слияния. Более того, если вы объединяете или извлекаете из ветки git, которая является зеркалом ветки SVN, dcommit может зафиксировать неправильную ветку.
Есть в первую очередь три причины не делать коммитов слияния:
git-svn не отправляет автоматически свойство svn: mergeinfo для объединенных ветвей. В результате Subversion не может отследить те слияния, которые выполняет git. Это включает в себя нормальные Git-слияния и вишневые кирки.
поскольку git-svn не конвертирует svn: ignore, svn: eol-style и другие свойства SVN автоматически, коммит слияния не имеет соответствующих метаданных в Git. В результате dcommit не отправляет эти свойства в репозиторий SVN, поэтому они теряются.
dcommit всегда отправляет изменения в ветку, на которую ссылается первый родительский элемент фиксации слияния. Иногда изменения появляются там, где пользователь их не ожидает.
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.
SmartGit - это альтернатива git-svn на стороне клиента.
SmartGit также поддерживает преобразование свойств svn: ignore, svn: eol-style и svn: mime-type. И также устанавливает свойство svn: mergeinfo для коммитов слияния. Он даже обновляет необходимые данные отслеживания слияний для коммитов cherry-pick.
SmartGit - это коммерческий клиент Git and Mercurial. Это бесплатно для некоммерческого использования.
Полное раскрытие: я один из разработчиков SubGit.