Rewriting History with Git Rebase

Payam Mousavi
3 min readSep 3, 2020

--

Background

As software engineers, we have always been looking for better ways to manage our codebases. And we may need specific source control (e.g. Git) techniques to resolve new issues, specially on big software solutions with huge codebases. We are trying to answer these questions:

  • When and how can I use Git Rebase?
  • Can we update/remove the last commit message or a specific commit?

One such situation is when we need to re-write Git history of a repository for any reason including:

  • Update (amend) a commit message
  • Remove (drop) a specific commit
  • Combine (squash) some commits with a specific commit
  • Change the order of commits (Re-order)

Let’s do it!

Hands on terminal

We can create a new Git repository and add some files and make some changes in those files and then make some commits. Suppose we need to update the last 7 commits (crazy I know!). Let’s run this command:

git rebase -i HEAD~7

This will open an interactive window (i.e. your default editor) where we can choose the proper action to apply to the repository history. Note that Git adds the commit messages in reverse order, so commit 11454df test something! is actually our last commit:

pick 58bc9d0 file.txt created
pick 121c507 file2.txt created
pick 64a2c99 file2.txt updated
pick 2ef342a file2.txt updated step 1!
pick e84f687 file2.txt updated step 2!
pick 16c8448 file2.txt updated step 3!
pick 11454df test something!
# Rebase e84f687..11454df onto e84f687 (7 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
# d, drop <commit> = remove commit
#
# REMOVED FOR BREVITY

You will see we have a couple of options to choose including:

  • Select (pick) the same commit
  • Update (reword) a commit message in-place
  • Update (edit) a commit message (This will open another window to edit the commit message)
  • Combine (squash) commit messages
  • Remove (drop) a commit

All we need to do is select the required action (e.g. pick or squash) and replace the current pick actions with the new action:

reword 58bc9d0 file.txt created and updated
pick 121c507 file2.txt created
pick 64a2c99 file2.txt updated
squash 2ef342a file2.txt updated step 1!
squash e84f687 file2.txt updated step 2!
squash 16c8448 file2.txt updated step 3!
drop 11454df test something!

#
# REMOVED FOR BREVITY

After saving the above (e.g. using :wq in vi), as we asked Git to squash some of our commits, it will open another window so we can finalize the commit message:

# This is a combination of 4 commits.
# This is the 1st commit message:

file2.txt updated

# This is the commit message #2:

file2.txt updated step 1!

# This is the commit message #3:

file2.txt updated step 2!

# This is the commit message #4:

file2.txt updated step 3!

# Please enter the commit message for your changes.
#
# REMOVED FOR BREVITY

We can update this to have our desired message (e.g. remove all commit messages except file2.txt updated) or we can save it just as it is. Note that lines starting with a hash # will not be added to the final commit message.

Now if you run git log, you will see the applied changes which are:

  • update the message of the 1st commit
  • retain the 2nd and the 3rd commits
  • squash the 4th, 5th and the 6th commits into the 3rd commit (This opens another window so we can make the final change)
  • remove the 7th commit

Note that instead of squash we could choose fixup for commits we want to combine and Git would choose the message of the pick commit before those commits (i.e. 64a2c99) as the final commit message for the combined commits.

Also, for re-ordering commits, we can simply change the line arrangement of the commits and put a specific commit before or after another commit:

pick 121c507 file2.txt created
pick 58bc9d0 file.txt created

Happy coding!

--

--