Undo Changes in Git – Part II – revert and amend

In the last post, we went over how to undo changes in your working directory and staging index.  In this post we’ll start to take a look at how to undo changes we’ve already committed, which is a little more involved in Git and requires some slightly more powerful tools.

The reason for this is the Git architecture itself.  When you create a set of changes in Git and commit them to the repository, Git generates a checksum to refer to those changes.  This checksum is generated via an algorithm based on the data in the changesets themselves, plus some other meta data.  Any change to that data, no matter how slight will cause a change in the generated checksum.  This is how Git ensures data integrity.

The checksum is generated using SHA-1 (Secure Hashing Algorithm), and generates a 40-character hexadecimal string.  Each commit other than the initial commit in a project has its SHA value partially based on information from the prior commit.  So you can see how this can be an issue when needing to undo actual commits.  Removing or undoing commits in the middle of the commit log would have bad consequences for the data integrity of subsequent commits and break the whole system.

So before we start breaking out the big guns, those being the variations on the reset command, we’re going to go over some ways to change or undo what you’ve done in your last commit.  Specifically how to revert a commit and how to amend a commit.

git revert

*If you didn’t read the first part of this tutorial where we went over undoing changes to your working directory and staging index, you can find that here if you want to follow along.

Picking up where we left off from last time, we should only have 3 commits right now, our initial commits when adding our three files:

commit 2424f4fd65b3a56f46614d9c8078546ddc558891
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:30 2017 -0400

 Initial commit for file3

commit 0b9a947f84b8296fccd3fea140bd9cd6125941fe
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:14 2017 -0400

 Initial commit for file2

commit d341ff615ae2124a761d87fe3450665ebe9b3678
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:23:59 2017 -0400

 Initial commit for file1

Let’s add another commit so we have something to revert.  I will change the lazy dog to diligent.

➜ fox-project git:(master) ✗ git status
On branch master
Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
 (use "git checkout -- <file>..." to discard changes in working directory)

modified: file3.txt

no changes added to commit (use "git add" and/or "git commit -a")
➜ fox-project git:(master) ✗ git add file3.txt
➜ fox-project git:(master) ✗ git commit -m "Changing the lazy dog to diligent"
[master ee3a893] Changing the lazy dog to diligent
 1 file changed, 1 insertion(+), 1 deletion(-)
➜ fox-project git:(master) git status
On branch master
nothing to commit, working tree clean
➜ fox-project git:(master)

And git log:

commit ee3a8937b29cf204c70c6f1bdc51b5bbfc3adea9
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:33:02 2017 -0400

Changing the lazy dog to diligent

commit 2424f4fd65b3a56f46614d9c8078546ddc558891
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:30 2017 -0400

Initial commit for file3

commit 0b9a947f84b8296fccd3fea140bd9cd6125941fe
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:14 2017 -0400

Initial commit for file2

commit d341ff615ae2124a761d87fe3450665ebe9b3678
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:23:59 2017 -0400

Initial commit for file1

git revert will undo the last commit by adding a new commit which negates all the previous changes.  Let’s see it in action.

Revert the last commit by issuing a git revert:

git revert ee3a8937b29cf20

And this is gonna bring up our editor with a default commit message, which I’ll accept and save:

Revert "Changing the lazy dog to diligent"

This reverts commit ee3a8937b29cf204c70c6f1bdc51b5bbfc3adea9.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# modified: file3.txt
#

As you can see now, we have a new git log which shows this new commit:

commit a346265bd0cc8100ce5efa311b649679575acdae
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:40:35 2017 -0400

 Revert "Changing the lazy dog to diligent"

 This reverts commit ee3a8937b29cf204c70c6f1bdc51b5bbfc3adea9.

commit ee3a8937b29cf204c70c6f1bdc51b5bbfc3adea9
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:33:02 2017 -0400

 Changing the lazy dog to diligent

commit 2424f4fd65b3a56f46614d9c8078546ddc558891
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:30 2017 -0400

 Initial commit for file3

commit 0b9a947f84b8296fccd3fea140bd9cd6125941fe
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:14 2017 -0400

 Initial commit for file2

commit d341ff615ae2124a761d87fe3450665ebe9b3678
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:23:59 2017 -0400

 Initial commit for file1

Now let’s take a look at our various levels of files to see where we’re at:

➜ fox-project git:(master) git status
On branch master
nothing to commit, working tree clean

We have a clean working directory and looking at our now reverted file3.txt, it should still read ‘the lazy dog’ after reverting our ‘diligent’ commit.

This git revert command is perfect for when you perhaps realize you made a mistake with your last commit and want to undo it quickly.  However, this is primarily for simple undos.  When things get more complicated, we need a more powerful tool, which we’ll look at when we talk about the reset command.

amend

Let’s make a new change and commit it so we have something we can amend.  I will change file1.txt to read the ‘The sly brown fox’ instead of ‘quick’.

➜ fox-project git:(master) vi file1.txt
➜ fox-project git:(master) ✗ git add file1.txt
➜ fox-project git:(master) ✗ git commit -m "Changing the fox from quick to sly"
[master 482090d] Changing the fox from quick to sly
 1 file changed, 1 insertion(+), 1 deletion(-)
➜ fox-project git:(master)

And a quick git log:

commit 482090d73f561fe06cbb31afad6b7da6a9c2565f
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 11:31:50 2017 -0400

Changing the fox from quick to sly

commit a346265bd0cc8100ce5efa311b649679575acdae
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:40:35 2017 -0400

Revert "Changing the lazy dog to diligent"

This reverts commit ee3a8937b29cf204c70c6f1bdc51b5bbfc3adea9.

commit ee3a8937b29cf204c70c6f1bdc51b5bbfc3adea9
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:33:02 2017 -0400

Changing the lazy dog to diligent

commit 2424f4fd65b3a56f46614d9c8078546ddc558891
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:30 2017 -0400

Initial commit for file3

commit 0b9a947f84b8296fccd3fea140bd9cd6125941fe
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:14 2017 -0400

Initial commit for file2

commit d341ff615ae2124a761d87fe3450665ebe9b3678
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:23:59 2017 -0400

Initial commit for file1

Now, the amend option can be used to change the substance of the latest commit or the message for the commit.  Basically, as discussed before, we are able to modify only the latest commit because nothing depends on it yet.  Remember that Git creates its commit SHAs based on the information from previous commits and data.

So our last commit is the change from sly to quick for our fox.

Let’s make sure we have a clean working tree:

➜ fox-project git:(master) git status
On branch master
nothing to commit, working tree clean
➜ fox-project git:(master)

And now let’s say we don’t want the fox to just be sly, we want to add back that he’s also quick.  So let’s do that:

➜ fox-project git:(master) ✗ git status
On branch master
Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
 (use "git checkout -- <file>..." to discard changes in working directory)

modified: file1.txt

no changes added to commit (use "git add" and/or "git commit -a")
➜ fox-project git:(master) ✗

Now let’s add that to our staging index:

➜ fox-project git:(master) ✗ git add file1.txt
➜ fox-project git:(master) ✗ git status
On branch master
Changes to be committed:
 (use "git reset HEAD <file>..." to unstage)

modified: file1.txt

➜ fox-project git:(master) ✗

And finally let’s use the amend option to amend our commit:

➜ fox-project git:(master) ✗ git commit --amend -m "Adding quick back with sly"
[master a35cde8] Adding quick back with sly
 Date: Tue Mar 28 11:31:50 2017 -0400
 1 file changed, 1 insertion(+), 1 deletion(-)
➜ fox-project git:(master)

And our git log:

commit a35cde81f9f4ed693b81aed3a618f7624af99552
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 11:31:50 2017 -0400

Adding quick back with sly

commit a346265bd0cc8100ce5efa311b649679575acdae
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:40:35 2017 -0400

Revert "Changing the lazy dog to diligent"

This reverts commit ee3a8937b29cf204c70c6f1bdc51b5bbfc3adea9.

commit ee3a8937b29cf204c70c6f1bdc51b5bbfc3adea9
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:33:02 2017 -0400

Changing the lazy dog to diligent

commit 2424f4fd65b3a56f46614d9c8078546ddc558891
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:30 2017 -0400

Initial commit for file3

commit 0b9a947f84b8296fccd3fea140bd9cd6125941fe
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:24:14 2017 -0400

Initial commit for file2

commit d341ff615ae2124a761d87fe3450665ebe9b3678
Author: Tom Casper <tmcasper@gmail.com>
Date: Tue Mar 28 10:23:59 2017 -0400

Initial commit for file1

As you can see, Git basically just changed our latest commit to become what we amended it to.  Also notice that each time we do this the SHA changes.  Remember, this is fine because we are changing our latest, or last commit, and nothing depends on it yet.  Keep in mind too that you can use –amend to change the commit message as well.

So there you have two more useful tools in your Git toolbox to undo or change your most recent commits. In the next post in this series, we’ll look at the git reset command to see how we can undo commits not limited to our last commit.

Until then brothers and sisters, thanks for reading \,,/


Also published on Medium.

Leave a Reply

Your email address will not be published. Required fields are marked *