Git reflog – The git lifesaver

Git command is a very powerful tool, allowing you to do practically everything to the git repository you’re using. As it is powerful, it is also very non-user friendly, even compared to other Linux commands. And so, you can easily f!^k things up.

I’m here to show you a very useful tool, for the case you did something stupid… localy… if you were talented enough to push your mistake (we all have done it at some point), then only the repository’s owner will help you, and you can only hope that he’s mercyfull.
[Actually, you can probably do something like “git revert” and push, but you’re mistake(s) will be visible to all. If someone knows of a “quiet” way of reverting erroneous commits from the remote repository, I’ll be glad to learn]

Introducing “git reflog” – This command will show you a list of the recent operation you have done on the local repository, similar to “git log –oneline”, except instead of a list of commits, you see a list of changes, and each change has a “SHA” – The long hex which uniquely identify it – Just like a commit. All that is left to do in order to revert to the desired point is “git reset –hard <change #>”.

And now, an example.
I created a dummy repository, and a main.c that prints one line of text, here is the our repository’s relog so far:

$ git reflog
0f26690 HEAD@{0}: commit: Add printout
aacbdb6 HEAD@{1}: commit: Add new file: "main.c"
0fc0894 HEAD@{2}: commit (initial): Initial commit

Now I made a “light mistake”, and amended the last commit with changes I did not intend on inserting:

$ vim main.c 
$ git add main.c 
$ git commit --amend
[master e6ea730] Add printout
 Date: Sun Dec 4 00:25:06 2016 +0200
 1 file changed, 3 insertions(+)

Oops… We can fix this by “reset HEAD~1”, erasing the unwanted text, and committing (again) only the wanted code. But it would be easier to fix with relog.
Here’s the reflog:

$ git reflog
  e6ea730 HEAD@{0}: commit (amend): Add printout
  0f26690 HEAD@{1}: commit: Add printout
  aacbdb6 HEAD@{2}: commit: Add new file: "main.c"
  0fc0894 HEAD@{3}: commit (initial): Initial commit

We can see the diff between the last good commit and the “amend” that messed it up:

$ git diff 0f26690 e6ea730
diff --git a/main.c b/main.c
index a29c03d..6c261d7 100644
--- a/main.c
+++ b/main.c
@@ -2,7 +2,7 @@

int main()
{
    -    printf("This is a dummy program\n");
    +    printf("This is a dummy program\n"); this is a mistake

        return 0;
}

And now we can revert to the desired point:

git reset --hard 0f26690
HEAD is now at 0f26690 Add printout

Looking at the log we can see these commits:

$ git log --oneline
0f26690 Add printout
aacbdb6 Add new file: "main.c"
0fc0894 Initial commit

But only the desired changes are in the last commit:

$ git diff 0f26690^!
diff --git a/main.c b/main.c
index 31a1337..a29c03d 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,8 @@
+#include 

int main()
{
    +    printf("This is a dummy program\n");
    +
        return 0;
}

This is, of course, just a simple example. But we can use “reflog” to fix real damage we made by, for example, using “git rebase” (excellent tool for messing up your repository) or by any other means.

Till next time,
Amnon.