Опасно ли git-svn dcommit после слияния с git?
Моя мотивация попробовать git-svn - это легкое слияние и ветвление. Затем я заметил, что мужчина git-svn(1) говорит:
Запуск git-merge или git-pull НЕ рекомендуется для ветки, из которой вы планируете dcommit. Subversion не представляет слияния каким-либо разумным или полезным способом; таким образом, пользователи, использующие Subversion, не могут видеть сделанные вами слияния. Более того, если вы объединяете или извлекаете из ветки git, которая является зеркалом ветки SVN, dcommit может зафиксировать неправильную ветку.
Означает ли это, что я не могу создать локальную ветку из svn/trunk (или ветки), взломать, объединить обратно в svn/trunk, а затем dcommit? Я понимаю, что пользователи svn увидят тот же беспорядок, который всегда был в svn pre 1.5.x, но есть ли другие недостатки? Последнее предложение меня тоже волнует. Люди обычно делают такие вещи?
6 ответов
На самом деле, я нашел еще лучший способ --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
[В конце концов] спрятать изменения, которые вы не хотите видеть зафиксированными на сервере 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
Теперь пришло время объединить все три коммита из ветви "работа" в "мастер", используя этот замечательный
--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-парней (в противном случае они увидят только один коммит с сообщением "Merge branch 'work'"(master)$> git commit --amend
Наконец зафиксировать на сервере SVN
(master)$> git svn dcommit
Вернитесь к работе и в конечном итоге восстановите ваши спрятанные файлы:
(master)$> git checkout work (work)$> git stash pop
Создание локальных веток определенно возможно с помощью git-svn. Пока вы просто используете локальные ветки и не пытаетесь использовать git для слияния между ветвями SVN верхнего уровня, у вас все будет хорошо.
У меня есть "главная" ветка, которую я использую для отслеживания сервера SVN. Это единственная ветка, из которой я делаю коммит. Если я делаю какую-то работу, я создаю ветку тем и работаю над ней. Когда я хочу зафиксировать это, я делаю следующее:
- Зафиксируйте все в ветке темы
- git svn rebase (разрешите любые конфликты между вашей работой и svn)
- мастер проверки
- git svn rebase (это делает следующий шаг быстрым слиянием, см. комментарии Аарона ниже)
- git merge topic_branch
- разрешить любые конфликты слияния (в этот момент их не должно быть)
- git svn dcommit
У меня также есть другая ситуация, когда мне нужно поддерживать некоторые локальные изменения (для отладки), которые никогда не должны передаваться в svn. Для этого у меня есть вышеупомянутая основная ветка, но также есть ветка под названием "работа", где я обычно работаю. Тематические ветки разветвлены от работы. Когда я хочу зафиксировать работу там, я извлекаю master и использую cherry-pick, чтобы выбрать коммиты из рабочей ветки, которые я хочу зафиксировать в svn. Это потому, что я хочу избежать фиксации трех локальных изменений. Затем я делаю коммит из ветки master и перебазирую все.
Стоит бежать git svn dcommit -n
сначала убедитесь, что вы собираетесь совершить именно то, что вы намереваетесь совершить. В отличие от git, переписывать историю в svn сложно!
Я чувствую, что должен быть лучший способ объединить изменения в ветке темы с пропуском этих локальных изменений, чем при использовании cherry-pick, поэтому, если у кого-то есть какие-либо идеи, они будут приветствоваться.
Простое решение: удалить ветку 'работа' после слияния
Краткий ответ: Вы можете использовать git так, как вам нравится (простой рабочий процесс см. Ниже), включая слияние. Просто убедитесь, что после каждого "git merge work" используется "git branch -d work", чтобы удалить временную рабочую ветку.
Фоновое объяснение: проблема слияния / dcommit заключается в том, что всякий раз, когда вы 'git svn dcommit' ветвь, история слияния этой ветки 'сглаживается': git забывает обо всех операциях слияния, которые пошли в эту ветку: сохраняется только содержимое файла, но тот факт, что этот контент (частично) пришел из определенной другой ветки, теряется. Смотрите: Почему git svn dcommit теряет историю коммитов слияния для локальных веток?
(Примечание: git-svn мало что может с этим поделать: svn просто не понимает гораздо более мощных git-слияний. Таким образом, в хранилище svn эта информация о слиянии не может быть представлена каким-либо образом.)
Но это вся проблема. Если вы удалите ветку 'work' после того, как она будет объединена с 'master веткой', то ваш репозиторий git будет на 100% чист и выглядит точно так же, как ваш svn-репозиторий.
Мой рабочий процесс: Конечно, я сначала клонировал удаленный svn-репозиторий в локальный git-репозиторий (это может занять некоторое время):
$> git svn clone <svn-repository-url> <local-directory>
Вся работа происходит внутри "local-directory". Всякий раз, когда мне нужно получить обновления с сервера (например, 'svn update'), я делаю:
$> git checkout master
$> git svn rebase
Я делаю всю свою работу по разработке в отдельной ветке 'работа', которая создается следующим образом:
$> git checkout -b work
Конечно, вы можете создать столько веток для вашей работы, сколько захотите, а также объединять и перебазировать их между собой по своему усмотрению (просто удалите их, когда закончите с ними - как описано ниже). В своей обычной работе я совершаю очень часто:
$> git commit -am '-- finished a little piece of work'
Следующий шаг (git rebase -i) не обязателен - он просто очищает историю перед тем, как архивировать ее на svn: Как только я достиг стабильного мили, которым хочу поделиться с другими, я переписываю историю этой "работы" разветвляйте и очищайте сообщения коммита (другие разработчики не должны видеть все маленькие шаги и ошибки, которые я сделал на пути - только результат). Для этого я делаю
$> git log
и скопируйте хэш sha-1 последнего коммита, который находится в репозитории svn (как указано в git-svn-id). Тогда я звоню
$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb
Просто вставьте хэш sha-1 нашего последнего SVN-коммита вместо моего. Вы можете прочитать документацию с помощью git help rebase для получения подробной информации. Вкратце: эта команда сначала открывает редактор, представляющий ваши коммиты ---- просто измените 'pick' на 'squash' для всех тех коммитов, которые вы хотите раздавить с предыдущими коммитами. Конечно, первая строка должна оставаться в качестве "выбора". Таким образом, вы можете сконцентрировать ваши многочисленные маленькие коммиты в одну или несколько значимых единиц. Сохраните и выйдите из редактора. Вы получите другой редактор с просьбой переписать сообщения журнала коммита.
Короче говоря: после того, как я закончу "взлом кода", я массирую свою ветку "работа", пока она не увидит, как я хочу представить ее другим программистам (или как я хочу увидеть работу через несколько недель, когда я просматриваю историю).,
Чтобы отправить изменения в репозиторий svn, я делаю:
$> git checkout master
$> git svn rebase
Теперь мы вернулись к старой ветке 'master', обновленной со всеми изменениями, произошедшими за это время в репозитории svn (ваши новые изменения скрыты в ветке 'work').
Если есть изменения, которые могут конфликтовать с вашими новыми "рабочими" изменениями, вам нужно разрешить их локально, прежде чем вы сможете отправить свою новую работу (подробности см. Ниже). Затем мы можем отправить наши изменения в SVN:
$> git checkout master
$> git merge work # (1) merge your 'work' into 'master'
$> git branch -d work # (2) remove the work branch immediately after merging
$> git svn dcommit # (3) push your changes to the svn repository
Примечание 1. Команда 'git branch -d work' довольно безопасна: она позволяет вам удалять только те ветки, которые вам больше не нужны (потому что они уже объединены с вашей текущей веткой). Если вы выполнили эту команду по ошибке перед тем, как объединить свою работу с веткой 'master', вы получите сообщение об ошибке.
Примечание 2: Обязательно удалите ветку с помощью 'git branch -d work' между слиянием и dcommit: если вы попытаетесь удалить ветку после dcommit, вы получите сообщение об ошибке: Когда вы делаете 'git svn dcommit', git забывает, что ваша ветвь была объединена с 'master'. Вы должны удалить его с помощью 'git branch -D work', который не выполняет проверку безопасности.
Теперь я немедленно создаю новую ветку 'работа', чтобы избежать случайного взлома ветки 'master':
$> git checkout -b work
$> git branch # show my branches:
master
* work
Интеграция вашей "работы" с изменениями в svn: Вот что я делаю, когда "git svn rebase" показывает, что другие изменили репозиторий svn, когда я работал над моей веткой "работа":
$> git checkout master
$> git svn rebase # 'svn pull' changes
$> git checkout work # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed
$> git checkout master # try again to push my changes
$> git svn rebase # hopefully no further changes to merge
$> git merge integration # (1) merge your work with theirs
$> git branch -d work # (2) remove branches that are merged
$> git branch -d integration # (2) remove branches that are merged
$> git svn dcommit # (3) push your changes to the svn repository
Существуют более мощные решения: представленный рабочий процесс упрощен: он использует возможности git только в каждом раунде "update / hack / dcommit" - но оставляет долгосрочную историю проекта столь же линейной, как и хранилище svn. Это нормально, если вы просто хотите начать использовать git merges небольшими первыми шагами в устаревшем проекте svn.
Когда вы познакомитесь с git merging, не стесняйтесь исследовать другие рабочие процессы: если вы знаете, что делаете, вы можете смешивать git merges с svn merges ( используя git-svn (или аналогичный) просто для того, чтобы помочь с svn merge?)
Ответ Грега Хьюгилла сверху небезопасен! Если между двумя "git svn rebase" в транке появились какие-либо новые коммиты, слияние не будет происходить быстро.
Это может быть обеспечено использованием флага "--ff-only" для git-merge, но я обычно не запускаю "git svn rebase" в ветке, только "git rebase master" на нем (при условии, что это только локальный ветка). Тогда после этого "git merge thebranch" будет гарантированно ускорен.
Безопасный способ объединить svn-ветки в git - это использовать git merge --squash. Это создаст единый коммит и остановит вас, чтобы добавить сообщение.
Допустим, у вас есть тема svn branch, которая называется svn-branch.
git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch
к этому моменту все изменения из svn-ветви сведены в один коммит, ожидающий в индексе
git commit
Перебазируйте локальную ветку git на главную ветку git, затем dcommit, и похоже, что вы сделали все эти коммиты последовательно, чтобы svn люди могли видеть это линейно, как они привыкли. Итак, если у вас есть локальная ветка с названием topic, вы можете сделать
git rebase master topic
который затем будет воспроизводить ваши коммиты через главную ветку, готовую для вас