Перейти к содержимому

Как подтянуть изменения из master в свою ветку

  • автор:

Git для начинающих. Урок 9.
Слияния или мерджи веток

Краткое содержание урока, основные инструкции для командной строки, полезные ссылки и советы.

Ветка master — еще раз

Мастер — это основная ветка проекта, в которую заливается только рабочий проверенный код. Новый функционал в конце концов оказывается в мастере. В этой ветке находится тот же самый код, что и на боевом сайте

В различных компаниях и командах могут быть приняты другие соглашения насчет веток. Например, что весь функционал сначала сливается в промежуточную ветку. Но в наших уроках мы будем исходить из того, что ветка мастер — главная и в нее в итоге заливаются все остальные ветки

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

Что такое мердж или слияние веток

Это перенос кода из одной ветки в другую. Например, когда мы заканчиваем работу над веткой, например, сделали новый функционал или поправили багу, мы сливаем ее в мастер. В мастере код проверяется еще раз и выкладывается на боевой сервер.

Сливать друг в друга можно любые ветки. Технически, с точки зрения git нет никакой разницы, сливается ветка с новым функционалом в мастер или наоборот. Для нас мастер — это основная ветка разработки, а для git это просто ветка.

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

Мастер сливается в ветку или мастер подтягивается в ветку, когда мы продолжаем работать над веткой, но хотим периодически подтягивать новые коммиты с сервера — новый код, который написали наши коллеги. Если работа над веткой идет довольно долго, есть смысл подтягивать изменения из мастера хоть каждый день.

Следует четко различать мердж своей ветки в мастер и мердж мастера в свою ветку.

Мердж ветки в мастер

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

 $ git checkout master $ git merge news 

При этом возможны разные ситуации

Поговорим о них подробнее

Пока мы работали над веткой, в мастере не появилось новых коммитов

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

 $ git merge news Updating f32b91e..33ea897 Fast-forward index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) $ git push origin master $ git branch -d news 

Git понимает, что это новый код, который можно просто положить поверх старого. Это простая ситуация и git не задает никаких вопросов.

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

Теперь другая ситуация.

Пока мы работали над веткой, в мастере появились коммиты от коллег

Сначала переключаемся на мастер

 $ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'. 

Почему «is up-to-date»? Потому что мы еще не сделали git pull. Делаем

 $ git pull --rebase origin master 

Мерджим свою ветку в мастер

 $ git merge news-styles 

И не забываем запушить изменения

 $ git push origin master 

Что если сначала не подтягивать мастер, а смерджить свою ветку

Принципиально ничего не изменится, но лучше сначала сделать актуальной ветку мастер, а уже потом заливать свои изменения. А еще лучше держать актуальной свою ветку относительно мастера. Это значит, что стоит почаще подтягивать мастер в свою ветку. Таким образом мы в своей ветке будем работать с актуальным кодом и у нас меньше риска что-нибудь поломать. А если поломаем, то лучше чинить это в своей ветке, а не в мастере.

Как вмерджить мастер в свою ветку

Сначала идем в мастер, подтягиваем изменения с сервера, то есть делаем git pull. Затем переключаемся в свою ветку и делаем git merge master

 $ git checkout master $ git pull --rebase origin master $ git checkout news-redesign $ git merge master 

Затем проверяем, что ничего не поломалось и продолжаем работать.

Мердж коммиты

Чем чаще мерджить между собой ветки, тем больше появляется так называемых мердж-коммитов. Такой коммит появляется каждый раз, когда мы подтягиваем мастер в свою ветку или сливаем свою ветку в мастер. Эти коммиты не хранят изменений, они хранят только факт мерджа одной ветки в другую.

Посмотрим список коммитов и найдем мердж-коммит с хэшем 051f754

 $ git log --oneline 051f754 Merge branch 'news' . 

Посмотрим его содержимое

 $ git show 051f754 commit 051f75475cb1dca3cd08c1c7367a3308671ccf7b Merge: 0a3a6a3 2346be5 Author: Alexandr Shestakov Date: Sat Feb 8 14:10:39 2020 +0300 Merge branch 'news' 

То есть информация только о том, что в мастер была залита ветка news. Сами изменения в файлах, которые мы делали в ветке news, лежат в других коммитах.

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

Плюс в том, что у нас есть возможность выбора — git позволяет обходиться без таких коммитов вообще. Тогда история коммитов будет содержать только изменения в коде, а не операции с ветками. Это достигается механизмом ребейза, но это тема, которая выходит за рамки первой курса. Ребейз, его плюсы и минусы, мы подробно рассмотрим во второй части курса.

Также можете почитать мою старую статью — Отличия мерджа от ребейза.
В ней нет видеоурока, но наглядно объясняется на скриншотах.

Мерджи всегда проходят так гладко?

К сожалению, нет

В этом уроке мы намеренно упрощали ситуацию и рассматривали случаи, когда наши коллеги делают изменения в других участках кода. То есть мы с ними даже не пересекались. В реальной жизни так происходит не всегда. Иногда мы правим одни и те же участки кода и тогда при их слиянии git не может понять, чей вариант правильный. Это называется возникновения конфликта.

Подробнее о конфликтах и их разрешении мы поговорим в следующем уроке.

Git merge без конфликта

Что могу посоветовать

  • Не забывайте, что мастер — это продакшен, это рабочая версия кода, которую не стоит ломать
  • В мастер не сливается незаконченная работа, только полностью рабочий и проверенный функционал
  • Перед мерджем своей ветки в мастер, подтягивайте изменения в мастер с сервера
  • После мерджа в мастер, не забывайте пушить эти изменения
  • Подтягивайте мастер в свою ветку почаще
  • Мердж-коммиты несут информацию только о факте слияния веток. Договоритесь в команде, насколько они вам нужны
  • Познакомьтесь с механизмом ребейза, он позволяет вести чистую историю без мердж-коммитов

Спасибо за внимание и до встречи!

Все уроки курса

  • Вводный урок
  • 1. Установка и базовая настройка git
  • 2. Создание и клонирование репозитория git
  • 3. Делаем первые изменения, git status и git diff
  • 4. Коммиты и история коммитов, git commit, git log и git show
  • 5. Подробнее об истории коммитов. Путешествие по истории
  • 6. Работа с сервером, git push и git pull
  • 7. Ветки — главная фишка git, git branch и git checkout
  • 8. Работа с ветками на сервере, git fetch
  • 9. Слияния или мерджи веток, git merge
  • 10. Конфликты и их разрешение
  • Платная часть курса. Презентация
  • * 11. Работа с gitignore и git exclude
  • * 12. Буфер обмена git, git stash
  • * 13. Копирование коммитов, git cherry-pick
  • * 14. Отмена и редактирование последнего коммита
  • * 15. Отмена произвольного коммита, git revert
  • 16. Склеивание коммитов, git rebase —interactive и git reflog
  • * 17. Зачем склеивать коммиты. Плюсы и минусы сквоша
  • * 18. Работа с git rebase. Отличия от merge
  • * 19. Что такое git push —force и как с ним работать
  • * 20. Ищем баги с помощью git, git bisect
  • * 21. Как и зачем работать с тегами git
  • * 22. Процессы: github flow и git flow
  • * 23. Псевдонимы в git
  • 24. Мердж-реквесты
  • * 25. Форки

Как обновить свою ветку из master git?

Есть ветка a, и есть ветка master.
В мастер рабочая версия.
При попытке выполнить merge: git merge a ( находимся в ветке master) все проходит нормально, но при переходе в ветку a, приложение перестает правильно работать. Хочется залить в ветку а актуальный работающий код из ветки master.

Я понимаю, что можно создать новую ветку на основе мастер, но хочется обновить именно ветку a

  • Вопрос задан более трёх лет назад
  • 3631 просмотр

1 комментарий

Простой 1 комментарий

Krasnodar_etc

Егор Живагин @Krasnodar_etc

Почитайте про rebase . Это вам немного поможет + сейчас в большинстве компаний принят именно rebase-flow

Решения вопроса 1
Saboteur @saboteur_kiev Куратор тега Git
software engineer
git checkout a
git merge master
Ответ написан более трёх лет назад
Нравится 3 3 комментария

Krasnodar_etc

Егор Живагин @Krasnodar_etc

BD_ l3ftoverZ!, вместо мержа fetch использовать ну никак не выйдет 🙂
fetch не обновит ветки, он может только узнать, изменились ли они на сервере. Для обновления придётся делать pull

Saboteur @saboteur_kiev Куратор тега Git

ну тогда просто
git checkout master
git pull
git checkout a
git pull
merge master

или
git checkout a
git pull
git merge origin/master

honor8

6248aab87bc07197120348.png

Если в ветви master вносились изменения, то в консоли отобразится состояние (a|MERGING)
Если разрешаем конфликты в Github Desktop (на скриншоте обозначены символом восклицательного знака внутри треугольника), то в консоли можно просто запушить.
‘
Без отображения истории git merge —squash master , но не разрешает конфликты.
Сначала можно попробовать git pull —no-commit upstream master .

Бедросова Юлия

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

Git обновить текущую ветку из master

  • Получить ссылку
  • Facebook
  • Twitter
  • Pinterest
  • Электронная почта
  • Другие приложения

Если разработка велась в ветке, и за время этой разработки ветка master сильно изменилась, лучше не вливать ветку сразу в мастер, а сначала влить мастер в ветку – чтобы предварительно протестировать.
Для этого нужно переключиться на ту ветку, в которую мы будем вливать мастер, а затем выполнить команду

git pull origin master

Cкорее всего, после этого возникнут конфликты – гит скажет об этом.
Чтобы просмотреть все файлы, в которых произошли конфликты, нужно выполнить команду

git status

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

git pull origin master

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

  • Получить ссылку
  • Facebook
  • Twitter
  • Pinterest
  • Электронная почта
  • Другие приложения

Комментарии

Спасибо! Мне помогло.
Анонимный написал(а)…
Помогло, спасибо.
Анонимный написал(а)…
Анонимный написал(а)…
Анонимный написал(а)…
Благодарю! Очень помогло!

Популярные сообщения из этого блога

О лишних запросах

Совершенство достигается не тогда, когда уже нечего прибавить, но когда уже ничего нельзя отнять Антуан де Сент-Экзюпери Оптимизация процесса интеграции 1С Предприятия и 1С Битрикс – это неисчерпаемая тема. Чего только не увидишь порой в обработчиках событий добавления и обновления элемента инфоблока. Больше всего меня убивает, когда я вижу, что разработчики тянут из базы то, что у них и так уже есть. Пример из жизни (нет, серьезно – это реальный пример): AddEventHandler(«iblock», «OnAfterIBlockElementAdd», «BXMUpdateElement_FIELDS»); function BXMUpdateElement_FIELDS(&$arFields) < $ibe = new CIBlockElement(); $dbr = $ibe->GetList(array(), array(‘ID’=>$arFields[‘ID’]) ); while($oe = $dbr->GetNextElement()) < $arP = $oe->GetProperty(‘CML2_TRAITS’); > … > А то, что нужно – уже передано в обработчик в $arFields[‘PROPERTY_VALUES’][92] Зачем

3.6 Ветвление в Git — Перебазирование

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

Простейшее перебазирование

Если вы вернётесь к более раннему примеру из Основы слияния, вы увидите, что разделили свою работу и сделали коммиты в две разные ветки.

История коммитов простого разделения

Рисунок 35. История коммитов простого разделения

Как мы выяснили ранее, простейший способ выполнить слияние двух веток — это команда merge . Она осуществляет трёхстороннее слияние между двумя последними снимками сливаемых веток ( C3 и C4 ) и самого недавнего общего для этих веток родительского снимка ( C2 ), создавая новый снимок (и коммит).

Слияние разделённой истории коммитов

Рисунок 36. Слияние разделённой истории коммитов

Тем не менее есть и другой способ: вы можете взять те изменения, что были представлены в C4 , и применить их поверх C3 . В Git это называется перебазированием. С помощью команды rebase вы можете взять все коммиты из одной ветки и в том же порядке применить их к другой ветке.

В данном примере переключимся на ветку experiment и перебазируем её относительно ветки master следующим образом:

$ git checkout experiment $ git rebase master First, rewinding head to replay your work on top of it. Applying: added staged command

Это работает следующим образом: берётся общий родительский снимок двух веток (текущей, и той, поверх которой вы выполняете перебазирование), определяется дельта каждого коммита текущей ветки и сохраняется во временный файл, текущая ветка устанавливается на последний коммит ветки, поверх которой вы выполняете перебазирование, а затем по очереди применяются дельты из временных файлов.

Перебазирование изменений из `C4` поверх `C3`

Рисунок 37. Перебазирование изменений из C4 поверх C3

После этого вы можете переключиться обратно на ветку master и выполнить слияние перемоткой.

$ git checkout master $ git merge experiment

Перемотка ветки `master`

Рисунок 38. Перемотка ветки master

Теперь снимок, на который указывает C4′ абсолютно такой же, как тот, на который указывал C5 в примере с трёхсторонним слиянием. Нет абсолютно никакой разницы в конечном результате между двумя показанными примерами, но перебазирование делает историю коммитов чище. Если вы взглянете на историю перебазированной ветки, то увидите, что она выглядит абсолютно линейной: будто все операции были выполнены последовательно, даже если изначально они совершались параллельно.

Часто вы будете делать так для уверенности, что ваши коммиты могут быть бесконфликтно слиты в удалённую ветку — возможно, в проекте, куда вы пытаетесь внести вклад, но владельцем которого вы не являетесь. В этом случае вам следует работать в своей ветке и затем перебазировать вашу работу поверх origin/master , когда вы будете готовы отправить свои изменения в основной проект. Тогда владельцу проекта не придётся делать никакой лишней работы — всё решится простой перемоткой или бесконфликтным слиянием.

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

Более интересные перемещения

Также возможно сделать так, чтобы при перебазировании воспроизведение коммитов применялось к совершенно другой ветке. Для примера возьмём История разработки с тематической веткой, ответвлённой от другой тематической ветки. Вы создаёте тематическую ветку server , чтобы добавить в проект некоторую функциональность для серверной части, и делаете коммит. Затем вы выполнили ответвление, чтобы сделать изменения для клиентской части, и создали несколько коммитов. Наконец, вы вернулись на ветку server и сделали ещё несколько коммитов.

История разработки с тематической веткой, ответвлённой от другой тематической ветки

Рисунок 39. История разработки с тематической веткой, ответвлённой от другой тематической ветки

Предположим, вы решили, что хотите внести изменения клиентской части в основную линию разработки для релиза, но при этом не хотите добавлять изменения серверной части до полного тестирования. Вы можете взять изменения из ветки client , которых нет в server ( C8 и C9 ), и применить их на ветке master при помощи опции —onto команды git rebase :

$ git rebase --onto master server client

В этой команде говорится: «Переключись на ветку client , найди изменения относительно ветки server и примени их для ветки master ». Несмотря на некоторую сложность этого способа, результат впечатляет.

Перемещение тематической ветки, ответвлённой от другой тематической ветки

Рисунок 40. Перемещение тематической ветки, ответвлённой от другой тематической ветки

Теперь вы можете выполнить перемотку (fast-forward) для ветки master (см Перемотка ветки master для добавления изменений из ветки client ):

$ git checkout master $ git merge client

Перемотка ветки `master` для добавления изменений из ветки `client`

Рисунок 41. Перемотка ветки master для добавления изменений из ветки client

Представим, что вы решили добавить наработки и из ветки server . Вы можете выполнить перебазирование ветки server относительно ветки master без предварительного переключения на неё при помощи команды git rebase , которая извлечёт тематическую ветку (в данном случае server ) и применит изменения в ней к базовой ветке ( master ):

$ git rebase master server

Это повторит работу, сделанную в ветке server поверх ветки master , как показано на рисунке:

Перебазирование ветки `server` на вершину ветки `master`

Рисунок 42. Перебазирование ветки server на вершину ветки master

После чего вы сможете выполнить перемотку основной ветки ( master ):

$ git checkout master $ git merge server

Теперь вы можете удалить ветки client и server , поскольку весь ваш прогресс уже интегрирован и тематические ветки больше не нужны, а полную историю вашего рабочего процесса отражает рисунок Окончательная история коммитов:

$ git branch -d client $ git branch -d server

Окончательная история коммитов

Рисунок 43. Окончательная история коммитов

Опасности перемещения

Но даже перебазирование, при всех своих достоинствах, не лишено недостатков, которые можно выразить одной строчкой:

Не перемещайте коммиты, уже отправленные в публичный репозиторий

Если вы будете придерживаться этого правила, всё будет хорошо. Если не будете, люди возненавидят вас, а ваши друзья и семья будут вас презирать.

Когда вы что-то перемещаете, вы отменяете существующие коммиты и создаёте новые, похожие на старые, но являющиеся другими. Если вы куда-нибудь отправляете свои коммиты и другие люди забирают их себе и в дальнейшем основывают на них свою работу, а затем вы переделываете эти коммиты командой git rebase и выкладываете их снова, то ваши коллеги будут вынуждены заново выполнять слияние для своих наработок. В итоге, когда вы в очередной раз попытаетесь включить их работу в свою, вы получите путаницу.

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

Клонирование репозитория и выполнение в нём какой-то работы

Рисунок 44. Клонирование репозитория и выполнение в нём какой-то работы

Теперь кто-то другой внёс свои изменения, слил их и отправил на сервер. Вы стягиваете их к себе, включая новую удалённую ветку, что изменяет вашу историю следующим образом:

Извлекаем ещё коммиты и сливаем их со своей работой

Рисунок 45. Извлекаем ещё коммиты и сливаем их со своей работой

Затем автор коммита слияния решает вернуться назад и перебазировать свою ветку; выполнив git push —force , он перезаписывает историю на сервере. При получении изменений с сервера вы получите и новые коммиты.

Кто-то выложил перебазированные коммиты, отменяя коммиты, на которых основывалась ваша работа

Рисунок 46. Кто-то выложил перебазированные коммиты, отменяя коммиты, на которых основывалась ваша работа

Теперь вы оба в неловком положении. Если вы выполните git pull , вы создадите коммит слияния, включающий обе линии истории, и ваш репозиторий будет выглядеть следующим образом:

Вы снова выполняете слияние для той же самой работы в новый коммит слияния

Рисунок 47. Вы снова выполняете слияние для той же самой работы в новый коммит слияния

Если вы посмотрите git log в этот момент, вы увидите два коммита с одинаковыми авторами, датой и сообщением, что может сбить с толку. Помимо этого, если вы отправите свою историю на удалённый сервер в таком состоянии, вы вернёте все эти перебазированные коммиты на сервер, что ещё больше всех запутает. Логично предположить, что разработчик не хочет, чтобы C4 и C6 были в истории, и именно поэтому она перебазируется в первую очередь.

Меняя базу, меняй основание

Если вы попали в такую ситуацию, у Git есть особая магия чтобы вам помочь. Если кто-то в вашей команде форсирует отправку изменений на сервер, переписывающих работу, на которых базировалась ваша работа, то ваша задача будет состоять в определении того, что именно было ваше, а что было переписано ими.

Оказывается, что помимо контрольной суммы коммита SHA-1, Git также вычисляет контрольную сумму отдельно для патча, входящего в этот коммит. Это контрольная сумма называется «patch-id».

Если вы скачаете перезаписанную историю и перебазируете её поверх новых коммитов вашего коллеги, в большинстве случаев Git успешно определит, какие именно изменения были внесены вами, и применит их поверх новой ветки.

К примеру, если в предыдущем сценарии вместо слияния в Кто-то выложил перебазированные коммиты, отменяя коммиты, на которых основывалась ваша работа мы выполним git rebase teamone/master , Git будет:

  • Определять, какая работа уникальна для вашей ветки (C2, C3, C4, C6, C7)
  • Определять, какие коммиты не были коммитами слияния (C2, C3, C4)
  • Определять, что не было перезаписано в основной ветке (только C2 и C3, поскольку C4 — это тот же патч, что и C4′)
  • Применять эти коммиты к ветке teamone/master

Перемещение в начало force-pushed перемещённой работы

Рисунок 48. Перемещение в начало force-pushed перемещённой работы

Это возможно, если C4 и C4′ фактически являются одним и тем же патчем, который был сделан вашим коллегой. В противном случае rebase не сможет определить дубликат и создаст ещё один патч, подобный C4 (который с большой вероятностью не удастся применить чисто, поскольку в нём уже присутствуют некоторые изменения).

Вы можете это упростить, применив git pull —rebase вместо обычного git pull . Или сделать это вручную с помощью git fetch , а затем git rebase teamone/master .

Если вы используете git pull и хотите использовать —rebase по умолчанию, вы можете установить соответствующее значение конфигурации pull.rebase с помощью команды git config —global pull.rebase true .

Если вы рассматриваете перебазирование как способ наведения порядка и работаете с коммитами локально до их отправки или ваши коммиты никогда не будут доступны публично — у вас всё будет хорошо. Однако, если вы перемещаете коммиты, отправленные в публичный репозиторий, и есть вероятность, что работа некоторых людей основывается на этих коммитах, то ваши действия могут вызвать существенные проблемы, а вы — вызвать презрение вашей команды.

Если в какой-то момент вы или ваш коллега находите необходимость в этом, убедитесь, что все знают, как применять команду git pull —rebase для минимизации последствий от подобных действий.

Перемещение vs. Слияние

Теперь, когда вы увидели перемещение и слияние в действии, вы можете задаться вопросом, что из них лучше. Прежде чем ответить на этот вопрос, давайте вернёмся немного назад и поговорим о том, что означает история.

Одна из точек зрения заключается в том, что история коммитов в вашем репозитории — это запись того, что на самом деле произошло. Это исторический документ, ценный сам по себе, и его нельзя подделывать. С этой точки зрения изменение истории коммитов практически кощунственно; вы лжёте о том, что на самом деле произошло. Но что, если произошла путаница в коммитах слияния? Если это случается, репозиторий должен сохранить это для потомков.

Противоположная точка зрения заключается в том, что история коммитов — это история того, как был сделан ваш проект. Вы не публикуете первый черновик книги или инструкции по поддержке вашего программного обеспечения, так как это нуждается в тщательном редактировании. Сторонники этого лагеря считают использование инструментов rebase и filter-branch способом рассказать историю проекта наилучшим образом для будущих читателей.

Теперь к вопросу о том, что лучше — слияние или перебазирование: надеюсь, вы видите, что это не так просто. Git — мощный инструмент, позволяющий вам делать многое с вашей историей, однако каждая команда и каждый проект индивидуален. Теперь, когда вы знаете, как работают оба эти приёма, выбор — какой из них будет лучше в вашей ситуации — зависит от вас.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *