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..
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. 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.