Inspecting State
Three commands answer "where am I?" in a repository: git status shows what has changed and what is staged right now, git diff shows the exact line-level changes, and git log shows the history that led here. They read state and change nothing.
Misreading repo state is the root cause of most accidental data loss — discarding the wrong file, resetting past work you meant to keep, committing half of what you intended. Reading state correctly is the cheap habit that prevents the expensive recovery, so these commands belong before every operation that changes anything.
Status
git status sorts your files into three buckets: staged (going into the next commit), modified-but-unstaged (changed on disk, not yet added), and untracked (Git has never seen them). It also tells you the branch and whether you are ahead of or behind the remote. git status -sb gives the same picture in a compact two-letter-per-file form once you know what the columns mean.
Diffing the Trees
The diff commands compare specific pairs of trees, and which pair you ask for is the whole point. git diff with no arguments compares the working tree to the index — your unstaged changes. git diff --staged compares the index to HEAD — what is staged and headed into the next commit. git diff <a> <b> compares any two commits. Asking for the wrong pair is why a change can look like it vanished.
Reading History
Bare git log dumps full commit entries newest-first, which buries the structure on any real repository. --oneline collapses each commit to one line, --graph draws the branch and merge topology, and --stat shows which files each commit touched. Filters narrow it down: --since, --author, -p to show each commit's diff, and -S<string> — the pickaxe — to find the commits where a given string entered or left the code.
Finding Who and When
git blame <file> annotates each line with the commit, author, and date that last changed it — useful for finding the commit and its reasoning, less useful as a way to assign fault, since a whitespace reformat can put an innocent author on every line. git show <commit> prints one commit in full: its message and its complete diff, which is the fastest way to see what a single commit actually did.
Following a Single File
A file's history can predate its current name. git log --follow <file> traces it across renames, so you see the full lifetime of the content rather than just the commits since the last git mv. Without --follow, history stops at the rename and the earlier work looks like it belongs to a different file.
git diff (no arguments) — compares the working tree to the index, so it shows only the changes you have not staged yet. Once you stage a change, it disappears from this view, which is exactly what makes people think it was lost.
git diff --staged (alias --cached) — compares the index to HEAD, so it shows what is staged and will go into the next commit. When a change "vanishes" from plain git diff after an add, this is the view that shows it.
- Running plain
git diffafter staging everything, seeing nothing, and concluding the changes were lost — they are staged, sogit diff --stagedis the correct view. - Browsing a large repo's history with bare
git logand getting lost, because without--oneline --graphthe branch topology is invisible. - Using
git blameto assign fault rather than to find the commit and its reasoning, missing that a reformat commit can mask the real author. - Hunting for when a string was introduced by scrolling through
git logby eye instead of usinggit log -S<string>, the pickaxe built for exactly that. - Reading
git logon a renamed file without--followand concluding the file has no history before the rename.
- Run
git statusbefore any state-changing command —reset,checkout,commit— to confirm what is staged. - Make
git log --oneline --graph --decorateyour default history view to see branches and merges at a glance. - Use
git diff --stagedto review precisely what a commit will contain before runninggit commit. - Use
git log -S<term>orgit log -G<regex>to find the commit that added or removed specific code. - Inspect one commit in full — message and diff — with
git show <commit>instead of guessing from the log summary.
hg status, hg diff, hg log, hg annotate (blame)Subversion svn status, svn diff, svn log, svn blamePerforce p4 status, p4 diff, p4 changes, p4 annotateFossil fossil status, fossil diff, fossil timelineKnowledge Check
You stage a change, then run plain git diff and see nothing. Where is the change?
- Staged — plain
git diffcompares the working tree to the index, so a staged change shows only undergit diff --staged - Lost — the act of staging removed it from the working tree and never wrote it into the index either
- In the previous commit, already recorded permanently against HEAD by the staging step itself the moment you ran it
- In the reflog, parked alongside the other HEAD movements until you run a manual restore to bring it back
What does git log --oneline --graph reveal that bare git log hides?
- The branch and merge topology — where branches diverged and rejoined — in a compact, scannable form
- The full multi-paragraph commit message body for each entry, which the
--onelineflag normally truncates away - Commits that bare log withholds from you because per-commit access control rules restrict which users may read them
- The remote's newer commits that you have not fetched yet, drawn in as a dotted line above your own branch tip
When does the pickaxe git log -S<string> beat reading the log by hand?
- When you need the commit where a specific string was introduced or removed, found directly rather than by scrolling
- When you want the log sorted by author name instead of by commit date, so that one person's changes to a file all group together
- When the repository was shallow-cloned with a fixed depth limit, so its older history is therefore incomplete on disk
- When you need to see the staged but uncommitted changes shown alongside the committed ones
What can git blame reliably tell you, and what can it not?
- It tells you which commit last touched each line; it does not reliably tell you who wrote the logic, since one reformat commit can take ownership of every line
- It reliably names the author who originally wrote each line, no matter how many later edits that file has since seen
- It lists every commit that has ever touched the file at all, presented in full graph order with each contributing commit's subject line attached for context
- It shows the currently staged but still uncommitted edits annotated against each line before you have committed them anywhere
You got correct