28. Перебазування
Цілі
- Використовувати команду
rebase
замість командиmerge
.
Ми повернули гілку style
до стану перед першим злиттям. В гілці main
є дві коміти, яких зараз немає у гілці style
: новий файл README
і конфліктна зміна у файлі index.html
. Цього разу ми перенесемо ці зміни до гілки style
за допомогою команди rebase
, а не merge
.
01 Перебазуйте гілку style
на main
.
Виконайте
git switch style
git rebase main
git status
Результат
$ git switch style
Already on 'style'
$ git rebase main
Rebasing (1/3)
Rebasing (2/3)
Auto-merging hello.html
CONFLICT (content): Merge conflict in hello.html
error: could not apply 903eb1d... Included stylesheet into hello.html
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 903eb1d... Included stylesheet into hello.html
$ git status
interactive rebase in progress; onto 85c14e9
Last commands done (2 commands done):
pick 555372e Added css stylesheet
pick 903eb1d Included stylesheet into hello.html
Next command to do (1 remaining command):
pick 0ee0113 Renamed hello.html; moved style.css
(use "git rebase --edit-todo" to view and edit)
You are currently rebasing branch 'style' on '85c14e9'.
(fix conflicts and then run "git rebase --continue")
(use "git rebase --skip" to skip this patch)
(use "git rebase --abort" to check out the original branch)
Unmerged paths:
(use "git restore --staged <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: hello.html
no changes added to commit (use "git add" and/or "git commit -a")
Знову виник конфлікт! Зверніть увагу, що конфлікт стався в hello.html
, а не в index.html
, як минулого разу. Це тому, що rebase
був у процесі застосування змін style
поверх гілки main
. У той момент в гілці main
ще не було перейменовано файл hello.html
, тому він все ще має стару назву.
При злитті виник би "зворотній" конфлікт. Під час злиття зміни гілки main
були б застосовані поверх гілки style
. У гілці style
файл перейменовано, тому конфлікт виник би у файлі index.html
.
Файл: hello.html
<!-- Author: Alexander Shvets (alex@githowto.com) -->
<html>
<head>
<<<<<<< HEAD
<title>Hello World Page</title>
=======
<link type="text/css" rel="stylesheet" media="all" href="style.css" />
>>>>>>> 903eb1d (Included stylesheet into hello.html)
</head>
<body>
<h1>Hello, World!</h1>
<p>Let's learn Git together.</p>
</body>
</html>
02 Розв'яжіть конфлікт
Сам конфлікт можна усунути так само, як ми це робили раніше. По-перше, ми відредагуємо файл hello.html
, щоб він відповідав нашим очікуванням.
Файл: hello.html
<!-- Author: Alexander Shvets (alex@githowto.com) -->
<html>
<head>
<title>Hello World Page</title>
<link type="text/css" rel="stylesheet" media="all" href="style.css" />
</head>
<body>
<h1>Hello, World!</h1>
<p>Let's learn Git together.</p>
</body>
</html>
Але після цього нам не потрібно комітити зміни. Ми можемо просто додати файл до індексу і продовжити процес перебазування. Ось за що я люблю rebase
! Ця команда дозволяє мені усувати конфлікти, не створюючи купу потворних конфліктів злиття.
Для простоти ми можемо додати всі зміни, використовуючи
.
, що означає шлях до поточної директорії. Git інтерпретує це як «додати всі зміни з поточної директорії та її піддиректорій».
Виконайте
git add .
git rebase --continue
Тут, найімовірніше, Git знову відкриє редактор, щоб дозволити нам змінити текст коміту. Ми можемо залишити текст без змін. Після збереження змін Git завершить процес rebase
, і ми зможемо виконати наступні команди:
Виконайте
git status
git log --all --graph
Результат
$ git add .
$ git rebase --continue
[detached HEAD 23149b5] Included stylesheet into hello.html
1 file changed, 1 insertion(+)
Rebasing (3/3)
[KSuccessfully rebased and updated refs/heads/style.
$ git status
On branch style
nothing to commit, working tree clean
$ git log --all --graph
* 39a1e0f 2023-11-28 | Renamed hello.html; moved style.css (HEAD -> style) [Alexander Shvets]
* 23149b5 2023-11-28 | Included stylesheet into hello.html [Alexander Shvets]
* b9e6de1 2023-11-28 | Added css stylesheet [Alexander Shvets]
* 85c14e9 2023-11-28 | Added meta title (main) [Alexander Shvets]
* ee16740 2023-11-28 | Added README [Alexander Shvets]
* 9288a33 2023-11-28 | Added copyright statement with email [Alexander Shvets]
* b7614c1 2023-11-28 | Added HTML header (tag: v1) [Alexander Shvets]
* 46afaff 2023-11-28 | Added standard HTML page tags (tag: v1-beta) [Alexander Shvets]
* 78433de 2023-11-28 | Added h1 tag [Alexander Shvets]
* 5836970 2023-11-28 | Initial commit [Alexander Shvets]
03 Злиття VS перебазування
Кінцевий результат перебазування дуже схожий на результат злиття. Гілка style
зараз містить всі свої зміни, а також всі зміни гілки main
. Однак, дерево комітів значно відрізняється. Дерево комітів гілки style
було переписано таким чином, що гілка main
є частиною історії комітів. Це робить ланцюг комітів лінійним і набагато більш читабельним.
04 Коли використовувати команду rebase
, а коли команду merge
?
Використовуйте команду rebase
:
- Коли ви підтягуєте зміни з віддаленого репозиторія і хочете злити їх до вашої локальної гілки.
- Якщо ви хочете, щоб історія комітів була лінійною і легкою для читання.
Не використовуйте команду rebase
:
- Якщо поточна гілка є загальнодоступною. Перезапис таких гілок заважатиме роботі інших членів команди.
- Коли важлива точна історія гілки комітів (оскільки команда
rebase
переписує історію комітів).
Враховуючи наведені вище рекомендації, я вважаю за краще використовувати rebase
для короткострокових, локальних гілок, а команду merge
— для гілок у публічному репозиторії.