git rebase -i <ref>
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
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 --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
master branches has now changed.
branch_a still has
87b5eff forth commit.
This is why we need to be very careful rebasing.
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