The Atom of Git History
When you run git commit, you might think Git stores a list of the changes you made — a diff showing what was added and removed. It doesn't.
Git takes a full snapshot of what your entire project looks like at that moment. Think of it like a photograph of your filesystem, not a list of edits. Every commit is a complete picture.
If a file hasn't changed since the last commit, Git doesn't store it again. It simply reuses the existing blob object for that file. The new tree object points to the same blob. This is why snapshots are efficient — unchanged content is automatically deduplicated through the content-addressing scheme.
What's in a Commit?
A commit object contains:
- Tree Pointer: The SHA-1 of the root tree object representing the project snapshot.
- Parent(s): The SHA-1 hash(es) of the preceding commit(s). This is what creates the history chain. A merge commit has two or more parents.
- Author: Who wrote the change and when (name, email, Unix timestamp, timezone).
- Committer: Who applied the commit. Usually the same as the author, but differs after a rebase or cherry-pick.
- Commit Message: The human-readable description of why the change was made.
The SHA-1 of the commit is computed from all of this data combined. Change a single character in the message, or shift the timestamp by one second, and you get a completely different hash. This is why rebasing "rewrites history" — it creates new commit objects with new hashes, even if the file changes are identical.
Key Point: Git stores complete snapshots, not diffs. Efficiency comes from content-addressed deduplication — unchanged files share blob objects across commits. The commit hash is a cryptographic fingerprint of the entire snapshot including metadata, which is why any rewrite produces a new hash.