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

Разница между git merge и rebase

· 5 мин. чтения

1. Обзор

Работая с git в качестве нашей системы контроля версий (VCS), мы можем следовать любой из стратегий ветвления, но в конечном итоге нам может понадобиться интегрировать изменения из одной из веток функций в основную или основную ветку.

В этом руководстве мы рассмотрим два разных способа интеграции изменений из одной ветки в другую.

2. Перебазировать Git

Проще говоря, git rebase берет всю вашу функциональную ветку и перемещает ее в конец основной ветки . Он создает новые коммиты для каждого коммита в исходной функциональной ветке.

Давайте создадим новый репозиторий и ветку функций в репозитории, чтобы понять, как работает перебазирование:

git clone <your_repository_here>
git branch testBranch1
git branch testBranch2

Давайте создадим новый файл в функциональной ветке testBranch1 и зафиксируем изменения:

git add .
git commit -m "<Commit_Message_Here>"
git push --set-upstream origin testBranch1
git log

Выполнение этих команд даст нам вывод ниже:

./91b52574290ca05b4b1e7c516ff5b8b6.jpg

Теперь давайте попробуем перебазировать эту ветку на основную ветку:

git rebase main

Это приведет к следующему сообщению:

./d4e403409f135facee02576139534181.jpg

Так как в основной ветке нет коммитов, как видно из вышеизложенного, ожидать каких-либо изменений не стоит.

Теперь давайте объединим ветку функций с основной веткой:

git checkout main
git merge testBranch1
git push
git log

Эти команды выведут следующее:

./8b551fdc74fb7ccf9c4a583ed2a3a749.jpg

Идентификаторы коммитов из ветки функций не изменяются при слиянии с основной веткой. Это похоже на то, что происходит при быстром слиянии.

Поскольку мы уже объединили testBranch1 с основной веткой, в testBranch2 отсутствуют коммиты, из которых она была вырезана.

Давайте посмотрим, как происходит перебазирование и слияние testBranch2 .

Давайте создадим новый файл в функциональной ветке testBranch2 и зафиксируем изменения:

git checkout testBranch2
git add .
git commit -m "<Commit_Message_Here>"
git push --set-upstream origin testBranch2
git log

И после выполнения этих команд мы увидим:

./3efcaa7f87b00019f1b1933da37e92f1.jpg

Теперь попробуем перебазировать эту ветку на основную ветку:

git rebase main

И это должно дать нам сообщение, отличное от предыдущего случая:

./dd651cbbbd70ed405e9a9bf738528d57.jpg

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

git checkout main
git merge testBranch2
git push
git log

Эти команды выведут следующее:

./20ed91db8b0b08387cd106ac0e70e1d4.jpg

Идентификаторы коммитов отличаются, как и ожидалось, и если мы посмотрим на график журнала git, мы увидим, что репо имеет линейную историю:

git log --graph --oneline

Приведенная выше команда показывает структуру графа, отображающую информацию о коммите в одной строке:

./09cc2878813eef8d48be9c93e61f36de.jpg

3. Слияние Git

Git merge возьмет две ветки, которые мы объединяем, найдет общий базовый коммит, а затем воспроизведет последовательность коммитов из двух веток в базовом коммите, чтобы объединить ветки .

Давайте создадим новый репозиторий и пару веток функций, чтобы понять, как работает слияние:

Клонируйте репозиторий на свой локальный компьютер и создайте новую ветку функций:

git clone <your_repository_here>
git branch testBranch1
git branch testBranch2

Давайте создадим новый файл в функциональной ветке testBranch1 и зафиксируем изменения:

git add .
git commit -m "<Commit_Message_Here>"
git push --set-upstream origin testBranch1
git log

Выполнение этих команд даст нам вывод ниже:

./634f2e0eba218be2ea3d0c1556ddc8ec.jpg

Теперь давайте объединим эту функциональную ветку с основной веткой с помощью команды слияния:

git checkout main
git merge testBranch1
git push
git log

Эти команды выведут следующее:

./7f3f0d6a65522ae636dc6e72c46342dc.jpg

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

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

Давайте рассмотрим другой сценарий, в котором есть изменения как в основной, так и в функциональной ветке, и как git их обрабатывает.

Давайте создадим новый файл в функциональной ветке testBranch2 и зафиксируем изменения:

git checkout testBranch2
git add .
git commit -m "<Commit_Message_Here>"
git push --set-upstream origin testBranch2
git log

И после выполнения этих команд мы получим следующее:

./4049a3df0df563d3fb94d3b4251b679c.jpg

Теперь давайте объединим эту функциональную ветку с основной веткой с помощью команды слияния:

git checkout main
git merge testBranch2
git log

Затем мы можем увидеть это в терминале:

./ef4d3b6197998a4444e8ea312b118b26.jpg

Существует отдельный коммит слияния, на который сейчас указывает HEAD, в то время как исходные коммиты присутствуют для обеих ветвей функций. Самый верхний коммит также имеет дополнительный информационный ключ «Слияние», в котором указаны идентификаторы коммитов для обеих ветвей.

Мы также можем проверить граф ветвей и проверить историю репозитория:

git log --graph --oneline

Приведенная выше команда показывает структуру графа, отображающую информацию о коммите в одной строке:

./596d26d41c922a97ee9b3f1a1f1d9310.jpg

4. Варианты использования

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

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

5. Вывод

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