Skip to content

Chapter 7 of 8

Investigating and Searching History

Git's history tools answer different questions, and choosing the right one saves time. git log --oneline --graph --decorate --all renders the branch topology in the terminal so you can see merges and divergence at a glance. For blame-style questions, git blame file annotates each line with the commit that last touched it (add -w to ignore whitespace changes), while git log -L :funcName:file traces a function's life from introduction to removal. The pickaxe form git log -S 'searchString' finds every commit whose diff adds or removes that exact string, which is invaluable for tracking when a feature was added or removed across many refactors. To see the full commit message of a single commit, run git log -1 <sha> or git show <sha>. To inspect any object stored in Git (a commit, tree, blob, or tag), git cat-file -p <sha> prints its human-readable contents.

Diffs come in many useful variants. Plain git diff shows unstaged changes, git diff --staged (or --cached) shows what is staged, and git diff --word-diff highlights changes within lines. git show --name-only <sha> lists the files a commit changed, and git diff sha1 sha2 -- file compares a single file at two points in history. Comparing branches uses the dot notation: git log main..feature lists commits in feature not yet in main, while git log feature..main does the opposite. The three-dot form git log main...feature is special: it shows the diff from the merge base of the two branches to feature, which is exactly the change set a pull request would introduce; the same logic applies with git diff main...feature. To list branches sorted by recent activity, git for-each-ref --sort=-committerdate refs/heads/ --format='%(committerdate:short) %(refname:short)' produces a clean leaderboard of recent work.

For automatically locating the commit that introduced a bug, Git ships a binary search tool called bisect. Start it with git bisect start, mark the current commit as bad with git bisect bad, mark an earlier known-good commit with git bisect good <sha>, and Git will check out intermediate commits for you to test. When a test can be expressed as a script, git bisect run ./test.sh automates the search: exit 0 means good, exit 1 means bad, and exit 125 means skip. Always finish a session with git bisect reset to return HEAD to where you started.

All chapters
  1. 1Undoing Commits and Local Changes
  2. 2Cleaning the Working Tree and Fixing .gitignore
  3. 3Rewriting History with Rebase
  4. 4Merging and Conflict Resolution
  5. 5Stashing Work in Progress
  6. 6Branches, Remotes, Tags, and Force-Push Safety
  7. 7Investigating and Searching History
  8. 8Advanced Recovery, Configuration, and Housekeeping

Drill it

Reading is not remembering. These come from the Git Recovering From Common Mistakes deck:

Q

Undo the last commit but keep changes staged.

git reset --soft HEAD~1

Q

Undo the last commit AND discard changes.

git reset --hard HEAD~1 &nbsp;⚠ destructive.

Q

Undo the last commit but keep changes unstaged in the working tree.

git reset --mixed HEAD~1 (the default).

Q

Amend the last commit message.

git commit --amend -m 'new message'