Back to blog
GIT

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

Feb 15, 2026 6 min read


Git is Not Magic

When you run git commit, something concrete happens. Git doesn't just remember your files — it stores them in a specific way, using a specific structure, inside a specific folder.

That folder is .git.

Understanding what's inside .git transforms Git from a mysterious tool into something predictable. You'll stop memorizing commands and start understanding what they actually do.


The .git Folder

When you run git init, Git creates a hidden .git folder in your project. This folder contains everything — all your history, all your branches, all your commits.

my-project/
├── .git/           ← Everything Git needs
│   ├── objects/    ← All your files and commits
│   ├── refs/       ← Branches and tags
│   ├── HEAD        ← Current branch pointer
│   ├── config      ← Repository settings
│   └── index       ← Staging area
├── index.html
└── style.css

Delete .git, and you lose all history. The folder is the repository.


Git Objects: The Building Blocks

Git stores everything as objects. There are three types you need to understand.

Blob — File Content

A blob stores the contents of a single file. Not the filename — just the content.

If two files have identical content, Git stores only one blob. This makes Git space-efficient.

Tree — Directory Structure

A tree represents a directory. It contains references to blobs (files), references to other trees (subdirectories), filenames, and permissions.

Think of a tree as a snapshot of your folder structure at a specific moment.

Commit — A Snapshot in Time

A commit ties everything together. It contains a reference to a tree (the project state), a reference to parent commit(s) (the history), author and timestamp, and a commit message.

A commit doesn't store files directly. It points to a tree, which points to blobs.


How Git Uses Hashes

Every object in Git has a unique identifier — a SHA-1 hash. This is a 40-character string like:

a1b2c3d4e5f6789012345678901234567890abcd

The hash is calculated from the content. This means:

Same content = same hash (always). If you create a file with the exact same content on two different computers, both will produce the same hash.

Different content = different hash (always). Even a tiny change produces a completely different hash.

Change one byte = completely different hash. There's no way to predict what the new hash will be.

This gives Git two superpowers:

Integrity — If content is corrupted during transfer or storage, the hash won't match. Git will know something is wrong.

Deduplication — Identical files are stored only once. If ten commits all have the same README file, Git stores one blob and points to it ten times.

When you see commit IDs like a1b2c3d, that's the first few characters of the full hash.


What Happens During git add

When you run git add index.html:

  1. Git reads the file content
  2. Git creates a blob object with that content
  3. Git compresses and stores the blob in .git/objects/
  4. Git updates the staging area (.git/index) to track this blob

  5. The file isn't simply copied — its content is hashed, compressed, and stored as an object. The staging area records which blob corresponds to which filename


  1. What Happens During git commit

  2. When you run git commit -m "Add homepage":

    1. Git reads the staging area
    2. Git creates a tree object representing the directory structure (which files exist, what their names are, which blobs they point to)
    3. Git creates a commit object that points to the tree, the parent commit, and includes your message, name, email, and timestamp
    4. Git updates the current branch to point to this new commit

    5. After committing, the staging area is cleared of pending changes, but the blobs remain in the object database forever (until garbage collected)


    1. How Git Tracks Changes

    2. Git doesn't store differences — it stores complete snapshots.

    3. Wait, isn't that wasteful?

    4. Not really. Here's why:

    5. Identical files aren't duplicated. If a file didn't change between commits, the new tree points to the same blob. No extra storage needed.

    6. Compression. Git compresses objects individually, and periodically packs similar objects together for even better compression.

    7. Speed. Full snapshots are faster to reconstruct than applying hundreds of diffs. Checking out an old commit is nearly instant because Git just reads the tree and blobs — no need to replay history.

    8. When you checkout an old commit, Git doesn't rewind changes one by one. It simply rebuilds the working directory from that commit's tree.



    1. The Object Database

    2. All objects live in .git/objects/. Let's peek inside:

    3. .git/objects/
      ├── a1/
      │   └── b2c3d4e5...    ← Object with hash starting "a1b2c3d4e5..."
      ├── e5/
      │   └── f6a7b8c9...
      ├── info/
      └── pack/              ← Compressed packs of objects
      
    4. Objects are organized by the first two characters of their hash. This prevents any single directory from having too many files, which would slow down the filesystem.

    5. You can inspect any object using Git commands:

    6. git cat-file -t a1b2c3d   # Show object type (blob, tree, commit)
      git cat-file -p a1b2c3d   # Show object content (pretty-print)
      
    7. Try this on a real repository. You'll see exactly what Git stores


    1. Visualizing the Structure

    2. Each commit is a complete snapshot. The history is a chain of snapshots, each pointing to its parent. Branches are just pointers to commits. Tags are also just pointers to commits.

    3. Everything is objects and references.


 Key Takeaways

  1. .git/ — The entire repository. Delete it and lose everything.
  2. Blob — Stores file content only. No filename, no metadata.
  3. Tree — Stores directory structure. Maps filenames to blobs and subdirectories to other trees.
  4. Commit — Stores a tree pointer, parent pointer(s), and metadata (author, message, timestamp).
  5. Hash — Unique ID calculated from content. Ensures integrity and enables deduplication.
  6. git add — Creates blobs and updates the staging area.
  7. git commit — Creates a tree and commit object, updates the branch pointer


Wrapping Up

  1. Git's internals follow a simple pattern. Everything is an object — blobs for file content, trees for directory structure, commits for snapshots. Every object has a unique hash based on its content. Objects reference other objects by hash. Commits are snapshots, not diffs.
  2. Understanding this model changes how you think about Git. Commands become predictable when you know what they're actually doing inside .git/. "Detached HEAD" makes sense when you know HEAD is just a file containing a reference. "Rebasing" makes sense when you know commits are immutable objects being recreated.
  3. The mystery disappears. Git becomes a tool you understand, not just a tool you use.


Resources

0 Comments

Sign in to join the conversation

No comments yet. Be the first to comment!