Моя мотивация попробовать git-svn - это легкое слияние и ветвление. Затем я заметил, что man git-svn (1) говорит:
Running git-merge or git-pull is NOT recommended on a branch you plan to dcommit from. Subversion does not represent merges in any reasonable or useful fashion; so users using Subversion cannot see any merges you've made. Furthermore, if you merge or pull from a git branch that is a mirror of an SVN branch, dcommit may commit to the wrong branch.
Означает ли это, что я не могу создать локальную ветку из svn / trunk (или ветку), взломать, снова слить в svn / trunk, а затем выполнить dcommit? Я понимаю, что пользователи svn увидят тот же беспорядок, который всегда был в svn pre 1.5.x, но есть ли другие недостатки? Это последнее предложение меня тоже беспокоит. Люди обычно делают такие вещи?
@AlexanderKitaev: git-svn документы изменились с тех пор, и, кроме того, есть опция --mergeinfo=<mergeinfo>
, которая может передавать информацию о слиянии в SVN. Не знаю, как его использовать.
Создание локальных веток определенно возможно с помощью git-svn. Пока вы просто используете локальные ветки для себя и не пытаетесь использовать git для слияния ветвей svn восходящего потока, все будет в порядке.
У меня есть «главная» ветка, которую я использую для отслеживания svn-сервера. Это единственная ветка, из которой я делаю коммит. Если я делаю какую-то работу, я создаю тематическую ветку и работаю над ней. Когда я хочу зафиксировать это, я делаю следующее:
У меня также есть другая ситуация, когда мне нужно поддерживать некоторые локальные изменения (для отладки), которые никогда не должны переноситься в svn. Для этого у меня есть указанная выше основная ветка, а также ветка под названием «работа», в которой я обычно работаю. Тематические ветки разветвляются от работы. Когда я хочу зафиксировать работу там, я проверяю мастер и использую вишневый выбор, чтобы выбрать коммиты из рабочей ветки, которые я хочу зафиксировать в svn. Это потому, что я хочу избежать фиксации трех локальных изменений. Затем я делаю фиксацию из основной ветки и все переустанавливаю.
Стоит сначала запустить git svn dcommit -n
, чтобы убедиться, что вы собираетесь зафиксировать именно то, что собираетесь зафиксировать. В отличие от git, переписать историю в svn сложно!
Я считаю, что должен быть лучший способ объединить изменения в тематической ветке, пропуская эти локальные изменения, чем использование cherry-pick, поэтому, если у кого-то есть какие-либо идеи, они будут приветствоваться.
Если я правильно понимаю, в git слияние git с svn в порядке, но не svn с svn? Значит, я не могу объединить мою svn / ветку с svn / trunk в git?
Переписать историю в SVN сложно, если вы хотите сделать что-то тривиальное. В нетривиальных случаях это практически невозможно.
Jegern: Верно. Для слияния svn-to-svn я бы рекомендовал использовать для этого сам svn.
Ответ Грега Хьюджилла набрал много голосов, но я считаю, что это неверно. Слияние из topic_branch с мастером безопасно только в том случае, если это просто слияние с перемоткой вперед. Если это настоящее слияние, требующее фиксации слияния, то фиксация слияния будет потеряна при dcommit. В следующий раз, когда вы попытаетесь объединить topic_branch с мастером, git решит, что первого слияния не было, и начнется ад. См. Вопрос Почему git svn dcommit теряет историю коммитов слияния для локальных веток?
@Greg Hewgill, редактирование непонятно. Вы писали, что перебазирование «делает следующее коммитирование слиянием с перемоткой вперед». Я не знаю, что это значит, потому что слияние с быстрой перемоткой вперед не требует фиксации, но, возможно, вы имели в виду «делает следующее слияние слиянием с перемоткой вперед». Но если вы это имели в виду, это неверно. Является ли слияние topic_branch в master слиянием с перемоткой вперед или нет, зависит от того, были ли сделаны какие-либо коммиты на master с момента точки ветвления. Когда вы перебазируете мастер, это создает новые коммиты на мастере, поэтому последующее слияние обязательно нет слияние с ускоренной перемоткой вперед.
@Aaron: Да, я не знаю, о чем я там думал. Я исправил это снова, надеюсь, это имеет смысл. Одна из проблем заключается в том, что в Git так много способов делать что-то, что требуется некоторое объяснение, чтобы описать последовательность действий специфический.
Я думаю, что это утверждение «пока вы просто используете локальные ветки для себя и не пытаетесь использовать git для слияния между ветвями восходящего потока svn, все будет в порядке», на мой взгляд, вводит в заблуждение, что это невозможно и / или полезно для используйте GIT для реальных слияний SVN. ИМХО, верно и обратное, см. Ответ luntain ниже и мой @ stackoverflow.com/questions/2945842/…
@Greg Hewgil Вы говорите, что «следующим шагом будет быстрое слияние», но я не уверен, как это может быть, если разработка продолжается на master. Когда вы являетесь мастером git svn rebase
, он может вносить новые изменения, о которых ваша тематическая ветка не знает. Таким образом, страхование вашего слияния будет чем-то, кроме быстрой перемотки вперед. Может быть, на всякий случай использовать --ff-only
? Но на самом деле вы должны быть --squash
ing
@jemmons: если между шагами 2 и 4 нет новых коммитов Subversion, тогда шаг 5 действительно будет слиянием с перемоткой вперед. Если кто-то еще выполняет Subversion между шагами 2 и 4, затем вернитесь в ветку темы и повторите с шага 2.
Безопасный способ объединить ветки svn в git - использовать git merge --squash. Это создаст одну фиксацию и остановит вас, чтобы добавить сообщение.
Допустим, у вас есть ветка svn в теме, которая называется svn-branch.
git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch
на этом этапе у вас есть все изменения из svn-ветки, сжатые в одну фиксацию, ожидающую в индексе
git commit
Однако, как отмечали другие, при этом теряется детализация коммитов.
@Tchalvak: Иногда хочется именно этого. Я часто совершаю коммиты в ветке функций, а именно «исправленный беспорядок из предыдущего коммита», и эти тупики я люблю скрывать из-за хорошей репутации :-)
Да, хотя я считаю, что это прогулка по канату, поскольку всякий раз, когда вы давите, вы также теряете способность позже разрывать отдельные коммиты. Просто вопрос о разных вариантах выполнения стандартов.
@schoetbi да, иногда вам нужно очистить грязную историю перед публикацией. Здесь очень помогает git rebase -i <trunk>: вы можете присоединяться / переупорядочивать / удалять и даже разделять (!) Коммиты, выборочно исправлять сообщения.
Переустановите локальную ветку git на основную ветку git, затем dcommit, и тогда будет похоже, что вы выполнили все эти коммиты последовательно, чтобы люди svn могли видеть это линейно, как они привыкли. Итак, если у вас есть локальная ветка под названием topic, вы могли бы сделать
git rebase master topic
который затем будет воспроизводить ваши коммиты над основной веткой, готовой для вас dcommit
На самом деле, я нашел даже лучший способ с опцией --no-ff
в git merge.
Вся эта техника сквоша, которую я использовал раньше, больше не требуется.
Мой новый рабочий процесс выглядит следующим образом:
У меня есть «главная» ветка, которая является единственной веткой, из которой я делаю фиксацию и которая клонирует репозиторий SVN (-s
предполагает, что у вас есть стандартный макет SVN в репозитории trunk/
, branches/
и tags/
):
git svn clone [-s] <svn-url>
Работаю на локальной ветке "работа" (-b
создает ветку "работа")
git checkout -b work
выполнить локальную фиксацию в «рабочую» ветку (-s
для подписи вашего сообщения о фиксации). В дальнейшем я предполагаю, что вы сделали 3 локальных коммита
...
(work)$> git commit -s -m "msg 1"
...
(work)$> git commit -s -m "msg 2"
...
(work)$> git commit -s -m "msg 3"
[В конце концов] спрятать изменения, которые вы не хотите фиксировать на сервере SVN (часто вы комментировали некоторый код в основном файле только потому, что хотите ускорить компиляцию и сосредоточиться на данной функции)
(work)$> git stash
перебазировать основную ветку с репозиторием SVN (для обновления с сервера SVN)
(work)$> git checkout master
(master)$> git svn rebase
вернитесь в рабочую ветку и переустановите с мастером
(master)$> git checkout work
(work)$> git rebase master
Убедитесь, что все в порядке, например, используя:
(work)$> git log --graph --oneline --decorate
Теперь пришло время объединить все три коммита из ветки "work" в "master", используя эту замечательную опцию --no-ff
.
(work)$> git checkout master
(master)$> git merge --no-ff work
Вы можете заметить статус журналов:
(master)$> git log --graph --oneline --decorate
* 56a779b (work, master) Merge branch 'work'
|\
| * af6f7ae msg 3
| * 8750643 msg 2
| * 08464ae msg 1
|/
* 21e20fa (git-svn) last svn commit
Теперь вы, вероятно, захотите отредактировать (amend
) последнюю фиксацию для своих парней из SVN (иначе они увидят только одну фиксацию с сообщением «Объединить ветку 'работает'».
(master)$> git commit --amend
Наконец, выполните фиксацию на сервере SVN
(master)$> git svn dcommit
Вернитесь к работе и в конечном итоге восстановите свои спрятанные файлы:
(master)$> git checkout work
(work)$> git stash pop
Это ТОЧНО рабочий процесс, который искал git n00b. Создайте локальную ветку, чтобы исправить ошибку, сделайте что угодно, а затем отправьте ее в svn с ОДНОЙ фиксацией. Использование здесь самого высокого рейтингового ответа испортило то, что я делал - не мог git svn rebase без ошибок.
Я тоже считаю, что "ответ" нужно поменять на этот.
Было бы неплохо, если бы вы могли удалить свой старый ответ на этот вопрос, так как этот способ лучше. Спасибо, что добавили это!
Разве это не именно то, о чем предупреждают процитированные в операторе git-svn документы? Запустив слияние с параметром --no-ff
, вы явно создаете фиксацию слияния (фиксацию с двумя родителями) вместо быстрой перемотки вперед. Чтобы гарантировать, что все коммиты в ветке svn-tracking являются одиночными коммитами, все слияния должны быть либо ускоренными (--ff-only
может в этом помочь), либо, если ствол изменился за вашей спиной, --squash
, верно?
Это работает для одноразовой ветки, которую вы немедленно удаляете, но git svn dcommit
перезаписывает переданный вами коммит git. Это означает, что вы теряете другого родителя, и теперь в вашем репозитории git нет записи о том, что вы когда-либо объединяли эту ветвь с master
. Это также может привести к тому, что ваш рабочий каталог окажется в несогласованном состоянии.
используйте git merge --no-ff work -m "commit message"
вместо дополнительного шага git commit --amend
Отличное резюме того, как заставить Git и SVN хорошо играть в песочнице вместе, не заставляя Git идти домой, плача с песком в глазах ...
для меня я бы предпочел использовать "git merge --ff-only work", так как я хочу сохранить все свои коммиты, а не только последний
Это только у меня или есть причина удалить ветку work
после слияния и повторно ветвиться в конце процесса? stackoverflow.com/q/26511177/671013
Ответ Грега Хьюджилла сверху небезопасен! Если какие-либо новые коммиты появились в стволе между двумя "git svn rebase", слияние не будет ускорено.
Это может быть обеспечено с помощью флага «--ff-only» для git-merge, но я обычно не запускаю «git svn rebase» в ветке, а только на нем «git rebase master» (при условии, что это только локальный ветка). Затем после этого "git merge thebranch" гарантированно переместится вперед.
Это просто неправильно: Subversion не представляет собой слияния в разумной или полезной форме; поэтому пользователи, использующие Subversion, не могут видеть никаких сделанных вами слияний. Кроме того, если вы выполните слияние или извлечение из ветки git, которая является зеркалом ветки SVN, dcommit может выполнить фиксацию в неправильную ветку. Subversion может представлять не только информацию отслеживания слияния git, но также гораздо более подробную информацию. Это git-svn, который не может правильно составить svn: mergeinfo или заставить dcommit в правильную ветку.