Git Versioning and Backup Workflows
Git Internal Logic
Git's Object Model
Most version control systems store changes as a set of differences, or deltas. If you change a line in a file, the system records just that change. Git doesn't work this way. Instead, every time you commit, Git essentially takes a picture of all your files at that moment and stores a reference to that snapshot. If a file hasn't changed, Git doesn't store the file again; it just includes a link to the previous identical version it has already stored. This approach makes operations like branching and checking out past versions incredibly fast.
Git thinks of its data like a series of snapshots, not a series of deltas.
This design choice makes Git fundamentally a content-addressable filesystem. In systems you might be familiar with, like RAG pipelines, you retrieve information based on a query. In Git, you retrieve data based on its content. Every piece of content, from a single file change to an entire project snapshot, is run through a hashing algorithm and given a unique ID. This ID, a SHA-1 hash, is derived directly from the content itself. If the content changes, even by a single bit, the hash changes completely. This ensures the integrity of your data; it's impossible to change a file's history without Git knowing about it.
First, if it isn’t yet clear, Git is fundamentally a content-addressable filesystem with a VCS user interface written on top of it.
Everything in Git is stored as one of three types of objects: blobs, trees, and commits. These are all kept inside the .git/objects directory, a simple key-value data store where the key is the object's SHA-1 hash and the value is the compressed object data.
Blobs, Trees, and Commits
Let's break down the three fundamental objects that make up Git's database.
blob
noun
A 'binary large object' that stores the contents of a file. A blob contains no metadata, not even the filename. It is just a chunk of data, a snapshot of a file's content at a specific moment. Git hashes the content to generate the blob's unique ID.
Next, there are tree objects. A tree is like a directory. It stores a list of blobs and other trees, essentially mapping filenames to their corresponding content (blobs) or subdirectories (other trees). Each entry in a tree contains a pointer (the SHA-1 hash) to a blob or another tree, along with the file's mode, type, and name. This is how Git reconstructs the file hierarchy for any given snapshot.
Finally, the ties everything together. It contains a pointer to the single top-level tree that represents the project's root directory for that snapshot. It also includes metadata: the author and committer information, a timestamp, and a log message. Crucially, it also contains a pointer to one or more parent commits, which is what creates the historical chain of changes. A commit with one parent is a regular commit, while a commit with multiple parents is a merge commit.
You can inspect these objects yourself using a few plumbing commands. For example, to see the contents of an object, you can use git cat-file -p <SHA-1_hash>.
# Find the hash of your most recent commit
$ git log -1
commit a1e8fb534354c4d2325000579483725b74c568f5
# Inspect the commit object
$ git cat-file -p a1e8fb5
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
parent 4a2b2e35a297e593c6812837c355c3c0b3950e41
author User <user@example.com> 1672531200 -0500
committer User <user@example.com> 1672531200 -0500
Update README
# Inspect the tree object from that commit
$ git cat-file -p 4b825dc
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 .gitignore
100644 blob d3b07384d113edec49eaa6235ad5e83a2141505e README.md
Understanding this object model is the key to mastering Git. When you run commands, you're not just manipulating files; you're creating and navigating a graph of these interconnected objects. This structure is what gives Git its power and flexibility.
Let's test your understanding of Git's core concepts.
How does Git fundamentally store changes every time you commit?
In Git's object model, what is the function of a 'tree' object?
Now that you understand how Git stores its data, you can start to appreciate why commands for branching, merging, and reviewing history work the way they do.