Introduction
In my earlier posts — Why Version Control Exists: The Pendrive Problem and Git for Beginners: Basics and Essential Commands — we addressed the why and the how of Git. Why version control became non-negotiable, and how developers interact with Git on a day-to-day basis using familiar commands like add, commit, and push.
This blog deliberately moves past that surface layer.
If you already know what commands to run, the next logical question is far more interesting:
What is Git actually doing behind the scenes?
At the center of that answer lies a folder most developers barely acknowledge — .git. It sits quietly at the root of every repository, hidden by default, yet it is the only reason Git works at all. Delete it, and Git disappears. Understand it, and Git suddenly becomes predictable, debuggable, and far less intimidating. And all of this happens with one single command, which is git init.
This article focuses mainly on that internal engine. We will not revise basic workflows or re-explain version control fundamentals. Instead, we will open the black box and examine how Git represents data, tracks changes, guarantees integrity, and builds history—starting with the role of the .git directory.
The objective is simple but ambitious: to help you build a mental model of Git. Not one based on memorized commands, but on understanding how blobs, trees, commits, and hashes fit together to form Git’s internal architecture.
Once that model clicks, Git stops feeling like magic—and starts feeling like engineering.
Rethinking Git: A Mental Reset
Before touching the .git folder, we need to fix one misconception.
Git is not:
- A backup system
- A cloud storage tool
- A diff tracker
Git is a content-addressable filesystem with a versioning layer on top. At its core, Git:
- Stores snapshots, not diffs
- Identifies everything using hashes
Every time you commit, Git:
- Takes the current state of your files
- Converts them into objects
- Links those objects together
- Stores them immutably
Git doesn’t ask “What changed?”
Git asks “What does the project look like right now?”
If you internalize this, Git stops feeling magical and starts feeling deterministic.
What Exactly Is the .git Folder?
The .git folder is the repository itself.
Your project files are just a working copy.
The real Git data—history, commits, branches, everything—lives inside .git.
If you delete the .git folder:
- Your code remains
- Git forgets everything
Why does .git exist?
Because Git needs a place to store:
- Project snapshots
- Object data
- Branch references
- Metadata
Inside the .git Folder: A Guided Tour
Now we are going to explore the entire .git folder — but keep in mind not everything here is meant for you to touch. I know it might feel overwhelming, but I am here to make you feel familiar with the .git directory. Let's deep dive into it:
1..git/HEAD — “Where am I right now?”
The HEAD file is a straightforward text file pointing to the current branch reference.
For example:

It tracks which branch you're currently on.
2..git/config — Project Settings
Contains repository-specific configuration settings (like remotes, user info, aliases), separate from global Git config.
Example:
[core]
repositoryformatversion = 0
filemode = true
bare = false
[remote "origin"]
url = git@github.com:user/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
3..git/objects/ — The Warehouse
The heart of Git’s content storage.
Git stores everything—files, directories, commits—as objects.
Objects are named based on the hash of the contents (SHA-1).
- blobs: store file contents
- trees: represent directory structures
- commits: snapshots
- tags: point to specific objects
Structure example:
objects/ab/cdef1234567890...
This approach ensures deduplication and data integrity.
4..git/refs/ — The References
The .git/refs folder contains references (or "refs") that point to specific commits in your Git repository. These include branches, tags, and the HEAD pointer, all stored as plain text files.
📁 Structure of .git/refs Directory
The .git/refs directory is organized into subfolders that categorize different types of references:
-
.git/refs/heads/--> Contains files for each local branch (e.g.,main,dev). Each file stores the hash of the latest commit on that branch. -
.git/refs/tags/--> Contains files for each tag. Tags are static references to specific commits, often used for marking releases. -
.git/refs/remotes/--> Contains remote-tracking branches (e.g.,origin/main). These reflect the state of branches on remote repositories.
5..git/logs/ — Git’s Black Box Recorder
The .git/logs folder stores recent updates to references (try git reflog command after reading this section to have more understanding), which are histories of how Git references (like branches and HEAD) have changed over time. It records movements of pointers such as HEAD, branches, and remote-tracking branches, including when they were updated and by which operation. Think of .git/logs as Git’s memory of where things used to point. Even if you mess up, Git remembers.
What lives inside .git/logs:
HEAD: A text file that logs every change to HEAD (checkout, commit, reset, rebase, merge, etc.).Each line shows: Old commit ID, New commit ID, User identity (name, email), Timestamp and timezone, A short description of the action (e.g., commit: add feature, checkout: moving from main to dev).refs/directory:
logs/refs/heads/: history of updates to each local branch tip (e.g., logs/refs/heads/main).
logs/refs/remotes//: history of updates to remote‑tracking branches (e.g., logs/refs/remotes/origin/main) when you fetch or pull.
Potential subpaths like logs/refs/stash when using git stash.
6..git/index — The Staging Area
Also called the staging area. Keeps track of changes staged for the next commit. It is a buffer between:
- Your working directory
- Your commit history
An unreadable binary file internally, tracking which content should be part of the next commit. It is the intentional design by which you can:
- Stage only part of your work
- Create clean, focused commits
- Avoid accidental changes
This explains why git add exists.
7..git/hooks/ — Automation Triggers
Contains scripts that Git can trigger at key events, i.e., Git can run before or after actions, such as before a commit (pre-commit) or after a push (post-receive).
Custom logic for code quality checks, CI/CD, and other tasks can be executed here.
8..git/info/ — Local .gitignore
Houses the exclude file, which can be used to ignore files locally, supplementing .gitignore.
What You Don’t Need to Worry About:
- You don’t need to edit files inside .git/
- You don’t need to memorize folder structures
- You don’t need to touch objects/ or logs/
Knowing what exists and why is enough for now.
After the git init command, you might not see all of these files or directories at first. But after the first commit, you will see all of these files or directories. So don't need to panic, seeing more files after your first commit means Git is working correctly.
Git Objects: Blob, Tree, Commit (The Core Model)
Everything Git stores is an object. There are three components based on which everything is happening.
Blob — The Content
A blob stores file content only.
- No filename
- No directory
- Just raw data
Example:
feature.txt → "New feature added."
Git stores "New feature added." as a blob.
If two files have the same content, Git stores one blob.
Tree — The Structure
A tree represents a directory.
- Maps filenames → blobs
- Can point to other trees
- Stores file permissions
Example:
Demo/ (tree)
|-- demo.txt (blob)
`-- src (tree)
`-- style.js (blob)
Trees do not store file content. They only point to blobs.

Trees tell Git:
- Which files exist
- Their names
- Their structure
Commit — The Snapshot
A commit ties everything together.
It stores:
- A reference to a tree (project state)
- A reference to parent commit(s)
- Author, timestamp, message
A commit does not store files.
It stores references to them.
Mental shortcut:
- Blob → What
- Tree → Where
- Commit → When & why
How Git Tracks Changes (Snapshots, Not Diffs)
This is where many beginners get confused.
Git does not store line-by-line changes internally.
It stores snapshots of file states.
When you modify a file:
- Git does nothing immediately
- No tracking happens yet
Git only records changes when you:
- Stage (
git add) - Commit (
git commit)
If a file hasn’t changed:
- Git reuses the old blob
- No duplication
- No extra storage cost
This is why Git is fast and efficient—even for large projects.
What Happens During git add
When you run git add:
- Git reads the file content
- Creates a blob object
- Hashes the content
- Stores it in .git/objects if it doesn't already exist (based on hash)
- Updates the index to point to that blob
Important insight:
git add→ "Prepare this snapshot for the next commit."
What Happens During git commit
When you run git commit:
- Git reads the staging area
- Builds a tree object
- Creates a commit object pointing to the tree
- Links it to the parent commit
- Moves the branch pointer forward
Nothing is overwritten, nothing is deleted, unless you rewrite it.
Hashes: Git’s Superpower
Git identifies everything using cryptographic hashes (SHA-1 or SHA-256). Example:
f43c5163416f89bjkie7d9ty43ca2e25604we760
This gives Git:
- Data integrity
- No duplication
- Tamper detection
If content changes:
- Hash changes
- Object identity changes
- History breaks visibly
This creates a chain of trust:
- Blob hash affects tree
- Tree hash affects commit
- Commit hash affects history
That’s why Git repositories are reliable at massive scale.
Closing Thoughts
Most Git tutorials teach commands.
Very few teach how Git thinks.
The .git folder is much more than a hidden subdirectory—it’s the central nervous system of your repository. By understanding what’s inside and how Git builds its history through objects, trees, commits, and references, you gain a powerful perspective on your codebase. With this mental model, concepts like rebase, reset, detached HEAD, and reflog stop being scary—and start making sense. Next time you run a Git command, you’ll know exactly what’s happening behind the scenes, inside the humble .git directory.
Follow for more beginner-friendly breakdowns of core software engineering concepts.









Top comments (0)