Table of Contents
Getting started with git reflog
Git reflog tracks the HEAD of your repository.
git reflog
It is thus one of the most crucial commits to restoring lost changes resulting from branching, rebasing, and resetting. Using the command requires an intermediate understanding of git workflow. You should know fundamentals such as
However, having inadequate knowledge of git basics should not prevent you from following this tutorial because we shall briefly discuss the terms and do a lot of practice to let you apply the git reflog command. Let us get started.
Understand git reflog and related commands
Git reflog is built on essential git commands like git commit, branch, reset, rebase and merge. Here is brief information about the commands and related terms.
At the working directory
Managing a repository entails navigating along a branch or switching between branches. Say your focus in the main
branch. You can clone a repo, downloading a template with the initialization done for you. Otherwise, you run the init command to create an empty repository.
git init
An empty repository is like a database with no files. Then the files lie in the working tree.
At the index
Git actually starts tracking the changes on staging the files. Staged files are said to be at the index, and they are a snapshot of the changes in the working tree.
Git remembers the changes by storing them as a blob. A git-blob is a binary string of data that stores file contents. You can undo the changes or send them to history.
Git history vs the HEAD
Then, git keeps track of the changes in sha1 of a commit object. Subsequent file changes get stacked onto the commit object using the unique hash alongside their author, timestamp, and commit message. The latest commit, according to the current timestamp, becomes the HEAD.
Git branching, merging and rebasing vs the HEAD
Switching branches relocates the HEAD, enabling git to accommodate all changes irrespective of the branch, tag, or commit. A branch is an independent line where you work and test code before joining the changes with the main development line of the repo through rebasing or merging.
Rebasing stacks one branch's commits onto another's if the commits you do not squash the commits. Unlike git rebase, which creates a line repository, the merge command combines one branch's commits into one huge commit before throwing the ball into the main
branch.
Where git reflog comes in?
While working along or cross branches, you may make changes that require retreating your journey. Several commits come into play to undo the changes, including the most destructive ones like the reset command.
The reset command occurs in three stages: hard, soft, and mixed. A hard reset is discards commits and related files from the filesystem. The soft reset reverts the HEAD to the index, whereas the mixed reset unstages a file.
Since a typical development line has several commits, resets, rebases, branching, and merging, you may lose a bunch of commits. So, are you helpless if you want to regain lost commits? No! Here comes the saviour: git reflog
A detailed explanation of git reflog
Git reflog runs parallel to the git workflow, recording the destination of every current branch's HEAD commit. Simply put, git reflog is an ordered list of commits telling you where the HEAD ever pointed at.
It differs from the log command since it workstation excludes git pushes, clones, and fetches. Also, git reflog discards commits automatically.
Think of reflog as a compound word of ref + log. Say ref stands for refs while the log is short for logs in the .git
subdirectory.
The logs
subdirectory houses the the HEAD and refs
, whereas the refs
subdirectory has data about git heads
and remotes
. So, .git/logs
folder is the backend while git reflog is the frontend, exposing us to the UI.
Now that you know the roots of git reflog, let us practice using it. Before that, let us set up a lab as follows.
Lab setup to practice git reflog
I am creating a remote on GitHub called git_reflog
.
Copy its URL, clone it on the terminal and navigate into it.
cd git_reflog
Let us create starter files, stage them, and commit them.
touch file1 git add file1 git commit -m "Add file1 in the main branch"
Here are some of the practical ways to deploy git reflog.
Example~1: Use git reflog to restore commits after the amend operation
Assume we change the commit message from Add file1 in the main branch to Adding the new file to main. We can do that as follows.
git commit --amend -m "Adding the new file in main"
Checking history,
git log
we can see that we do not have the parent message in the second commit. Assume we later decide to return the deleted message. We can do that by visiting the reflog and resetting the hash of the message's commit.
git reflog git reset --hard 75a12d7
We can see that git reflog is similar to git log in structure. The first part is a portion of a commit hash that once held the HEAD. On the other hand, the second part reveals the commit information. For instance, we can see the HEAD points to the main branch. (HEAD -> main)
Example~2: Use git reflog to restore changes lost after git reset
Let us create a file, stage it, and commit it before discarding the changes.
touch index.py git add index.py git commit -m "Track the py file"
Log the history.
git log
Discard the last two commits, removing their files from the working tree.
git reset --hard HEAD~2
Recheck history, status, and working tree.
git log git status ls
We can neither trace the commits nor the files!
We can restore the files by resetting the target commit hash. Alternatively, we can check out the hash and make a branch from it. Let us go the second route: checkout a commit hash.
git reflog
git checkout 75165f0 git switch -C second
Return to the main branch and inject the commits through git rebase. Then recheck history.
git checkout main git rebase second git log --oneline
Our commits are restored.
Example~3: Use git reflog to restore deleted branches
We have two branches.
git branch
Let us delete the second branch.
git branch -d second git branch
And recover it by rechecking out the commit, branch, and rebasing. I use the --no-abbrev
option to see the full SHA1 for the target commit.
git reflog --no-abbrev git checkout 75165f0c8f2d689c40e38567ef840734440447b9 git checkout -b second git checkout main git rebase second git branch
And voila, the branch and commits got restored!
Example~4: Use git reflog to restore commits lost during git squash
Let us checkout the second branch and squash the last commit into the preceding one.
git checkout second git rebase -i HEAD~2
We have lost the commits. But we can recover them using git reflog as follows.
git log --oneline git reflog git reset --hard 75165f0 git log --oneline
Conclusion
Git reflog is crucial in restoring lost resources after committing them. For instance, we used it to restore lost files, commits and messages, and branches in this tutorial.
Likewise, you can apply it to restore your changes lost during branching, merging, rebasing, resetting, and amending messages. However, it would help to first understand the commands that lead to commit losses.