Git Interactive Rebase

Git Interactive Rebase

“Can you please remove your last commit we decided not to use that feature ?”.

“Can you please squash your commits together so we get a clean, reversible git history?”.

“Can you rewrite your commit’s message to describe better the problem it solves, and how it solves it?”.

How to deal with these kinds of situations?

Interactive Rebase

git rebase re-applies commits, one by one, in order, from your current branch onto another. It accepts several options and parameters, so that’s a tip of the iceberg explanation, enough to bridge the gap in between StackOverflow or GitHub comments and the git man pages.

An interesting option it accepts is --interactive (-i for short), which will open an editor with a list of the commits which are about to be changed. This list accepts commands, allowing the user to edit the list before initiating the rebase action.

Let's run git log command

git log
commit 53f783b676b7de43ff9dd45b04d59748070840e9 (HEAD -> dev, origin/dev)
Author: Armen96 <barsegyan96armen@gmail.com>
Date:   Sat Nov 30 11:37:49 2019 +0400

    'Update Readme file :books: /play nyan'

commit 70deb939cd8ec4f2cab401dc871dbb3c51b6502f
Author: Armen96 <barsegyan96armen@gmail.com>
Date:   Sat Nov 30 11:30:59 2019 +0400

    'I am about to ...
    Remove unnecessary prop from env file'

commit 06243e81ad3b518202648a1322207be7c70db2b9
Author: Armen96 <barsegyan96armen@gmail.com>
Date:   Sun Nov 24 18:28:04 2019 +0400

    'Git amend command'

Changing a commit message

Let's remove :books: emoji from my last commit message

Update Readme file :books: /play nyan

Let's run

git rebase -i HEAD~1

HEAD is a reference to the commits in the currently check-out branch. HEAD~n is a reference to the last n commits.

It will open a new window

pick 53f783b Update Readme file :books: /play nyan

# Rebase 70deb93..53f783b onto 70deb93 (1 command)
#
# 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
# f, fixup <commit> = like "squash", but discard this commit's log message
...

pick <commit> just means to use the current commit. As we want to change commit message, we need to use reword <commit> option. In your case commit message will be different but it does not matter. Just change pick to reword or just r

reword 53f783b Update Readme file :books: /play nyan

Save changes and then move on. It will open another window.

Update Readme file :books: /play nyan

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sat Nov 30 11:37:49 2019 +0400
...

Now time to modifying the message (removing emoji part)

Update Readme file

Then you just need to push your changes to the repository.

git push origin dev -f

The result of git log will be

commit deeef03dfa0888b27327eef1424f92a4a7b12aad (HEAD -> dev, origin/dev)
Author: Armen96 <barsegyan96armen@gmail.com>
Date:   Sat Nov 30 11:37:49 2019 +0400

    Update Readme file

As you can see commit message changed successfully! Also, you can achieve the same result with

git commit --amend
git push origin master --force

But if you want to go n numbers of commits back, the solution is git rebase -i HEAD~n

Editing a commit

If you committed your changes but later you noticed that something wrong in your code but you do not want to add an additional commit with this message BugFix ... or something like that, you can do it with rebase edit. Imagine you want to edit the most recent commit so

git rebase -i HEAD~1

pick b50745c Update Readme file

Change pick to edit or just e then you can see

Stopped at 3f97704...  Update Readme file
You can amend the commit now, with

  git commit --amend

Once you are satisfied with your changes, run

  git rebase --continue

Now time to make fixes, when fixes completed you need to add your changes

git add .
git rebase --continue
git push origin dev -f

Done!

Squashing commits

Can you please squash your last 2 commits together so we get a clean, reversible git history? Yes, sure. Just a moment.

git rebase -i HEAD~2

You will see your last 2 commits

pick 70deb93 I'm about to ...

pick b50745c Update Readme file

Change pick to squash or just s

pick 70deb93 I'm about to ...

squash b50745c Update Readme file

It means that we want to combine this b50745c Update Readme file commit with this 70deb93 I'm about to ... one. It will open new window

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

I'm about to ...

Remove unnecessary prop from env file

# This is the commit message #2:

Update Readme file

You can edit the commit messages but the aim is to combine them together so you can just comment one of them and update another one like this

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

Remove unnecessary prop from env file and Update Readme file

# This is the commit message #2:

#Update Readme file*

Then push your changes to the repository

git push origin dev -f

Removing a commit

Can you please remove your last commit we decided not to use that feature? Yes, sure. Just a moment.

git rebase -i HEAD~1

pick cdf92bc Remove unnecessary prop from env file and Update Readme file

Change pick to drop or just d

drop cdf92bc Remove unnecessary prop from env file and Update Readme file

Then push your changes to the repository

git push origin dev -f

Congratulations, you removed your last commit.

Actually you can squash, drop, fixup, ... as much commits as you want just change number of commits

git rebase -i HEAD~n  // n=1, 7 or how much you have.

Git rebase is the powerful command with a bunch of options which can make our programming life more interesting and meaningful. Also, I recommend you to read Rebase vs Merge article.