28. Rebase
Goals
- To use
rebase
instead of themerge
command.
We have reverted the style
branch to the point in history before the first merge. There are two commits that are in the main
branch, but not in the style
branch: the new README
file and that conflicting change in the index.html
file. This time, we will move these changes to the style
branch using the rebase
command rather than merge
.
01 Rebase the style
branch onto main
Run
git switch style
git rebase main
git status
Result
$ 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")
There's a conflict again! Note that the conflict is in hello.html
, not in index.html
as the last time. It is because rebase
was in the process of applying the style
changes on top of the main
branch. The file hello.html
hasn't been renamed in main
yet, so it still has its old name.
When merging, we would have a "reverse" conflict. During the merge, the changes of the main
branch are applied on top of the style
branch. The style
branch has the file renamed, so the conflict would be in index.html
.
File: 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 Resolve the conflict
The conflict itself can be resolved in the same way we did before. First, we edit the hello.html
file to meet our expectations.
File: 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>
But after that, we don't need to commit the changes. We can just add the file to the index and continue the rebase process. This is why I love rebase! It allows me to fix conflicts without creating a bunch of ugly merge conflicts.
For simplicity's sake, we can add all files using
.
, which stands for the path of the current directory. Git interprets this as "add all files in the current directory and its subdirectories".
Run
git add .
git rebase --continue
Here, most likely, Git will open the editor again, to let us change the commit message. We can leave the message as it is. Upon saving changes, Git will finish the rebase process, and we can proceed with the following commands:
Run
git status
git log --all --graph
Result
$ 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 Merging VS rebasing
The result of the rebase
command looks much like that of the merge
command. The style
branch currently contains all its changes, plus all the changes of the main
branch. The commit tree, however, is a bit different. The style
branch commit tree has been rewritten to make the main
branch a part of the commit history. This makes the chain of commits linear and more readable.
04 When to use the rebase
command, and when the merge
command?
Use the rebase
command:
- When you fetch changes from a remote repository and want to apply them to your local branch.
- If you want to keep the commit history linear and easy to read.
Don't use the rebase
command:
- If the current branch is public and shared. Rewriting such branches will hinder the work of other team members.
- When the exact commit branch history is important (because the
rebase
command rewrites the history of commits).
Given the above recommendations, I prefer to use rebase
for short-term, local branches and the merge
command for branches in the public repository.