Inside Git: How It Works and the Role of the .git Folder

We run commands like git add, git commit, git push — and things just work.
But at some point, a question naturally comes up:
What is Git actually doing behind the scenes?
Understanding Git internally doesn’t make you a Git wizard overnight, but it does remove a lot of fear and confusion. Let’s open the black box.
How Git Works Internally (High-Level View)
At its core, Git is not a tool that tracks files.
It is a tool that tracks snapshots of content.
Every time you commit, Git:
Takes the current state of your project
Breaks it into objects
Stores those objects in a smart, efficient way
Git doesn’t store differences like “line 5 changed from X to Y” by default.
Instead, it stores what the project looks like at that moment.
Everything Git does revolves around one hidden folder:
👉 .git
Understanding the .git Folder
When you run git init, Git creates a hidden .git directory in your project.
This folder is the entire Git database.
If you delete it, your project is no longer a Git repository.
Some important contents inside .git:
objects/
This is where Git stores all data — commits, files, directories — everything.
refs/
Keeps track of branches and tags.
A branch is simply a pointer to a commit.
HEAD
Tells Git which branch (or commit) you are currently on.
config
Repository-specific configuration.
In short:
Your code lives outside
.git, but Git’s brain lives inside.git.
Git Objects: The Building Blocks of Git
Internally, Git stores data as objects.
There are four main types, but three are the most important.
1. Blob (Binary Large Object)
A blob stores the content of a file — not the filename, not permissions, just raw data.
Important points:
Same content = same blob (even across different files)
Git avoids duplication automatically
Example:
If two files have identical content, Git stores only one blob.
2. Tree
A tree represents a directory.
It contains:
File names
Directory structure
Pointers to blobs and other trees
Think of a tree as a folder snapshot.
A tree object answers:
“What files exist here, and what blobs represent them?”
3. Commit
A commit ties everything together.
A commit object contains:
A pointer to a tree (project snapshot)
Parent commit(s)
Author information
Commit message
Timestamp
This is why Git history forms a chain of commits.
Each commit knows:
What the project looked like
What came before it
Simple Relationship
Commit → Tree → Blobs
That’s it.
This simple model is the foundation of Git.
How Git Tracks Changes (The Real Magic)
Git does not track changes file-by-file like traditional systems.
Instead:
When you modify a file, Git creates a new blob for that content
A new tree is created if structure changes
A new commit points to the new tree
Old data is never overwritten.
This is why Git is:
Fast
Reliable
Safe
You’re not editing history — you’re adding to it.
Why This Design is Brilliant
Understanding Git internals explains many Git behaviors:
Why commits are cheap
They’re just lightweight objects pointing to existing data.
Why branching is fast
A branch is just a pointer to a commit.
Why Git rarely loses data
Objects are immutable — once created, they don’t change.
Why you can recover “lost” commits
They often still exist in the object database.
Final Thoughts
You don’t need to understand Git internals to use Git —
but once you do, Git stops feeling mysterious.
Commands start to make sense.
Errors become easier to reason about.
And Git transforms from a “tool I memorize” into a “system I understand”.
If Git ever felt scary, this is the layer that removes that fear.
