Understanding the Git Object Model¶
Overview¶
Explain blobs, trees, commits, and tags, and use git cat-file / rev-parse to inspect how history is stored — so reset, rebase, and recovery later make sense.
Git is a content-addressed object database. Commands move pointers; objects are rarely rewritten in place. That mental model unlocks reflog recovery and “detached HEAD” incidents.
Complete Introduction first. Diagrams use Excalidraw only.
This is a core tutorial in Module 1 · Version Control Fundamentals of the REBASH Academy Git for Cloud & DevOps Engineers series — written for Cloud, DevOps, Platform, and SRE engineers.
Prerequisites¶
Required¶
- Introduction to Git and Version Control
- Git installed (Module 2 can be done in parallel if needed)
Learning Objectives¶
By the end of this tutorial, you will be able to:
- Name the four object types
- Relate commits → trees → blobs
- Explain content-addressed SHA hashes
- Inspect objects with plumbing commands
- Connect branches to commit pointers
Architecture¶
This topic’s control points and relationships are shown below.
Theory¶
What¶
Git stores history as a content-addressed object database. The four object types are blob (file contents), tree (directory listing of names to blobs/trees), commit (a tree plus parent commit(s), author, and message), and tag (a named pointer, often annotated). Commands mostly move refs (branch and tag names); objects themselves are rarely rewritten in place.
Why¶
Ops incidents often look like “where did that commit go?” or “why did rebase break my SHA?”. Once you see that commits are immutable objects linked into a directed acyclic graph (DAG), reset, rebase, cherry-pick, and reflog stop feeling magical. Content addressing also gives integrity: change a byte and the object ID changes.
How it works¶
Object ID is essentially a hash of type plus content. Identical content yields the same hash, which is why Git deduplicates efficiently. A commit points at one root tree; that tree points at blobs and nested trees. Each commit (except the first) points at one or more parents, forming the DAG. Branches and tags are tiny files under .git/refs that store a commit ID. HEAD names the current branch, or a raw commit when you are in detached HEAD.
| Type | Stores |
|---|---|
| blob | File contents |
| tree | Directory entries (name → blob/tree) |
| commit | Tree + parent(s) + author/message |
| tag | Named pointer (lightweight or annotated) |
Plumbing tools such as git cat-file and git rev-parse let you inspect these objects directly when debugging.
Key concepts¶
- Immutable objects — rebase creates new commits with new IDs
- Refs are cheap —
git resetmoves a branch pointer; objects linger until garbage collection - Reflog remembers where HEAD pointed locally, even after “lost” commits
- Annotated tags store their own objects; lightweight tags are just refs
Common pitfalls¶
- Equating a branch name with a permanent identity — only the commit ID is durable
- Assuming deleted commits vanish immediately — they often remain until
gc - Hand-editing files under
.git/objects - Ignoring detached HEAD when checking out a tag or SHA for inspection
Hands-on Lab¶
Create a workspace for this tutorial.
Focus: inspect blobs/trees/commits with cat-file and rev-parse
Step 1 – Create objects and inspect¶
git init
git config user.name "REBASH Learner"
git config user.email "learner@rebash.local"
echo hello > hello.txt
git add hello.txt
git commit -m "chore: hello"
COMMIT=$(git rev-parse HEAD)
TREE=$(git rev-parse 'HEAD^{tree}')
echo "commit=$COMMIT"
echo "tree=$TREE"
git cat-file -t "$COMMIT"
git cat-file -p "$COMMIT"
git cat-file -p "$TREE"
Step 2 – Blob content¶
Final step – Cleanup note¶
Validation¶
- Lab commands run under
~/rebash-git/module-01/ - You can explain each Theory section in your own words
- You used modern tooling where it applies to this topic
- You can describe one production failure mode for this topic
Code Walkthrough¶
Production practice for Understanding the Git Object Model always combines:
- Inspect before you change (status, plan, logs, dry-run)
- Prefer reversible, documented changes (Git, IaC, drop-ins, version pins)
- Capture evidence (command output, pipeline logs) for handovers
- Prefer current tools and APIs over legacy shortcuts
- Least privilege — escalate credentials only when required
Keep runbooks short enough to follow under pressure. Automate checks; keep humans for judgement.
Security Considerations¶
- Treat credentials and tokens for git as privileged — never commit them
- Prefer short-lived auth (OIDC, roles, SSO) over long-lived keys
- Validate blast radius before apply/deploy/delete operations
- Restrict who can approve production changes
- Collect audit logs; limit who can read sensitive traces
Common Mistakes¶
Equating a branch name with a permanent identity — only the commit ID is durable
Validate assumptions against the Theory section and official docs before changing production.
Assuming deleted commits vanish immediately — they often remain until gc
Lab shortcuts (open security groups, admin roles, skip approvals) must not ship unchanged.
Changing production without a rollback path
Always know how to revert (previous artefact, prior release, state rollback, DNS failback).
Best Practices¶
- Encode Understanding the Git Object Model changes as code and review them in pull requests
- Pin versions (images, modules, actions, provider plugins)
- Separate environments with clear promotion gates
- Alert on symptoms with runbooks attached
- Destroy lab resources; tag everything with owner and expiry where possible
Troubleshooting¶
| Symptom | Likely cause | What to do |
|---|---|---|
cat-file fails | Wrong ID | Use git rev-parse |
| Empty repo | No commit yet | Create initial commit |
Summary¶
- Objects are immutable and hashed
- Branches are pointers; commits are snapshots
- Plumbing commands reveal the real model
Interview Questions¶
- Explain blob, tree, commit, and tag objects.
- How does a commit point to a tree?
- What makes Git content-addressed?
- How do you inspect an object with plumbing commands?
- Why does rewriting history change commit hashes?
Sample answer — question 2
Use git rev-parse and git cat-file -p on HEAD and its tree to see the object graph.
Sample answer — question 4
Signed commits/tags bind identity to hashes. Rewriting published history breaks signatures.