git rebase -i <ref>
rebase -i
An interactive rebase is one of the most powerful tools that git provides. You can reorder, edit, rename, squash and remove commits that have happened, producing a clean git history.
Try an interactive rebase on the workshop git repo:
git rebase -i HEAD~4
You’ll get an open screen within Vim that allows you to command git, telling it what to do with each commit
1 pick c890001 thirdcommit
2 pick 87b5eff forth commit
3 pick 5fd910b added important file
4 pick 7c39e9e rename to file
5
6 # Rebase 16797ce..7c39e9e onto 16797ce (4 commands)
7 #
8 # Commands:
9 # p, pick <commit> = use commit
10 # r, reword <commit> = use commit, but edit the commit message
11 # e, edit <commit> = use commit, but stop for amending
12 # s, squash <commit> = use commit, but meld into previous commit
13 # f, fixup <commit> = like "squash", but discard this commit's log message
.
.
.
A few things to note here:
Let’s smush two commits together, picking this one to lose the commit message using a fixup
2 fixup 87b5eff forth commit
If we then save the file using :wq
, git will merge these two commits together, and it’ll look like we did both in the same commit - magic!
c890001 thirdcommit
87b5eff forth commit
See what happened with a git log
$ git log --oneline --decorate --all --graph
* ea54536 (HEAD -> branch) rename to file
* 7b4f35b added important file
* e58222c thirdcommit
| * 5fd910b (master) added important file
| * 87b5eff (branch_a) forth commit
| * c890001 thirdcommit
|/
* 16797ce (tag: first_commit_tag) first commit m8
Huh?! We’re now diverging the history away from master
since we’ve rebased. This is because the common history between the branch
and master
branches has now changed. master
and branch_a
still has 87b5eff forth commit
.
This is why we need to be very careful rebasing.
commit --amend
For ninja edits to just last committed change, you can use the shortcut git commit --amend
. It effectively does a fixup
for just that last commit. All the same rules apply with common history though, as the commit’s identity will change.
$ echo 123 > test
$ git add test
$ git commit -m 'testing file'
$ echo 456 >> test
$ git add test
$ git commit --amend --no-edit
$ git log --oneline --decorate --all --graph
$ cat test
With great power, comes great responsibility. We’ll now look at rebasing safely and changing common history