Three Git Commands to Easily Navigate Version History

Navigating version history can feel like a perilous journey sometimes
Navigating version history can feel like a perilous journey sometimes - pixabay.com

Git is a powerful tool that allows you to go back in time to any previous versions of your project. Using the git checkout command, you’re able to go back to any reference (or ref for short) in the version history. A ref can be:

  • A commit, identified by its hash: 3f37c5c6
  • A branch: feat/add-login-button
  • A tag: v1.0
  • HEAD: A pointer to the tip of the current branch

But what if you don’t know the name of the reference you’re looking for?
Or worse, what if you don’t know what you are looking for?
In this post, we go through 3 Git commands you can use to efficiently navigate version history with practical use cases.

1. Git reflog shortnames

If the ref you’re looking for is a ref that you had previously checked out, then the reflog may help you. As HEAD jumps from commits, tags, branches through your repository, Git logs all the references it has pointed into the reflog.

git reflog is similar to git log , except that instead of displaying a list of commits, it will show a list of previous references, whether they are branches, commits, tags, and tell you from and to where you moved at each checkout command.

Example output of git reflog

HEAD@{0} is called a reflog shorthand, and it allows you to reference commits in relations to HEAD (or any other ref), instead of referencing them directly.

Here are a few examples of useful reflog shorthands to use:

  • git checkout HEAD@{1} : Jump back to the previous value of HEAD (equivalent to git checkout -)
  • git checkout HEAD@{5} : Jump back to the 5th previous value of HEAD Note that this is different from git checkout HEAD~5 which jump back to the 5th parent of the commit HEAD is pointing to.
  • git checkout HEAD@{1.month.ago} : You guessed it, jump back to the ref that was checked out a month ago.
  • git checkout feat/add-login-button@{2.weeks.ago} : reflog shortnames work from any ref, not just HEAD

Note: As opposed to the version history, the reflog cache does expire. Refs older than 90 days will get cleaned up by Git’s internal pruning mechanism. To increase the expiration date of the reflog cache, set thegc.reflogExpire property in your git config

2. Git bisect for binary search

If the ref you are looking for is the solution to a question similar to: “What is the first commit in my version history where X is true” then the ref can be efficiently found with git-bisect

Let’s say you want to find the first commit where a bug was introduced. You would do

git bisect start
git bisect bad # Flag HEAD as a bad commit containing the bug
git bisect good v1.0 # Can be any ref before the bug was introduced

Then Git will successively checkout a number of commits (no greater than log2 of the number of refs between HEAD and v1.0) and ask you to flag them as good or bad until it zeros in one the first commit where the bug was introduced.

See the git bisect documentation for more details, and a full example on how to use it.

3. Git Log Searching

If the ref you’re looking for is the answer to “What is the first commit that introduced this function?” or “What commit deleted this constant?”, then you can use the -S flag (aka the pickaxe flag) of the git log command to find it.

git log -S myAwesomeFunction --oneline

This command will only list commits that changed the number of occurrences of the string myAwesomeFunction

  • The commit where that function was created will be last in that list
  • The commit where that function was deleted will be first in that list

However, commits where the body of this function was changed without modifying the number of references to it will not show up in that list.

For that use case, you can use the -L flag of the git log command:

git log -L :myAwesomeFunction:./src/importantFile.js

This command will do two things:

  • Try to figure out what the bounds of that function are
  • Look through the history and show you every change that was made to the function as a series of patches back to when the function was first created.

Final Thoughts

Navigating version history, and finding exactly the commit that you want can be hard, but expanding your toolbox of commands to use, and knowing when to use them can help to improve your workflow.

What about you? What commands do you like to use to navigate version control?

Git’s version history is an incredibly useful tool and even more so the smaller and more atomic your commits are. Find out more from my other Git post: Improve your commit hygiene with `git add — patch`

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store