Git rebase is a powerful tool that allows you to modify your commit history in various ways. One of the most common uses of git rebase is to squash multiple commits into one, or to edit or reorder existing commits. You can do this with the interactive mode of git rebase, which can be invoked with the -i option.
In this blog post, I will show you how to use git rebase -i to rewrite your commit history and make it cleaner and more meaningful.
Contents / 目次
Basic steps of git rebase -i
The basic steps of using git rebase -i are as follows:
- Specify the range of commits that you want to rewrite with
git rebase -i <base>
, where<base>
is usually a commit hash or a branch name. For example,git rebase -i HEAD~3
will let you rewrite the last three commits on the current branch. - Git will open your default text editor with a list of commits in the specified range, along with some commands and instructions. Each line represents a commit, starting with the word “pick”. You can change the word “pick” to a different command to tell Git what to do with that commit. You can also reorder, delete, or add lines to modify the commit sequence.
- Save and close the editor. Git will then apply the commands that you specified and rewrite the commit history accordingly. If there are any conflicts or errors, Git will prompt you to resolve them before continuing.
- When the rebase is done, Git will show you a summary of the changes and the new commit hashes. You can verify that the rebase worked as expected with
git log
orgit show
. If you are satisfied with the result, you can push the rewritten history to a remote repository withgit push --force-with-lease
. If you want to undo the rebase, you can usegit reflog
andgit reset
to restore the original history.
Available commands for git rebase -i
There are six commands that you can use with git rebase -i:
- pick: This means to keep the commit as it is. You can change the order of pick commands to change the order of commits.
- reword: This is similar to pick, but it allows you to edit the commit message. The commit content is not affected.
- edit: This allows you to amend the commit. You can add, remove, or change files in the commit, or make more commits before continuing the rebase.
- squash: This allows you to combine two or more commits into one. The commit will be merged into the previous one. Git will prompt you to write a new commit message for the combined commit.
- fixup: This is similar to squash, but it discards the commit message of the merged commit. The commit will be simply merged into the previous one, and the commit message of the previous one will be used for both changes.
- exec: This allows you to run any shell command after applying each commit. You can use this to run tests or checks on your code.
Examples of using git rebase -i
Let’s see some examples of how to use git rebase -i for different scenarios.
Squashing multiple commits into one
Suppose you have made several small commits that are related to a single feature or bug fix, and you want to squash them into one big commit for clarity. You can use git rebase -i with squash or fixup commands to do this.
For example, let’s say you have these four commits on your branch:
$ git log --oneline
a3f2e4d (HEAD -> feature) Fix typo
9d3f6e2 Add more tests
4a7f2b1 Implement feature
c1f8a9d Update README
You want to squash them into one commit with a message like “Implement feature and add tests”. You can run git rebase -i HEAD~4
and change the commands like this:
pick c1f8a9d Update README
pick 4a7f2b1 Implement feature
squash 9d3f6e2 Add more tests
squash a3f2e4d Fix typo
# Rebase c1f8a9d..a3f2e4d onto c1f8a9d (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Save and close the editor. Git will then prompt you to write a new commit message for the squashed commit. You can write something like this:
Implement feature and add tests
- Update README with feature description
- Implement feature logic and interface
- Add more tests for feature functionality
- Fix typo in test file
Save and close the editor. Git will then apply the rebase and show you the result:
[detached HEAD 7a9f3b8] Implement feature and add tests
Date: Mon Dec 13 00:50:55 2021 +0900
4 files changed, 42 insertions(+), 3 deletions(-)
Successfully rebased and updated refs/heads/feature.
You can verify that the rebase worked as expected with git log
or git show
:
$ git log --oneline
7a9f3b8 (HEAD -> feature) Implement feature and add tests
Editing a previous commit
Suppose you have made a commit that contains some mistakes or omissions, and you want to edit it. You can use git rebase -i with edit command to do this.
For example, let’s say you have these two commits on your branch:
$ git log --oneline
f3a8c2d (HEAD -> feature) Add documentation
7b2f9a1 Implement feature
You want to edit the first commit to fix some typos and add some missing information. You can run git rebase -i HEAD~2
and change the command like this:
pick 7b2f9a1 Implement feature
edit f3a8c2d Add documentation
# Rebase 7b2f9a1..f3a8c2d onto 7b2f9a1 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Save and close the editor. Git will then stop at the commit that you want to edit and show you a message like this:
Stopped at f3a8c2d... Add documentation
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
You can then make any changes that you want to the files in the commit. For example, you can fix some typos in a file called docs.md
:
$ nano docs.md # or use any editor of your choice
$ git diff # to see what you have changed
diff --git a/docs.md b/docs.md
index e69de29..fc0ceaa 100644
--- a/docs.md
+++ b/docs.md
@@ -0,0 +1,6 @@
+# Feature documentation
+This is a documentation for the new feature.
+The feature does something amazing and useful.
+To use the feature, follow these steps:
+- ...
You can then add the changed files to the staging area and amend the commit with git commit --amend
. You can also edit the commit message if you want. For example:
$ git add docs.md # add any changed files that you want to include in the commit
$ git commit --amend # amend the commit with the staged changes
Add documentation for feature
- Fix some typos and grammar errors
- Add more details and examples
[detached HEAD