Каков наилучший (и самый безопасный) способ объединить ветку Git с master?


2105

Создается новая ветка из master, мы называем это test.

Есть несколько разработчиков, которые либо фиксируют, masterлибо создают другие ветви, а затем объединяются master.

Допустим, работа над этим testзанимает несколько дней, и вы хотите постоянно получать testобновления с коммитами внутри master.

Я бы сделал git pull origin masterиз test.

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


Моя работа testзавершена, и я готов объединить ее с master. Вот два способа, о которых я могу думать:

A:

git checkout test
git pull origin master
git push origin test
git checkout master
git pull origin test 

B:

git checkout test
git pull origin master
git checkout master
git merge test

Я не использую, --rebaseпотому что, насколько я понимаю, rebase получит изменения masterи поставит мои поверх этого, следовательно, может перезаписать изменения, сделанные другими людьми.

Вопрос 2: Какой из этих двух методов является правильным? Какая там разница?

Цель всего этого состоит в том, чтобы держать мою testветку в курсе происходящих событий, masterи позже я смогу объединить их в masterнадежде сохранить временную шкалу как можно более линейной.


18
нет .. rebase никогда не перезаписывает, просто пытается добиться более чистой истории. путем повторного присоединения (или подделки) истории к поздней точке мастера
Junchen Liu

7
rebase не перезаписывает ваши коммиты. Он отменяет ваши коммиты, применяет коммиты в ветке master к вашей тестовой ветке, а затем применяет ваши коммиты обратно к тесту.
Зунди

Ответы:


2995

Как бы я это сделал

git checkout master
git pull origin master
git merge test
git push origin master

Если у меня есть локальная ветвь с удаленной, я не чувствую себя комфортно, объединяя другие ветви, кроме этой, с удаленной. Кроме того, я не буду продвигать свои изменения, пока я не буду доволен тем, что я хочу подтолкнуть, а также я вообще не буду продвигать вещи, которые предназначены только для меня и моего локального хранилища. По твоему описанию кажется, что testэто только для тебя? Так что нет причин публиковать его.

git всегда старается уважать ваши и чужие изменения, и так будет --rebase. Я не думаю, что могу объяснить это должным образом, поэтому взгляните на книгу по Git - Rebasing или git-ready: введение в ребазинг для небольшого описания. Это довольно крутая особенность


2
git merge testдает мне fatal: 'test' does not point to a commit. Я должен искать git logточку фиксации в тестовой ветке, переключиться обратно в главную ветвь и затем сделать git merge 0f37d3154abbf52a4cbbbb5109f08af6a7567234.
Duncanmoo

17
@Duncanmoo Ну, конечно, ветвь testдолжна существовать. Конечно, вы можете использовать хеш коммита, но обычно проще использовать имя ветки. Внутренне он просто получает хеш HEADветки.
KingCrunch

44
@shanyangqu Чтобы получить последние изменения с пульта. Если вы работаете один и только с одной системой, проблем нет. Но когда есть изменения, выдвинутые из другой системы (возможно, от другого разработчика), вы увидите конфликт, как только вы попытаетесь отменить слияние (4-й шаг). Единственное решение теперь состоит в том, чтобы объединить ваш локальный мастер с мастером удаленных устройств, что в итоге приводит к довольно уродливому коммиту слияния «объединенный мастер с источником / мастером». Так что всегда хорошая идея сделать тягу до слияния
KingCrunch

7
«В вашем описании кажется, что этот тест только для вас? Так что нет причин его публиковать». Возможно, вы захотите перенести свою локальную ветку на сервер, если, например, этот сервер обеспечивает резервное копирование на случай сбоя локального диска или если у вас нет другого способа сделать резервную копию.
Эрик

5
«... Кроме того, я бы не стал настаивать на своих изменениях, пока я не доволен тем, что я хочу подтолкнуть ...», почему бы не настаивать на резервном копировании вашего кода, если ваши локальные машины умирают и дни усилий пропали?
Рич Стоун

400

Это очень практичный вопрос, но все ответы выше не практичны.

подобно

git checkout master
git pull origin master
git merge test
git push origin master

Этот подход имеет две проблемы :

  1. Это небезопасно, потому что мы не знаем, есть ли какие-либо конфликты между тестовой ветвью и главной ветвью.

  2. Это "сжало бы" все тестовые коммиты в один коммит слияния на master; то есть в основной ветке, мы не можем видеть все журналы изменений тестовой ветви.

Поэтому, когда мы подозреваем, что возникнут некоторые конфликты, мы можем выполнить следующие операции git:

git checkout test
git pull 
git checkout master
git pull
git merge --no-ff --no-commit test

Тестируйте mergeраньше commit, избегайте ускоренной фиксации --no-ff,

Если возникает конфликт, мы можем запустить, git statusчтобы проверить детали о конфликтах и ​​попытаться решить

git status

Раз мы решаем конфликты или, если нет конфликта, мы commitи pushони

git commit -m 'merge test branch'
git push

Но этот путь утратит историю изменений, записанную в тестовой ветке, и это затруднит понимание главной веткой главной ветки для других разработчиков.

Поэтому лучший метод - использовать rebaseвместо merge(предположим, когда за это время мы разрешили конфликты ветвей).

Ниже приведен один простой пример, для продвинутых операций, пожалуйста, обратитесь к http://git-scm.com/book/en/v2/Git-Branching-Rebasing.

git checkout master
git pull
git checkout test
git pull
git rebase -i master
git checkout master
git merge test

Да, когда вы сделали верх, все коммиты ветки Test будут перенесены на верх ветки Master. Основным преимуществом перебазирования является то, что вы получаете линейную и намного более чистую историю проекта.

Единственное, чего вам следует избегать: никогда не используйте rebaseв публичной ветке, как master ветка.

Никогда не выполняйте операции, подобные следующим:

git checkout master
git rebase -i test

Подробности для https://www.atlassian.com/git/tutorials/merging-vs-rebasing/the-golden-rule-of-rebasing.

приложение:


4
Я согласен, что откат тестовой ветки для последующего слияния с мастером - это путь. Даже если другие ответы верны, это сохранит историю изменений отраслевого теста в голове мастера, так как автор упоминает: «Вы получаете линейный и намного более чистый проект», который является целью системы контроля версий.
le0diaz

16
Утверждение «это не единственный путь безопасности, потому что мы не знаем, есть ли конфликты между тестовой ветвью и главной ветвью», неверно: всегда можно прервать слияние. И даже если нет конфликтов, вы всегда можете отменить последний локальный коммит, если он не выдвинут. Без правильного понимания мерзавца некоторые вещи могут показаться немного пугающими или неясными, но «небезопасные» просто неверны в любом случае. Пожалуйста, будьте осторожны, чтобы не перепутать других с неверной информацией.
Пол ван Леувен

4
согласно с @PaulvanLeeuwen, когда вы GIT сливаться тестовой ветвью в мастер, вы будете уведомлены о конфликтах, и то , где вы будете шаг и объединить изменения. Как только вы закончите, вы совершите слияние и отодвинетесь. Если вы сожалеете или не можете объединить его правильно, вы всегда можете отказаться от своей работы и снова отстраниться от мастера. Так что это точно не небезопасно ..
Хуан

3
зачем ребазировать -i?
MushyPeas

8
Перебазирование по своей природе более опасно, чем слияние. Предложение перебазирования в качестве более безопасного варианта слияния неверно. Перебазирование является действительной стратегией, но содержит больше предостережений, о которых пользователь должен остерегаться.
Икке

90

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

Обычный подход при разработке

git checkout master
git pull
git checkout test
git log master.. # if you're curious
git merge origin/test # to update your local test from the fetch in the pull earlier

Когда вы будете готовы вернуться к мастеру,

git checkout master
git log ..test # if you're curious
git merge test
git push

Если вы беспокоитесь о том, чтобы что-то сломать в процессе слияния, git merge --abortэто для вас.

Использовать толчок, а затем тянуть как средство слияния глупо. Я также не уверен, почему вы продвигаете тест на происхождение.


1
Этот процесс увеличит количество коммитов, каждый раз, когда вы переключаетесь между ветками, вы должны фиксировать свою ветку.
iBug

2
Какая? Вы говорите, что это будет увеличивать количество коммитов каждый раз, когда вы переключаете филиалы? Или вы говорите, что каждый раз, когда вы переключаете ветви, вы должны «зафиксировать свою ветку»? Первое не соответствует действительности, и я не уверен, что означает второе.
Райлу

перед оформлением заказа вы должны совершить переход. это то, что я говорю
iBug

11
Вы не: это (одна из вещей) git stashдля.
мсэнфорд

1
Или вы можете изменить свой последний коммит (в локальной ветке) и сделать его идеальным перед нажатием.
whihathac

42

Сначала я бы сделал ветвь, которая должна быть объединена, максимально чистой. Запустите свои тесты, убедитесь, что состояние соответствует желаемому. Убери новых коммитов с помощью git squash .

Помимо ответа KingCrunches , я предлагаю использовать

git checkout master
git pull origin master
git merge --squash test
git commit
git push origin master

Вы могли сделать много коммитов в другой ветке, которая должна быть только одна коммит в основной ветке. Чтобы сохранить историю коммитов настолько чистой, насколько это возможно, вы можете сжать все свои коммиты из тестовой ветки в один коммит в основной ветке (см. Также: Git: сквошить или не сквошить? ). Затем вы также можете переписать сообщение коммита в нечто очень выразительное. Что-то, что легко читать и понимать, не копаясь в коде.

редактировать: вы можете быть заинтересованы в

Так что на GitHub, я в конечном итоге сделать следующее для функциональной ветви mybranch :

Получить последнюю версию от происхождения

$ git checkout master
$ git pull origin master

Найдите базовый хеш слияния:

$ git merge-base mybranch master
c193ea5e11f5699ae1f58b5b7029d1097395196f

$ git checkout mybranch
$ git rebase -i c193ea5e11f5699ae1f58b5b7029d1097395196f

Теперь убедитесь, что только первое pick, остальное s:

pick 00f1e76 Add first draft of the Pflichtenheft
s d1c84b6 Update to two class problem
s 7486cd8 Explain steps better

Затем выберите очень хорошее сообщение коммита и нажмите на GitHub. Сделайте запрос на извлечение.

После объединения запроса на удаление вы можете удалить его локально:

$ git branch -d mybranch

и на GitHub

$ git push origin :mybranch

« который должен быть только один коммит в ветке master », ну не обязательно; Вы можете wekk хотеть сохранить историю
Cocowalla

Конечно. Но тогда просто не раздавите коммитов
Мартин Тома

Я думаю, что --first-parent кажется лучшим решением. davidchudzicki.com/posts/first-parent
bkribbs

7

Старый поток, но я не нашел свой способ сделать это. Это может быть полезно для тех, кто работает с rebase и хочет объединить все коммиты из ветви (feature) поверх master. Если на пути возникнет конфликт, вы можете разрешить его для каждого коммита. Вы сохраняете полный контроль над процессом и можете прервать его в любое время.

Получить Мастер и Филиал в актуальном состоянии:

git checkout master
git pull --rebase origin master
git checkout <branch_name>
git pull --rebase origin <branch_name>

Слияние веток поверх мастера:

git checkout <branch_name>
git rebase master

Необязательно: Если вы столкнетесь с конфликтами во время перебазирования:

Сначала разрешите конфликт в файле. Затем:

git add .
git rebase --continue

Нажмите на ваш перебазированный филиал

git push origin <branch_name>

Теперь у вас есть два варианта:

  • А) Создайте PR (например, на GitHub) и объедините его там через пользовательский интерфейс
  • Б) Вернитесь в командную строку и объедините ветку в мастер
git checkout master
git merge --no-ff <branch_name>
git push origin master

Выполнено.


6

Это рабочий процесс, который я использую на работе в команде. Сценарий такой, как вы описали. Во-первых, когда я testзаканчиваю работу, я делаю ребаз с мастером, чтобы добавить все, что было добавлено к мастеру за время работы над testветкой.

git pull -r upstream master

Это подтянет изменения к мастеру, так как вы разветвили testветвь и применили их, а затем примените сделанные вами изменения, чтобы проверить «поверх» текущего состояния мастера. Здесь могут возникнуть конфликты, если другие люди внесли изменения в те же файлы, которые вы редактировали в тесте. Если они есть, вам придется исправить их вручную и зафиксировать. Как только вы это сделаете, вам будет удобно переключиться на основную ветку и объединиться testбез проблем.


3
git checkout master
git pull origin master
# Merge branch test into master
git merge test

Если после слияния файл был изменен, то при слиянии произойдет ошибка «Разрешить конфликт».

Итак, вам нужно сначала разрешить все ваши конфликты, затем вы должны снова зафиксировать все ваши изменения и затем нажать

git push origin master

Это лучше делать тем, кто внес изменения в тестовую ветку, потому что он знал, какие изменения он сделал.


3

Я бы использовал метод rebase. Главным образом потому, что он идеально отражает ваш случай семантически, т.е. то, что вы хотите сделать, это обновить состояние вашей текущей ветви и «притвориться», как будто оно основано на последней версии.

Итак, даже не проверяя master, я бы:

git fetch origin
git rebase -i origin/master
# ...solve possible conflicts here

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


2

Ответ @ KingCrunch должен работать во многих случаях. Одна из проблем, которая может возникнуть, это то, что вы находитесь на другой машине, которой необходимо извлечь последние данные из теста. Итак, я рекомендую сначала потянуть тест. Редакция выглядит так:

git checkout test
git pull
git checkout master
git pull origin master
git merge test
git push origin master

0

Вы должны проверить ветку, чтобы вытащить, так как вытащить означает слияние с мастером, и вам нужно рабочее дерево для слияния.

git checkout master
git pull

Нет необходимости проверять сначала; rebase правильно делает с двумя аргументами

git rebase master test  

git checkout master
git merge test

git push по умолчанию выталкивает все ветки, которые существуют здесь и на удаленном

git push
git checkout test

0

Поскольку заголовок гласит «Лучший способ», я думаю, что это хорошая идея, чтобы рассмотреть стратегию слияния терпения .

От: https://git-scm.com/docs/merge-strategies

С этой опцией 'merge-recursive' тратит немного больше времени, чтобы избежать ошибочных слияний, которые иногда возникают из-за несущественных совпадающих строк (например, фигурные скобки из разных функций). Используйте это, когда ветви, которые будут объединены, сильно разошлись. Смотрите также git-diff [1] --patience.

Применение:

git fetch
git merge -s recursive -X patience origin/master

Git Alias

Для этого я всегда использую псевдоним, например, запускаю один раз:

 git config --global alias.pmerge 'merge -s recursive -X patience'

Теперь вы можете сделать:

git fetch
git pmerge origin/master


0

Я отвечу в соответствии с разработкой и особенностями веток,

если вы находитесь в функциональной ветке и вам нужно обновить ее с помощью команд разработки, используйте следующие команды: git checkoutvelop git pull git checkout feature / xyz git merge development

Теперь ваша функция обновляется с разработкой, вы можете нажать ваши изменения.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.