Git Object Model
Git stores every version of a project as a graph of immutable objects named by the hashes of their contents, blobs for files, trees for directories, and commits for snapshots, which makes history tamper-evident and identical content free to store twice.
The Git object model is the data structure underneath Git. Every file, directory, and commit is stored as an object named by a cryptographic hash of its contents. Git's commands, from branching to merging, are operations on this graph of objects.
There are four kinds of object:
- Blobs hold file contents, without names or metadata.
- Trees represent directories, listing names, permissions, and the hashes of blobs and other trees.
- Commits point to one top-level tree, a snapshot of the whole project, plus zero or more parent commits, an author, a committer, timestamps, and a message.
- Tags in their annotated form name a specific object with a message and, optionally, a signature.
Because objects are named by their contents, Git is a content-addressable store. Two identical files anywhere in the history are stored once. Changing any byte changes the hash, which changes the tree containing it, which changes the commit. A commit's hash therefore covers the entire history behind it, making the structure a Merkle graph: tampering with any past object would change every hash after it.
A notable consequence is that Git stores snapshots, not changes. Each commit records a complete tree. A Diff is computed on demand by comparing trees. Merges work by comparing two commits with their common ancestor; see Three-Way Merge.
Storing full snapshots would be wasteful without compression. New objects are first written individually as compressed loose objects. Periodically Git packs them into packfiles, a form of Data Compression in which similar objects are stored as differences from one another. Packfiles are also what Git sends over the network when cloning or fetching, and partial and shallow clones work by sending only some objects; see Shallow Clone.
Branches and tags are lightweight. A branch is a small file containing a commit hash. HEAD names the current branch, or a commit directly; see Detached HEAD. Objects that no named reference can reach are eventually pruned, though Git keeps recent ones findable for a while; see Reflog.
Because objects never change, history is a persistent data structure: new commits add objects without modifying old ones. Rewriting history really means creating new objects and moving labels.
Git originally used the SHA-1 hash. Researchers demonstrated a practical SHA-1 collision in 2017, two different files with the same hash. Git added collision detection and has been working toward SHA-256 support. Accidental collisions remain astronomically unlikely.
Large binary files fit poorly in this model, since each version is stored in full and fetched with every clone; see Git LFS.
See also2
Staging Area
The intermediate snapshot in Git between the working files and the next commit, which lets a developer choose exactly which changes go into each commit, down to individual lines.
Version Control & Delivery15 connections
Garbage Collection
A runtime automatically reclaiming memory occupied by objects nothing can reach anymore.
Computation & Algorithms14 connections
Linked from9
- CommitVersion Control & Delivery
A recorded snapshot of a project with a message explaining it.
- Data CompressionComputation & Algorithms
Representing data in fewer bits by exploiting its patterns, either exactly (lossless) or by discarding what people won't notice (lossy), with limits set by information theory.
- Detached HEADVersion Control & Delivery
The Git state in which the current checkout points directly at a commit rather than a branch, harmless for looking around but a trap for new work, since commits made there belong to no branch and can quietly disappear.
- Garbage CollectionComputation & Algorithms
A runtime automatically reclaiming memory occupied by objects nothing can reach anymore.
- Git LFSVersion Control & Delivery
A Git extension that stores large binary files on a separate server and keeps small pointer files in the repository, so history stays light enough to clone.
- Persistent Data StructureComputation & Algorithms
Data structures that preserve every previous version when changed, sharing unchanged parts between versions so "copying" is cheap.
- Shallow CloneVersion Control & Delivery
Ways to fetch less than a whole Git repository, by cutting history, deferring file contents, or checking out only some directories, and what each breaks.
- Staging AreaVersion Control & Delivery
The intermediate snapshot in Git between the working files and the next commit, which lets a developer choose exactly which changes go into each commit, down to individual lines.
- Three-Way MergeVersion Control & Delivery
Combining two lines of work by comparing both against their common ancestor.