Git Undo Commit Example
1. Introduction
Every human being may make mistakes, especially the Software developers:) When we’re writing code, it’s a process of how we’re thinking and how we solve specific problems. In real life, it could be a disaster if we make some irrecoverable mistakes. However, this will not happen in writing code for the developers, especially with the help of Git.
In this article, we will focus on how to revert what we have done to the previous status. This may be caused by that we have made wrong update to our code, or we have deleted the existed code by accident, or even it could be you made some inappropriate comments to the code. This could be really awful if we don’t have ways to solve it. However, Git
undo command makes this easy to recover to the previous version of the code. So you don’t need to worry about what you’ve done.
2. Git undo examples
2.1 Introduction on git directory
Before we dig into the Git
undo commit operations, we need to have a general idea on the three different directories that a git
system has: workspace, index/staging area and the local repository. The whole structure could be referred to the following figure, this figure comes out of the link on it. Detailed information could be found in this link. It’s a great article for beginners on git.
To understand further of Git, we need to be very clear about the directories.
- Workspace: it’s the place where you see in your computer system, or the directory where you check out your files. Files in the workspace could be added to the
Git
by usinggit add
command. - Index: it’s also called stating area. It’s an invisible space where you can add files that you want to commit. To add commit, you can use
git commit
command. - Local repository: it’s also an invisible repository. Actually it’s stored in the .git folder, which is hidden in the folder you created.
- Remote repository: this could be another computer, or it could be the server of others, such as Github, which we can consider it as a remote repository. To access to the remote repository,
git push
orgit pull
could be used
Here, we also need to get familiar with the concept of head, which is the pointer to the most recent commit on the current branch. It’s actually a hash value of current commit, which is calculated by SHA-1 hash on a file with a hash value of 160 bits that uniquely identifies the contents of the file.
2.2 Create git folder
To get started, we need to create a git repository firstly. So we go ahead and create a folder on our local machine with the name of GitLearning. Then we initialize the folder to make it a git repository with command git init
. After this, you’ve created an empty git repository successfully. Wonderful!
The whole process and the command is shown below:
WXMs-MacBook-Pro:~ WXM$ cd Documents/ WXMs-MacBook-Pro:Documents WXM$ cd GitLearning/ WXMs-MacBook-Pro:GitLearning WXM$ ls WXMs-MacBook-Pro:GitLearning WXM$ git init Initialized empty Git repository in /Users/WXM/Documents/GitLearning/.git/ WXMs-MacBook-Pro:GitLearning WXM$ ls -ah . .. .git
Note that ls -ah
is needed to make the .git folder visible. Otherwise, it can not been seen, and this is for security. If you change the content in .git folder, the whole git repository would be crush.
Then we create a empty txt file named README.txt. This is normal for software developers and also useful for others to check the usage of the code. So don’t forget to create readme file along with you code. After this, you can add any content into the txt file. For example, here we add a sentence with “This is a readme file.” in the file. To make it a real file in git system, we need to use git add
and git commit
commands, to add the file into the staging area and local repository, respectively. The whole procedure could be checked by the command below:
pcp352933pcs:GitLearning WXM$ vi READMEFILE.txt pcp352933pcs:GitLearning WXM$ ls READMEFILE.txt pcp352933pcs:GitLearning WXM$ git add READMEFILE.txt pcp352933pcs:GitLearning WXM$ git commit -m "First time writing readme file" [master d907151] First time writing readme file 1 file changed, 1 insertion(+) create mode 100644 READMEFILE.txt
In the bash above, git add READMEFILE.txt
add the READMEFILE.txt into the stating area, while the git commit -m “First time writing readme file” command add the READMEFILE.txt into the local repository.
Then if I run git status
command to check the status of my git system, it shows that:
pcp352933pcs:GitLearning WXM$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working directory clean
It shows that nothing to commit and working directory is clean. However, it also shows that your branch is ahead of ‘origin/master’ by 1 commit and use “git push” to publish your local commits. The reason for this is that I’ve connected this folder with my Github account, which is the remote repository. Because I haven’t add the file to the remote repository, so it will remind you of that. It also shows that using git push
command it will publish the local changes to the remote repository. After running the git push
, everything is good now:
pcp352933pcs:GitLearning WXM$ git push Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 309 bytes | 0 bytes/s, done. Total 3 (delta 1), reused 0 (delta 0) To https://github.com/******/GitLearning.git 5a5a9ea..d907151 master -> master
Then when you check the status again, it’ll show you that everything works cleanly now.
pcp352933pcs:GitLearning WXM$ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean
2.3 Git undo commit
In some cases, we want to change our minds and revert the commit we have made, then git makes this easy to operate on. This is called git undo commit.
To make this happen, we add another line to the READMEFILE.txt, with “Bad words for others”. Then we add the file to the stating area and to the local repository. The following is the process that we have done:
pcp352933pcs:GitLearning WXM$ git add READMEFILE.txt pcp352933pcs:GitLearning WXM$ git commit -m "Add bad words" [master 1f50e80] Add bad words 1 file changed, 1 insertion(+) pcp352933pcs:GitLearning WXM$ cat READMEFILE.txt This is a readme file. Bad words for others.
When we use git commit
command it shows that 1 file changes, 1 insertion(+). That’s because we’ve added one line with “Band words for others”. Using the cat
command to show where we’ve changed the file.
Again, git status
could be used to check the status:
pcp352933pcs:GitLearning WXM$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working directory clean
If we want to make sure what change we have made, then we could use git diff
to check the difference between current version with the previous one. For git diff
, more detailed instructions could be found in my other article about git diff example.
Then we add another line to the txt file with “I made changes again:)”. To check the difference, the following is how we do it:
pcp352933pcs:GitLearning WXM$ git diff diff --git a/READMEFILE.txt b/READMEFILE.txt index 4cc46cb..6b972f7 100644 --- a/READMEFILE.txt +++ b/READMEFILE.txt @@ -1,2 +1,3 @@ This is a readme file. Bad words for others. +I made changes again:)
Then we can see that the sentence with “+” shows that where we add content to the file.
Then if we made another change to the the txt file and add another line with “I love changing things.” Until now we’ve made three changes – adding three lines compared with the first version. The four commits are : Love making changes <- Made changes again <- Add bad words <- First time writing readme file, where the arrow shows the order of the changes.
In real life of development, thousands lines of code could be changed. We can not remember it rightly. So git log
should be useful right now, and it’ll show all the change history we have made. We can try it with our own example here:
pcp352933pcs:GitLearning WXM$ git log commit 67713e5af45b67aa2628b12a73d4b493a16de159 Author: Jun <wuxiaomin98@hotmail.com> Date: Wed Mar 30 17:19:12 2016 -0500 Love making changes commit 47640c18cf433c6f6c7ba26b34f886688d34a1d3 Author: Jun <wuxiaomin98@hotmail.com> Date: Wed Mar 30 17:18:38 2016 -0500 Made changes again commit 1f50e80eb551e3ed7981251378d4609e30248d2f Author: Jun <wuxiaomin98@hotmail.com> Date: Wed Mar 30 16:58:21 2016 -0500 Add bad words commit d90715179d20e10c5d88fc8d8a58972605fb38c0 Author: Jun <wuxiaomin98@hotmail.com> Date: Wed Mar 30 16:32:28 2016 -0500 First time writing readme file
The above file shows every change we’ve made with specific date and time. You should notice the long sequence of strings after the commit. That’s the commit id, which corresponds to specific commit. Why it’s not in 1, 2, 3… order? That’s because Git
is a distributed system. If every commit id is in order, when multiple changes happen, there should be conflict.
Sometime, the changes are quite a lot and what we want is just to check the changes. Then git log --pretty=oneline
could be utilized to show each commit in one line.
pcp352933pcs:GitLearning WXM$ git log --pretty=oneline 67713e5af45b67aa2628b12a73d4b493a16de159 Love making changes 47640c18cf433c6f6c7ba26b34f886688d34a1d3 Made changes again 1f50e80eb551e3ed7981251378d4609e30248d2f Add bad words d90715179d20e10c5d88fc8d8a58972605fb38c0 First time writing readme file
See how convenient it could be!
Then if we want to go back to the previous version, git reset
command could be used. What we use here is git reset --hard HEAD^
. HEAD is means the commit of current branch. Symbol “^” means go back to the previous one version, “^^” means the previous two version and so on so forth. While it’s hard to continue with multiple “^” symbols when there’s hundreds and thousands versions. Then you can use the number directly. For example git reset --hard HEAD^
is the same as git reset --hard HEAD~1
and git reset --hard HEAD^^
is the same as git reset –hard HEAD~2. Pay attention to the symbol “~” before the numbers and do not forget to add it.
For our own example, right now the head is in 67713e5af45b67aa2628b12a73d4b493a16de159 Love making changes. If we want to go back to the previous version. Run the git reset --hard HEAD^
command and check the result.
pcp352933pcs:GitLearning WXM$ cat READMEFILE.txt This is a readme file. Bad words for others. I made changes again:) I love changing things. pcp352933pcs:GitLearning WXM$ git reset --hard HEAD^ HEAD is now at 47640c1 Made changes again pcp352933pcs:GitLearning WXM$ cat READMEFILE.txt This is a readme file. Bad words for others. I made changes again:)
We can see from the above, that after we run the git reset
command, it goes back to the previous version Made changes again. The 47640c1 is exactly the shortcut commit id for the previous commit.
Then if we want to go back to the initial status, we can go back twice with command git reset --hard HEAD~2
pcp352933pcs:GitLearning WXM$ git reset --hard HEAD~2 HEAD is now at d907151 First time writing readme file pcp352933pcs:GitLearning WXM$ cat READMEFILE.txt This is a readme file.
Now job has done! Fantastic!
Then run git log
, it shows only the first version.
pcp352933pcs:GitLearning WXM$ git log commit d90715179d20e10c5d88fc8d8a58972605fb38c0 Author: Jun <wuxiaomin98@hotmail.com> Date: Wed Mar 30 16:32:28 2016 -0500 First time writing readme file pcp352933pcs:GitLearning WXM$ cat READMEFILE.txt This is a readme file.
However, if one day we find that the lines we added are useful, could we go further and get it back? Yes, we can! If the terminal is not closed, we need to find the commit number which the version is. For example, the commit number for Love making changes version is 67713e5af45b67aa2628b12a73d4b493a16de159. Then we can use the git reset --hard
command with the commit id following it. Note that we can use the first few numbers of the commit id in most case.
pcp352933pcs:GitLearning WXM$ git reset --hard 67713e5a HEAD is now at 67713e5 Love making changes pcp352933pcs:GitLearning WXM$ cat READMEFILE.txt This is a readme file. Bad words for others. I made changes again:) I love changing things.
You see, it’s back. However, make sure you really want to go back and force. In some cases, if you don’t know the commit id, you won’t come back to the newest version.
In some cases, that you really want to come back to the newest version. Then git reflow
could be useful for you, which will track every command you’ve made. Run the command and you’ll get something magic.
pcp352933pcs:GitLearning WXM$ git reflog d907151 HEAD@{0}: reset: moving to HEAD^^^ 67713e5 HEAD@{1}: reset: moving to 67713e5a d907151 HEAD@{2}: reset: moving to HEAD~2 47640c1 HEAD@{3}: reset: moving to HEAD^ 67713e5 HEAD@{4}: commit: Love making changes 47640c1 HEAD@{5}: commit: Made changes again 1f50e80 HEAD@{6}: commit: Add bad words d907151 HEAD@{7}: commit: First time writing readme file
Here we have all the commit number to each commit and each reset/undo operation. So you don’t need to worry about where you’re now.
To make it more clear to understand, we can use the following figure to show how it work. The HEAD works as a pointer to point to specific version. For example, if HEAD is pointer to the last version. Then after using the reset command, we can go back the initial version.
3. Conclusion
Git undo operation makes it quite easy for us to go back and force to different versions. If you get familiar with it, then it could be very powerful. However, please make sure that you know where you go to when you perform the undo operation. If not, you can make another branch to operate it, which will make your code more safe.