Переключение команды с Git Merge на Rebase
Наш отдел исследований и разработок работает с двумя центральными репозиториями, которые изначально были созданы очень упрямыми умными людьми, один работает с ребазингами, а другой - с gitflow и слияниями. Хотя я очень удобен в использовании слияний и вижу, что большинство проектов github используют эту модальность, мы вынуждены согласиться на "ребазинг", поскольку мы переходим к более организованной системе обзора кода Gerrit, и многие разработчики переходят на наш репо из другой команды.
Итак, вот оно: меня предупреждают man-страницы о том, что нельзя смешивать ребазинг и слияние, теперь я должен сменить всю свою команду. Интересно, как это сделать без особого риска для стабильности нашего кода. У людей всегда есть открытая ветвь функций или два, и во время разработки они могут сливаться с dev несколько раз. Можно ли использовать такие ветви функций, чтобы просто переключиться на перебазирование, или день завершения должен быть только после того, как все ветви функций будут объединены первыми, и не существует никаких ветвей с слияниями в их истории с момента создания fork? Как я планирую это как плавный переход?
2 ответа
Я бы сказал, что вам нужно понимать и использовать как merge, так и re base для работы с git (и особенно с gerrit).
Некоторые примеры...
Вы бы слились, когда вы подняли свою ветвь функций на новый удаленный мастер. Это дает минимальную работу по подъему и легко отслеживать историю развития функции, например, в gitk.
git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature
Вы объединитесь, когда будете готовить коммит доставки (с --squash
опция, поскольку никакие коммиты слияния не разрешены в master
).
git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master
Вы перебазируете, когда фиксация доставки не удастся интегрировать по любой причине, и вам нужно будет обновить ее до нового удаленного мастера.
git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master
Я вижу, что основная проблема в смешивании слияний и ребазирования заключается в том, что когда вы делаете ребазинг, он "линеаризует" историю, и это не очень хорошо работает с коммитами слияния. Но сама линеаризация на самом деле имеет свои достоинства, так как история становится проще и легче рассуждать.
Самая простая стратегия - избежать слияний. В тот момент, когда можно было бы сказать раньше git merge X
делать git rebase X
вместо.
Это не так уж и плохо, за исключением случаев, когда у вас есть несколько коммитов в вашей локальной ветке, и один из них вызывает конфликт слияния при перебазировании. Дальнейшие фиксации в том же месте могут приводить к одному и тому же конфликту слияния снова и снова. Обходной путь в таком случае может состоять в том, чтобы прервать ребаз git rebase --abort
и либо переставить локальные коммиты с git rebase --interactive
или сквош местные коммиты (git reset $(git merge-base HEAD X)
). Повторите ребаз после этого.
Особое внимание при проведении ребазинга должно быть уделено общим веткам. При опровержении этого потребуется синхронизация человека, и многие предпочитают ее вообще избегать, см. Ниже:
Другой подход заключается в том, чтобы принимать слияния из апстрима во время разработки и выполнять сквош перед слиянием / выполнением запроса на извлечение, например:
git checkout -b Work
#work...commit...commit..
git merge X
#work...commit...commit..
git merge X
git reset X && git add . && git commit -m 'All my work squashed'
#alternatively the last part might be like this:
git checkout X && git merge --squash Work
Преимущество этого подхода заключается в том, что вы можете относительно безопасно разделять такую ветку без дополнительных затрат на общение с людьми. Также часто легче разрешать конфликты при объединении двух ветвей, чем при воспроизведении одной ветви поверх другой.