Requisites for this post is my last three posts on the git
Topics consists in this post
- Reword last commit message
-
Interactive Rebase
- Reword other commit messages
- Deleting commits
- Reordering commits
- Squash commits together
Many times, when you are working with git, you may need to revise the git commit history which can include anything from changing the commit message to changing the order and content of the commit to squashing commits together.
To start with the above topics, first we need to create local git repository to do that follow the below steps:
-
Create a local directory.
$ mkdir rewriting-git-history $ cd rewriting-git-history
-
Use
git init
to initilize the empty git repository.$ git init Initialized empty Git repository in /Users/mountainfirefly/tmp/rewriting-git-history/.git/
-
Add some sample JS files to work with git.
$ echo "console.log('file 1 content')" >> file1.js $ echo "console.log('file 2 content')" >> file2.js
-
Let’s stage and commit them.
$ git commit -m "first commit" [master (root-commit) 5e63564] first commit 2 files changed, 2 insertions(+) create mode 100644 file1.js create mode 100644 file2.js
-
To see git logs, use
git log
command.$ git log --all --decorate --oneline --graph * 5e63564 (HEAD -> master) first commit
Now, we’ll move to our first topic.
Reword last commit message and its content
You can change the most recent commit in the commit history by using git commit --amend
command. The git commit --amend
command provides you a convenient way to modifying the most recent commit. It lets you combine the staged changes with the previous commit instead of creating the entirely new commit.
It can also be used to edit the previous commit message without affecting the snapshot.
Let’s change our most recent commit message that is first commit to add js files. To achieve this, run the below commands in your terminal inside your repository.
$ git commit --amend -m "add js files"
[master b7cf4bb] add js files
Date: Sun Jan 19 14:19:29 2020 +0530
2 files changed, 2 insertions(+)
create mode 100644 file1.js
create mode 100644 file2.js
Run git log
to see the changed commit message.
$ git log --all --decorate --oneline --graph
* b7cf4bb (HEAD -> master) add js files
Now, let’s add one more js file under the same commit message.
First, we need to stage the file that we want to add to the commit and then use git commit --amend
to amend it in the commit history.
$ echo "console.log('file 3 content')" >> file3.js
$ git add .
$ git commit --amend -m "add js files"
[master ca2833c] add js files
Date: Sun Jan 19 14:19:29 2020 +0530
3 files changed, 3 insertions(+)
create mode 100644 file1.js
create mode 100644 file2.js
create mode 100644 file3.js
Here, if you run git log
in the terminal you can see that we have successfully added the new content to the previous commit.
$ git log --all --decorate --oneline --graph
* ca2833c (HEAD -> master) add js files
Interactive Rebase
Rebasing the process of moving and combining a sequence of commits to a new base commit. Run git rebase
with -i
option to rewrite, replace, delete and merge individuals commits in the history. The primary reason for rebasing is to make the linear commit history.
Reword other commit messages
To modify the commit message that is much farther back in the commit history, we must move to the most complex tool which is an interactive rebase. With interactive rebase you can stop after each commit that you want to modify and change the message, add files or whatever you wish.
To change the commit which is much farther in the commit history, we need to add a couple of more commits to our rewriting-git-history
project.
Let’s add.
$ echo "console.log('file 4 content')" >> file4.js
$ git add .
$ git commit -m "add file4"
[master c093603] add file4
1 file changed, 1 insertion(+)
create mode 100644 file4.js
$ echo "console.log('file 5 content')" >> file5.js
$ git add .
$ git commit -m "add file5"
$ echo "console.log('file 6 content')" >> file6.js
$ git add .
$ git commit -m "add file6"
[master 10c729c] add file6
1 file changed, 1 insertion(+)
create mode 100644 file6.js
Let’s see the history.
$ git log --all --decorate --oneline --graph
* 10c729c (HEAD -> master) add file6
* 063f1ab add file5
* c093603 add file4
* ca2833c add js files
Let’s change the add file4 message to change add file4 commit message in the commit history. We will be using the git rebase -i
command which will be taking an argument the parent of the last commit that you want to edit, that is HEAD~2^
or HEAD~3
.
$ git rebase -i HEAD~3
The above command will display below output in the default terminal editor, for me it is displaying it in the vim editor.
Here it is.
pick c093603 add file4
pick 564b7b2 add file5
pick 853d328 add file6
# Rebase ca2833c..853d328 onto ca2833c (3 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
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
In the output, you can see that these commits are listed in the opposite order that you normally see with the git log
command.
Also, there are listed many commands that you can use to perform the mentioned operation next to it.
You need to edit the script so that it stops where want to edit the commit. To do so, change the word pick
to edit
for each of the commits you want to stop the script.
In our case, we have planned to modify the add file4
commit so we’ll be changing the add file4
pick
to edit
as below I have changed and save the file using Ese
:wq
command.
edit c093603 add file4
pick 564b7b2 add file5
pick 853d328 add file6
# Rebase ca2833c..853d328 onto ca2833c (3 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
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
Now, you will see this output in the terminal.
$ git rebase -i HEAD~3
Stopped at c093603... add file4
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
The script has stopped on the add file4
commit, here you can stage the new file and use git commit --amend
to amend it.
To continue the rebasing process run git rebase --continue
which will close the rebasing process if there are not anymore stops.
For now, we’ll just modify the commit message.
To do so, run below command or you can stage a file and run the below command.
$ git commit --amend -m "change add file4 commit message"
[detached HEAD e31f338] change add file4 commit message
Date: Sun Jan 19 15:09:01 2020 +0530
1 file changed, 1 insertion(+)
create mode 100644 file4.js
Run git rebase --continue
to resume the rebasing process.
$ git rebase --continue
Successfully rebased and updated refs/heads/master.
We didn’t have any more stops so it has simply existed.
Delete a commit
You can also use the interactive rebase for deleting a commit as well. To delete a commit, you have to remove the commit line from the script file.
Run git rebase -i HEAD~3
$ git rebase -i HEAD~3
You will see this output in the editor
pick c093603 change add file4 commit message
pick 564b7b2 add file5
pick 853d328 add file6
To remove the add file6
commit from the history, change it to this.
pick c093603 change add file4 commit message
pick 564b7b2 add file5
Save and exit the file.
Run git log
to see the changes.
$ git log --all --decorate --oneline --graph
* 289c24a (HEAD -> master) add file5
* e31f338 change add file4 commit message
* ca2833c add js files
You can see that you don’t have that commit anymore in the commit history also the file6
file is not there in the working directory too because it has been removed with the commit itself so be cautious whenever you doing these types of changes.
Reordering the commits
Reordering commits is very simple, all you need to do is open the interactive rebase and reorder the lines of commits in the file and save it.
Let’s change the order of our project commits in history.
$ git log --all --decorate --oneline --graph
* 289c24a (HEAD -> master) add file5
* e31f338 change add file4 commit message
* ca2833c add js files
Currently, our commit history looks like this, let’s switch add file5
and change add file4 commit message
commits with each other.
Open interactive rebase:
$ git rebase -i HEAD~2
Change this:
pick e31f338 change add file4 commit message
pick 289c24a add file5
To this:
pick 289c24a add file5
pick e31f338 change add file4 commit message
Save and exit the file.
Run git log
to the changes.
$ git log --all --decorate --oneline --graph
* b3305c1 (HEAD -> master) change add file4 commit message
* a964e23 add file5
* ca2833c add js files
You can see here the order of the commit has been changed.
Squashing commits
It is also possible to take the series of commits and squash them down into a single commit using interactive rebase tool.
For squashing commit we need to use squash
instead of edit
and pick
. Let’s squash our last two commits into one.
Trigger interactive rebase
$ git rebase -i HEAD~2
Which will display the below output, change the pick
to squash
command for the second commit, that will get merged into the first commit.
pick a964e23 add file5
squash b3305c1 change add file4 commit message
# Rebase ca2833c..b3305c1 onto ca2833c (2 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
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
Save and exit of the above script will open the below script, which tells you the change add file4 commit message
commit getting squashed into add file5
commit.
# This is a combination of 2 commits.
# This is the 1st commit message:
add file5
# This is the commit message #2:
change add file4 commit message
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Sun Jan 19 15:10:26 2020 +0530
#
# interactive rebase in progress; onto ca2833c
# Last commands done (2 commands done):
# pick a964e23 add file5
# squash b3305c1 change add file4 commit message
# No commands remaining.
# You are currently rebasing branch 'master' on 'ca2833c'.
#
# Changes to be committed:
# new file: file4.js
# new file: file5.js
#
Save and exit this script.
Run git log
to see the changes.
$ git log --all --decorate --graph
* commit 37d80516a5a4d954cbc5f1636110f82db07dbcd1 (HEAD -> master)
| Author: mountainfirefly <pankajdcoder@gmail.com>
| Date: Sun Jan 19 15:10:26 2020 +0530
|
| add file5
|
| change add file4 commit message
|
* commit ca2833ca9fb97024e8508ea00e9007665279622c
Author: mountainfirefly <pankajdcoder@gmail.com>
Date: Sun Jan 19 14:19:29 2020 +0530
add js files
Here you can see that add file5
and change add file4 commit message
have squashed down to one commit.
That is all for this post, I hope you must have enjoyed it.
I write articles like this every week, you can check those out here mountainfirefly.dev