█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Software Engineering/Git and GitHub Pro/Git Internals: Commits, Trees, and Blobs
45 minIntermediate

Git Internals: Commits, Trees, and Blobs

After this lesson, you will be able to: Understand what commits, trees, and blobs actually are inside .git, and why that mental model makes merges, rebases, and recovery commands stop being magic.

Most engineers use Git as a set of incantations. Engineers who understand the underlying object model (commits, trees, blobs) debug Git problems in seconds instead of asking on Slack for an hour.

This is a free introductory lesson. No purchase required.

Three object types: blob, tree, commit

Blob: the contents of a single file at a point in time. Identified by a SHA-256 hash of the contents. Same content = same hash = stored once. Tree: a snapshot of a directory. Contains pointers to blobs (files) and other trees (subdirectories), plus file names and modes. Commit: a tree + parent commit(s) + author + timestamp + message. Identified by a SHA of all that data. The chain of commits IS your repo history.

Inspect the object database yourself

Open any git repo and run these. The output tells the same story this lesson does.

tsx
# Show the SHA of HEAD
git rev-parse HEAD
# Show what HEAD points to (a commit object)
git cat-file -t HEAD # outputs 'commit'
git cat-file -p HEAD # shows the commit: tree + parent + author + msg
# Follow the tree pointer
git cat-file -p HEAD^{tree} # lists files + blob SHAs
# Read a single file blob by SHA
git cat-file -p <blob-sha> # outputs the raw file content
# See ALL objects (commits + trees + blobs) packed in .git
ls -lh .git/objects/pack

Why this matters for merges and rebases

A merge creates a new commit with two parents (your branch + the branch you merged in). The new tree is the result of combining both. A rebase rewrites each of your commits on top of a new parent, creating NEW commits with NEW SHAs. The old ones still exist in .git until garbage collection, which is why `git reflog` can recover them. Understanding this makes 'I just lost a branch' a 30-second fix (`git reflog` + `git reset --hard <old-sha>`) instead of a panic.

Detached HEAD and reflog: the safety net

Whenever HEAD points to a commit instead of a branch (e.g. `git checkout <sha>`), you're in detached HEAD. New commits made here aren't reachable from any branch and look 'lost' once you switch away. `git reflog` is your time machine: every move HEAD makes is logged for 90 days by default. If you ever think you've lost work after a `reset --hard` or a bad rebase, the answer is almost always `git reflog` + `git reset --hard HEAD@{n}`.

Hands-on: lose a commit, recover it

Practice in a throwaway repo. Knowing you can recover removes the fear of using Git boldly.

  1. 1

    Create a new repo: mkdir gitlab && cd gitlab && git init

  2. 2

    Add a file and commit it: echo a > a.txt && git add a.txt && git commit -m 'first'

  3. 3

    Make a second commit: echo b >> a.txt && git commit -am 'second'

  4. 4

    Note HEAD: git log --oneline

  5. 5

    Simulate disaster: git reset --hard HEAD~1 (you 'lose' the second commit)

  6. 6

    Find it: git reflog (the 'second' commit is in the log)

  7. 7

    Recover: git reset --hard HEAD@{1}

  8. 8

    Verify: git log --oneline shows both commits again

Common mistakes only experienced Git users avoid

Treating the staging area (index) as confusing magic. It's a third tree (working dir, index, HEAD) and `git status` shows the diff between them. Once you see it as three trees, it becomes obvious. Running `git rm` or `rm` on the wrong file and panicking. Files in .git/objects survive even when removed from the working tree; recover with `git checkout HEAD -- <file>`. Force-pushing without thinking about who else is on the branch. Force-push only after you understand reflog can save the receiver. Believing 'lost' work is gone. Until git gc runs (typically 30-90 days), it isn't.

Quick Check

What is a commit, fundamentally?

Pick the most precise answer.

Back to Git and GitHub Pro
Branching Strategies→