Back to top

The art of undoing in GIT

GIT provides us with various mechanisms of undoing changes. Let us look at them one at a time.

Undoing changes in working directory before staging

We are going to use the same scenario as in the article GIT basics where we have a folder named pond at /var/www/html/pond which contains two files frogs and snakes.

Let us first make changes to the file snakes

# vim snakes

this is a deadly snake.

save and exit

 

Check GIT status

# git status

Output:

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:   snakes

no changes added to commit (use "git add" and/or "git commit -a")

 

Now, as GIT is suggesting we can discard changes in working directory by typing following command;

# git checkout -- snakes

 

Check GIT status again

# git status

Output:

On branch master
nothing to commit, working directory clean

Thus we can see that with git checkout -- <file> command, we can undo changes in working directory before staging.

 

Undoing changes in working directory after staging

Make changes to snakes file again

# vim snakes

this is a deadly snake.

save and exit

 

Check GIT status

# 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:   snakes

no changes added to commit (use "git add" and/or "git commit -a")
 

Stage the modified file

# git add snakes

 

Check GIT status again

# git status

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   snakes

 

Now as GIT is suggesting git reset HEAD <file> command can be used to undo the staging process.

# git reset HEAD snakes

Output:

Unstaged changes after reset:
M    snakes

 

Check GIT status again

# git status

Output:

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:   snakes

no changes added to commit (use "git add" and/or "git commit -a")

Now as we can see we are at the situation where modifications have been unstaged. Now we can use git checkout -- <file> command to undo changes in the working directory.

 

Undo changes in working after commit

Check content of frogs file

# cat frogs

Output:

this is the first frog.

 

Make changes to the frogs file and perform a new commit.

# vim frogs

this is the first frog to see the world.

save and exit

# cat frogs

Output: 

this is the first frog to see the world.

# git add frogs

# git commit -m "more changes to frogs"

Output:

[master a63ed19] more changes to frogs
 1 file changed, 1 insertion(+), 1 deletion(-)

 

# git log

commit a63ed199ac742b13cf8fe77992f48e2f8ba66a8c
Author: root <apurwa@gmail.com>
Date:   Thu Feb 23 13:51:47 2017 +0545

    more changes to frogs

commit b0a2b9b16ed8bced2e04c3f88838479d28553a34
Author: root <apurwa@gmail.com>
Date:   Mon Feb 20 12:35:47 2017 +0545

    changes to frogs

commit 8d5e7611dd8eb2e43078a8e7dfe56e9e3cff3e8b
Author: root <apurwa@gmail.com>
Date:   Mon Feb 20 11:57:56 2017 +0545

    first commit
 

Now, if we want to recall the last commit's frog file we will type the following command;

# git checkout <first 4 characters of commit hash> <file>

Here commit hash is the 40 character long string such as b0a2b9b16ed8bced2e04c3f88838479d28553a34 which is used to identify a specific commit.

We can refer to a given commit by the first 4 character of its hash value.

Now if we want to recall the frogs file from the commit changes to frogs, we need to refer to its hash value, b0a2b9b16ed8bced2e04c3f88838479d28553a34 by b0a2

Hence, in order to recall frogs file from changes to frogs commit we type;

# git checkout b0a2 frogs

# git status

Output:

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   frogs

# cat frogs

Output: 

this is the first frog.
 

We can see that the above command reloaded the frogs file from the specified commit and pushed it to the staging area.

Now, we can continue with a new commit as before. However, this commit will have the old version of frogs file.

If we want to revert this operation and go back to the current the state of affairs, we simply type;

# git checkout master .

Here . represents all the files. Hence, this command loads the latest version of all the files.

 

There is another way we can reload old versions of the files.

Instead of typing git checkout b0a2 frogs command we can type the following command; 

# git checkout b0a2

Output:

Note: checking out 'b0a2'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at b0a2b9b... changes to frogs

# git status

Output:

HEAD detached at b0a2b9b
nothing to commit, working directory clean

# cat frogs

this is the first frog.

We can see that even in this case, frogs file has been loaded from an older commit titled changes to frogs marked by b0a2.

However this time, the file is not shown as modified and staged.

Another aspect of this operation we must understand is the detached head state. Detached head state refers to a state when the pointer points to an old state of the filesystem.

In case of the command git checkout b0a2 frogs, the pointer still pointed to the tip of the project however the file frogs was loaded from an old state.

In case of the command git checkout boa2, the whole filesystem was loaded from an old state. 

To get out of this detached head state we need to type the following;

# git checkout master

Output:

Previous HEAD position was b0a2b9b... changes to frogs
Switched to branch 'master'

In case we had made any commits before typing this command, these commits would be lost. To preserve these commits, we would have to create a new branch.