Git reflog vs. log: How these commit history tools differ
Git provides two similarly named components that provide insight to the repository's commit history, log and reflog. Developers access the git log and git reflog commands through the command line. Understandably, there's some confusion regarding these two commands and the underlying log and reflog components into which they hook.
But what scenarios make the most sense for Git reflog vs. log? Let's examine some examples that demonstrate exactly how the commands are similar, where they differ and when to use them.
Main Git reflog vs. log differences
The biggest difference between Git reflog vs. log is that the log is a public accounting of the repository's commit history while the reflog is a private, workspace-specific accounting of the repo's local commits.
The Git log is part of the Git repository and is replicated after a push, fetch or pull. In contrast, the Git reflog is not part of the replicated repo. A developer can't examine a local repository's reflog without having physical access to the computer where it is located.
Use the git log command to view the log and use the git reflog command to view the reflog.
In more technical terms, the reflog is a file found in .git\logs\refs\heads that tracks the history of local commits for a given branch and excludes any commits that were potentially pruned away through Git garbage collection routines. In contrast, the Git log provides a branch's historical traversal of commits that starts from the most recent commit and ends at the very first commit of the entire branch history.
Git reflog vs. log similarities
One of the reasons for the Git reflog vs. log confusion is the fact that the two components will often show an identical history, especially when a developer completes a number of local commits without a fetch or a pull.
Take a look at the following example, which starts by creating a Git repository and then performs three commits. Notice how the git reflog and log commands print out the exact same information:
$ git init
Initialized empty Git repository in C:/workspaces/temp/.git/
$ touch home.html
$ git add .
$ git commit -m "First commit"
$ echo "Small Change" >> home.html
$ git commit -a -m "Second commit"
$ echo "Another Change" >> home.html
$ git commit -a -m "Third commit"
When you perform these three commits and examine both the log and reflog, you'll notice how remarkably similar they look as they report the exact same commit history:
$ git log --pretty=oneline
7abb321 (HEAD -> master) Third commit
e1051e5 Second commit
95d919c First commit
$ git reflog
7abb321 (HEAD -> master) HEAD@{0}: commit: Third commit
e1051e5 HEAD@{1}: commit: Second commit
95d919c HEAD@{2}: commit (initial): First commit
How the Git reflog and log differ
Based on the similar output above, it's possible to conclude incorrectly that the Git log and reflog are essentially the same. To demonstrate how the two can differ, see what happens after a developer hard resets, or changes the last Git commit message.
Here we change the last Git commit message:
$ git commit --amend -m "3rd commit message"
After a developer issues the command, reflog's private listing of local commits reveals four entries. Every local commit issued against the repository is included in the output of the git reflog command:
$ git reflog
88846c2 (HEAD -> master) HEAD@{0}: commit (amend): 3rd commit message
7abb321 HEAD@{1}: commit: Third commit
e1051e5 HEAD@{2}: commit: Second commit
95d919c HEAD@{3}: commit (initial): First commit
However, the git log command, which shows a public view of the repository, doesn't reveal any information about the amended commit message. In this situation, we can now see how the Git log and reflog differ:
$ git log --pretty=oneline
88846c (HEAD -> master) 3rd commit message
e1051e Second commit
95d919 First commit
A reset example provides an even more pronounced Git relog vs. log difference.
$ git reset --hard 95d919c
After a hard reset takes the repository back to the first commit, the reflog will show the history of all five commits. The log will show only one and won't have any reference to the amend, the reset or even the second and third commits. Here is the output of the git reflog command after the reset:
$ git reflog
95d919c (HEAD -> master) HEAD@{0}: reset: moving to 95d919c
88846c2 HEAD@{1}: commit (amend): 3rd commit message
7abb321 HEAD@{2}: commit: Third commit
e1051e5 HEAD@{3}: commit: Second commit
95d919c (HEAD -> master) HEAD@{4}: commit (initial): First commit
In contrast, the Git log only shows one commit on the master branch:
$ git log --pretty=oneline
95d919c (HEAD -> master) First commit
Clones, logs and reflogs
In these scenarios, we see a reflog that is populated with more entries than the log. In contrast, the opposite occurs when you clone a repository. After a repository is cloned, the log will output a full history of the repository, while the reflog mentions nothing other than the clone. Look at the following Git log and reflog example after a developer has cloned a GitHub repository:
$ git clone https://github.com/cameronmcnz/spring-boot-examples.git
Cloning into 'spring-boot-examples'...
remote: Enumerating objects: 181, done.
remote: Total 181 (delta 0), reused 0 (delta 0), pack-reused 181
Receiving objects: 100% (181/181), 31.34 KiB | 943.00 KiB/s, done.
Resolving deltas: 100% (36/36), done.
After the clone, the reflog is quite sparse:
$ git reflog
46e70ce (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: clone
However, the git log command will show the entire history of the cloned GitHub repository's commits, which can span years and include hundreds of entries.
$ git log --pretty=oneline
46e70c (HEAD -> master, origin/master, origin/HEAD) Add Spring Configuration Example Tutorial
ad128a Update pom.xml
a04781 Update pom.xml
d816ba Update pom.xml
fb73eb Delete DemoApplicationTests.java
e14004 Create game.html
66a9e7 more boot
38a86d Merge branch 'master'
17c3ca Added Score class with static variables
d08cd7 Update WebController.java
ca01b6 added spring-ioc-example
0bc3b9 adding a few
f395f5 Update .gitignore
How to access the reflog from git log
Some developers prefer not to use the git reflog and classify it as a plumbing command. In contrast, developers may perceive the git log command to be part of the porcelain. To keep clear of the piping, you can view the reflog via the git log command with the --walk-reflogs switch:
$ git log --pretty=oneline --walk-reflogs master
95d919c (HEAD -> master) master@{0}: reset: moving to 95d919c
88846c2 master@{1}: commit (amend): 3rd commit message
7abb321 master@{2}: commit: Third commit
e1051e5 master@{3}: commit: Second commit
95d919c (HEAD -> master) master@{4}: commit (initial): First commit
Although both commands are intertwined with the commit history of a repository, there are significant differences between the two components. Think about the reflog as a record of lapidary local commits, and the log as the shiny, clean history a repository publicly presents to onlookers. This will hopefully help clear up any Git reflog vs. log component confusion.