Four object types
Git stores everything as content-addressable objects under .git/objects. There are four types: blob (file contents), tree (directory listing of blobs and subtrees), commit (snapshot pointer with author, committer, message, and parents), and tag (annotated tag with signer and message). Each is named by the SHA-1 (or SHA-256) of its content.
Inspecting
git cat-file -t <sha> # type
git cat-file -p <sha> # pretty-print
git cat-file -s <sha> # size
git ls-tree HEAD # list tree contents
git rev-parse HEAD^{tree} # tree of HEAD
Loose vs packed
Newly created objects start as loose: one zlib-compressed file per object under .git/objects/xx/yyyy.... Garbage collection later combines many objects into a packfile under .git/objects/pack/, sharing common bytes via delta compression. See "Git internals: packfiles and delta compression".
Hashing
Compute an object hash without writing it:
echo "hello" | git hash-object --stdin
git hash-object -w README.md # write to object DB
Trees encode permissions
A tree entry is mode + name + sha. Modes are 040000 (directory), 100644 (regular), 100755 (executable), 120000 (symlink), 160000 (gitlink/submodule). Git does not store other Unix permissions.
Walking history
git log --raw # show changed blobs
git log --pretty=raw # show internal commit format
git rev-list --objects HEAD # commits + reachable trees + blobs
rev-list --objects is what git fsck and git pack-objects use under the hood.
Reachability and pruning
An object is reachable if some ref (branch, tag, reflog entry) leads to it through the commit-tree-blob graph. Unreachable objects are pruned by gc after the reflog expiry window (default 90 days for reachable, 30 for unreachable).
git fsck --unreachable
git gc --prune=now
SHA-256 transition
Modern Git supports SHA-256 repositories (git init --object-format=sha256). Interop with SHA-1 repos remains limited; choose carefully for new projects expecting decades of life.
Common mistakes
Editing files under .git/objects directly. Don't. Use plumbing commands like git hash-object and git update-ref. Assuming SHA-1 collisions are impossible — Git includes hardened collision detection (SHAttered) by default. Confusing tree SHA with commit SHA in scripts; HEAD alone resolves to a commit, HEAD^{tree} to its tree.
Related
See "Git internals: packfiles and delta compression", "Git internals: references and the reflog", and "Git internals: the index format".