Merges / Interactive rebasing

git rebase -i <ref>

Interactive rebasing 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
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:

  1. If we reorder the lines above, the commits will be reordered in history.
  2. If we remove a line that commit will be lost
  3. We can use the ‘commands’ it suggests below to manipulate the history
  4. If we get scared, and want to go back to where we were before, just remove all the lines, and git will do nothing

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