How to find stuff in Git

5 minute read Published:

How to find stuff in Git

When you first started with git, you quickly got up to speed with committing, pushing, pulling, merging, and the like. But then you noticed a gaping hole in your knowledge - how do you find stuff in Git? Can you revert to a version of a file as it stood three weeks ago, or find out when a bug was introduced? Who was the last person to edit this file?

They always tell you that the great thing about Git is that you [almost] never lose any history. So how do you access and utilize that history?

Hey, Git. Who was the last person to change this file?

git log foo.c

What did they change?

git log --patch foo.c

Alternatively, use git show along with the commit hash.

git show <hash>

Hey, Git. Can you show me who changed this file, line by line?

git blame foo.c

Hey, Git. When was this bug introduced?

..when you know the line of code that is bad

Use Git’s “Pickaxe” like a code archaeologist to search through the commits until you find when a given string was introduced.

git log -S"Bad line of code"

..when you’re not sure what’s causing the bug

When you don’t know which commit introduced the bug, use git bisect to find the bad commit quickly via a binary search algorithm.

git bisect start
git bisect bad HEAD
git bisect good <commit>

Now bisect will select a commit in the middle of that range and check it out for you. Exercise the code and check whether or not the bug still exists. If the bug isn’t present in that commit, enter:

git bisect good

If the code is still broken, enter:

git bisect bad

In either case, bisect will continue on in this way until it finds the exact commit which introduced the bug.

Once, you have found the bug, clean up and return to the original HEAD.

git bisect reset

Fully automated Git bisect

If you have a build script that compiles your code and runs your tests, you can use Git bisect to find the bad commit for you, automatically. Plus, it’s a one liner.

git bisect start HEAD <good_hash> run ./build_script.sh

Go have some coffee. When you come back, you’ll know which commit introduced that bug.

Hey, Git. How do I check out the version of this file from two weeks ago?

So all of the changes to foo.c in the last two weeks were pure junk, huh? Or you just want to play with an older version of the code.

First, find which version of the file you want to check out

This will show you all of the commits which changed foo.c in the last two weeks, starting with the oldest commit.

git log --since=two.weeks.ago --reverse -- foo.c

Notice the double dash. That tells Git that it shouldn’t expect any more switches. The next argument will be a filename.

Checkout a version of the file from another commit

Now that you’ve found the commit containing the version of the file you’re interested in, copy its commit hash and check it out.

git checkout <hash> foo.c

You can use this same pattern to checkout any file from any commit. For instance, you have made a change to foo.c in another branch, and you would like the same changes in your current branch.

git checkout SomeOtherBranch foo.c

If you don’t want to check the file out, but just want to view a file in another branch.

git show SomeOtherBranch:foo.c

Hey, Git. Who has committed to most times in the whole repo?

This is pretty pointless, but can be fun nonetheless. It could also help your team to be more conscious about splitting up tasks into smaller, more focused commits. Generally, the smaller the commit, the better its documentation, and the better it is reviewed during code review.

git shortlog -s -n

Hey, Git. Is there a foo.c in this repository?

git ls-files foo.c

git ls-files also understands file globbing.

git ls-files *.c

Hey, Git. Is there a file containing “foo bar”?

git grep "foo bar"

To show line numbers, file headings, and use a case-insensitive search:

git grep -i --heading --line-number "foo bar"

Hey, Git. Show me all of Cueball’s commits

git log --author=cueball

Hey, Git. Show me the commits from a specific date range

git log --after="April 1, 2016" --before="April 30, 2016"

Hey, Git. Show me the commits where certain lines in a file were changed

git log -L 1,1:foo.c

Show me when a certain method in a class was changed.

git log -L:bar:foo.c

Hey, Git. How does my branch differ from master?

git diff master..

Or..

git cherry -v

Only show the names of the files that have changed

git diff --name-only master..

Hey Git. How can I visualize my commits and branches?

git log --oneline --graph --all --abbrev-commit

That should help you the next time you need to find stuff in Git. For a deeper dive into Git, I recommend these two books: Version Control with Git, and Pro Git. Just beware — you may start to receive a lot of phone calls:

If that doesn't fix it, git.txt contains the phone number of a friend of mine who understands git. Just wait through a few minutes of 'It's really pretty simple, just think of branches as...' and eventually you'll learn the commands that will fix everything.
Git, (xkcd)

If you have an amazing tip for finding all the Git things, let me know in the comments. I may even update this post to include your comment.