Git Internals and the Content-Addressable Object Store
See how Git objects connect logically, how packfiles, refs, and clone modes affect physical storage and transfer, and how to inspect a repository without confusing the object model with disk layout.
Publication & corrections: infostoa · Editorial standards
Individual author and specialist reviewer information is not provided for this article.
To understand a Git repository, separate its logical object model from its on-disk representation. Git names objects from their contents, and commits point to trees. That does not mean every object remains a separate file or every clone downloads the complete history.
Object IDs and the four object types
A Git object ID is not a hash of file bytes alone. Its input includes a header with the object type and length, a separator, and the content. The ID format also depends on whether the repository uses SHA-1 or SHA-256; do not assume every ID is a 40-character SHA-1 value.
| Object | Logical content | Relationship to filenames |
|---|---|---|
| blob | File bytes | Does not contain the filename or path |
| tree | Entry names, modes, object types, and IDs | Builds the directory hierarchy |
| commit | Root tree, parent commit(s), author and committer, message | Connects a project state to its history |
| annotated tag | Target object, tag metadata, optional signature | A lightweight tag is a ref without a separate tag object |
Within a repository, identical content with the same object header can yield the same logical blob ID, so multiple tree entries can refer to that blob. This means Git can avoid duplicate logical objects; it does not promise exactly one physical disk block in every storage format.
Separate a logical change from its disk cost
Change one byte in a large file and its content changes, so it receives a new blob ID. A tree that points to the changed file and a new commit may also be needed. Unchanged files can keep pointing to existing blobs, and identical trees can be reused.
That describes the logical graph. Loose objects may be stored as separate files, but Git can also group objects in packfiles and delta-compress similar objects. It is therefore incorrect to conclude that every one-byte edit leaves a complete new copy of a large file on disk. Delta compression also does not promise the same savings for every file. Actual storage depends on content, pack construction, compression, and which history remains available.
Branches and tags are names that point somewhere
A branch is a movable reference to a commit. “A branch is a pointer” is a useful model, but it does not mean there is always a 41-byte file under .git/refs/heads/. Refs may be loose or collected in packed-refs, and their representation can vary with repository configuration and ref backend. Branches and tags are not interchangeable: an annotated tag can have its own object, while a lightweight tag is just a ref.
You can inspect a local repository with:
git cat-file -t HEAD
git cat-file -p HEAD
git cat-file -p 'HEAD^{tree}'
git show-ref --head
The first commands show the object type and content at HEAD; the tree expression lists the top-level entries for that commit; show-ref lists refs known to the repository. Results depend on the repository’s current state. These commands were not run as part of this article review.
A clone does not always transfer the full history
A typical clone fetches history for selected remote refs, but “every clone downloads every historical object” is too broad. --depth creates a shallow history, while a partial-clone filter such as --filter=blob:none can defer some blob transfers until needed. The actual transfer depends on the requested refs, filter, and server support.
When large assets cause trouble, first identify the observed cost: clone transfer size, working-tree size, full-history storage, and many retained versions of a particular file are different problems. Shallow or partial clones adjust what is downloaded; Git LFS manages large-file content through a separate storage path. Choose after checking history-access needs, server support, and the team’s recovery and backup process.
Sources and verification scope
The object model, packfiles and deltas, ref layout, shallow and partial clones, and SHA-256 format were checked against Git Internals: Git Objects, Packfiles, the [git clone manual](https://git-scm.com/docs/git-clone), repository layout, and the hash-function transition document. The commands are suggestions for inspecting a reader’s own repository; no command output or storage measurement was produced for this article.