Taking GIT to the next level (Rewriting history).

Louis Lainé
4 min readOct 20, 2015

--

Last week I was to the bdxio and I saw a wonderful talk about the advanced possibility of GIT.

In this tiny article we are going to play with rebase.

Rebase

What’s the point?

git-rebase — Forward-port local commits to the updated upstream head

Rebase is actually going to play again some commit over other.

Before, replay commits over other
After

Fast-forward

If it’s possible git doesn’t look to create a merge commit even if a merge is requested.

For example, git-flow is using this technique. (I highly recommend you to use and to look at git-flow).

Interactive-rebase

git rebase -i <COMMIT SHA>

This command allow you to easily rewrite your history in a very flexible way, because you can rewrite pretty much everything.

You can reorder commits by just moving lines up or down, or removing commits by just removing a whole line.

In general, read what Git displays. For example, when you edit a commit, Git tells you what/how to do most of the things (git rebase — continue, etc.)

Be careful

git rebase -i will display commits in chronological order, contrary to git log.

Enough theory, let’s practice.

Easy ramp up

I’ve work on a feature and I realize that I make commits that are not very useful.

The three commits are not consistent separately, I want to merge these commits to create only one (and remove all the useless (part X) part of the commit log).

Let’s use interactive rebase!

git rebase -i HEAD~3

I’m going to replace pick with reword (or r) on the first commit, replace pick with f on the second and third.

Save then git opens the editor to change the commit message.

Save and watch git squash automatically next commits.

You can now see with git log, that your three commit have been merged in one, and you have a clean history!

(You can also see what has been done, using the git reflog command).

Bit harder

Imagine now, that I have two commits that are a mess. They contain a dump of modifications, without much consistency.

Commit 1e2ac contains different modifications :

  • Adds a footer
  • Fixes the header added in the previous commit

Commit a860 is a fix of commit 1e2ac.

What I want, is split the “Add footer + rename header menus” commit to split it in two distinct commits (a first one with the header) and a second one with the footer part, and then just merge the “Add style.css (footer) commit into the second one we’ve just created.

  • First, we need to open the interactive rebase on the first commit we want to modify, then put edit on the first line and fixup on the second one.
  • Git puts us now on the a860a43 commit.
  • We need now to reset “softly” one commit behind (to keep the code modification) with git reset HEAD~
  • git add -p, will allow us to interactively choose what we want to keep, split, etc. We are going to split with s to only stage the beginning of the file (the header).
  • After typing S, type Y, to save the split.
  • git commit -m “Added header”, to commit the split
  • git add -p again, to stage the end of the file
  • git commit -m “Added footer”
  • git rebase --continue to finish the rebase and update the master.

Tadaaa

Quite simple right ?

We can now check our log and see that everything is fine!

I hope you guys enjoy reading this article, feel free to comment or just share this article!

Ref and useful links

--

--