Section 1 · Git's Model
Reading History: Commits as a Graph
16 min3 min readChoose wisely
Lesson at a glance
Read a repository’s history with git log, git show and git diff, name any commit relative to HEAD, and picture history as a graph of snapshots linked to their parents.
No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.
Your portfolio has a handful of commits now. Six months from now it will have hundreds, and the question you’ll actually ask is never “what’s the history?” but something sharper: when did the footer break, what did this file look like before the redesign, which commit added that colour. Reading history well is how you answer those in seconds.
The everyday view
Plain git log prints every commit, newest first, with full IDs and dates. It’s thorough and tiring. This is the version to remember:
git log --oneline --graph --all* e5d81c0 (HEAD -> main) Merge branch 'dark-mode'
|\
| * d4a7f20 (dark-mode) Add dark mode colors
* | c39be11 Add projects page
|/
* b2e04f3 Add navigation bar with base styles
* a1c9d72 Add home pageRead it bottom to top for chronology. Each * is a commit; the lines show which commit came from which. In parentheses are labels: main and dark-mode are branches, and HEAD -> main means you’re on main. --all matters: without it, Git shows only commits reachable from where you are, and the dark-mode line would still be there only because it was merged.
Long output opens in a pager. Use the arrow keys or space to scroll and q to quit.
Useful filters, all combinable: -n 5 (last five), --stat (which files changed), -p (full diffs), --author="Maya", --since="2 weeks ago", and -- index.html (only commits that touched that file).
Commits form a graph
The output above is a drawing of a directed acyclic graph, or DAG. Directed, because each commit points to its parent. Acyclic, because you can’t follow parents and end up where you started; a commit can’t be its own ancestor. Most commits have one parent. The root commit has none. A merge commit has two.
Keep this picture in your head. In section 2 you’ll see that a branch is nothing more than one of those labels, and every branching command moves a label or adds a circle.
Naming commits
You can name any commit by its ID, and Git accepts the shortest unambiguous prefix, usually 7 characters. IDs are hashes of the commit’s content, metadata and parent, so they never change, and in practice two different commits never share one.
Counting from where you are is often easier:
HEADis the commit you’re on.HEAD~1(orHEAD~) is its parent,HEAD~3is three generations back, following the first parent each time.HEAD^2is the second parent of a merge commit; one5d81c0above, that’sd4a7f20.- A branch name works anywhere a commit does:
dark-mode~1isb2e04f3.
Looking inside commits
git show c39be11 # message, author, date and the diff it introduced
git show HEAD~2:styles.css # the whole file as it was in that snapshot
git diff a1c9d72 HEAD # everything that changed between two snapshots
git diff HEAD~3 HEAD -- styles.css # the same, for one file onlygit diff takes any two commits because each is a complete snapshot. The diff is calculated on demand by comparing them. The same goes for the diff git show prints: it’s this commit’s snapshot compared with its parent’s.
A real investigation
Here’s how these commands combine. A friend tells you the footer on your projects page has disappeared, and you’re sure it was there last week. Start by narrowing the history to the file that matters:
git log --oneline --since="1 week ago" -- projects.html8f1e2aa Move project cards into a grid
c39be11 Add projects pageTwo suspects. Look at the newer one in full:
git show 8f1e2aa -- projects.htmlThe diff shows the <footer> block in red, removed along with the old list markup. That’s your culprit, found in under a minute. To grab the old footer markup without rewinding anything, print the file as it was in the parent commit and copy what you need:
git show 8f1e2aa~1:projects.htmlNothing in this investigation changed a single file or commit. Reading history is always safe, so do it freely and often. Most “Git emergencies” I’ve seen were really reading problems: someone panicked before looking at the graph, and the answer was already sitting in git log.
You’ve seen labels like main and dark-mode sitting on commits. Section 2 starts with what those labels really are and why creating one costs almost nothing.
Key takeaways
- History is a directed acyclic graph, each commit pointing to its parent, and a merge commit pointing to two.
git log --oneline --graph --alldraws the graph in the terminal, including branches you’re not on.git show <commit>prints one commit’s message and changes;git show <commit>:<path>prints a file as it was then.HEAD~1is the commit before the one you’re on,HEAD~3three steps back along first parents.git diff A Bcompares any two snapshots, and-- <path>limits it to one file.