How Git Works Internally
So you've been using git add, git commit, git push like a good developer. But have you ever wondered what actually happens when you run these commands

i was a nobody until the covid-19 and like most of the devs from this covid-19 wave, i too started learning something to transition from that nobody to somebody/someone because i had some spare time during ๐ & after all those online classes.
so fast-forward โฉ to 2025 i am currently a frontend developer who
- is still learning basics of javascript
- primarily uses CSS for styling
- ships a couple of apps every now and then
- uses react.js as the primary framework
impact:
- Sep,2022 developed the first website aka current one for MuLearn Foundation
- 2023 developed the web app for MuLearn Foundation, used by over 30,000+ students
- 2024 - present co-founded the event management and ticketing platform makemypass.com along with few sub-products such as hoogo, premote, quizit, jusvote, leadx
- 2025 - present working at ente.io
Where does the code GO? How does Git remember everything? What sorcery is this? Today we're going DEEP. We're opening that mysterious .git folder and understanding what the hell is inside.
The .git Folder โ Where All the Magic Lives
When you run git init, Git creates a hidden folder called .git in your project directory. This folder? It IS Git. Delete this folder and boom โ your entire Git history is gone. No more commits, no more branches, nothing. Just regular files. So what's inside this magical folder?
.git/
โโโ HEAD
โโโ config
โโโ description
โโโ hooks/
โโโ index
โโโ info/
โโโ logs/
โโโ objects/
โโโ refs/
โ โโโ heads/
โ โโโ tags/
โโโ COMMIT_EDITMSG
โโโ FETCH_HEAD
โโโ ORIG_HEAD
Looks intimidating right? Let me break it down:
HEAD โ tells Git "where am I right now?", points to current branch
config โ repo configuration, author name, email, remote URLs
index โ your staging area, when you do
git addfile info goes hereobjects/ โ THE MOST IMPORTANT FOLDER, stores everything โ files, commits, trees
refs/ โ pointers to commits, branches live in
refs/heads/, tags inrefs/tags/logs/ โ tracks when refs were updated, useful for
git refloghooks/ โ scripts that run automatically on Git events
Git Objects โ The Building Blocks
Git is basically a content-addressable filesystem. Fancy words, simple meaning โ Git stores everything as objects, and each object has a unique ID (a hash). There are THREE main types of objects:
1. Blob (Binary Large Object) A blob is basically the content of a file. Just the content, not the filename, not the location โ just what's inside. When you add a file to Git, it creates a blob with the file's content and generates a SHA-1 hash for it. Same content = Same hash. Always.
2. Tree A tree is like a directory listing. It contains:
references to blobs (files)
references to other trees (subdirectories)
filenames and permissions
Think of it as Git's way of saying "in this folder, there's file A (blob xyz) and subfolder B (tree abc)."
3. Commit A commit object contains:
pointer to a tree (snapshot of your project)
author and committer information
commit message
pointer to parent commit(s)
This is the unreadable shit you see when you look at raw Git data โ but it's actually beautifully organized.
The Objects Folder โ Let's Get Our Hands Dirty
Remember the objects/ folder? Let's see what's actually inside.
.git/objects/
โโโ 1b/
โโโ 05/
โโโ 5a/
โโโ 1c/
โโโ 8a/
โโโ pack/
โโโ info/
See those two-letter folders? 1b, 05, 5a? Here's the trick: Git takes the first 2 characters of the hash and makes it a folder name. The rest becomes the filename. So if your commit hash is 2b9b0a8hdec89a1667..., Git stores it as objects/2b/9b0a8hdec89a1667... Why? Performance. Instead of having millions of files in one folder, Git distributes them. You can actually READ these objects:
bash
git cat-file -p 2b9b0a8hdec
And you'll see the raw content โ the changes, the author, the commit message, the parent commit hash. Everything.
How Git Tracks Changes โ The Flow
Let me walk you through what ACTUALLY happens when you use Git.
When You Do git add:
Git reads your file's content
creates a blob object with that content
generates a SHA-1 hash for it
stores the blob in
.git/objects/updates the index (staging area)
Your file is now "staged" โ but not committed yet.
When You Do git commit:
Git takes everything in the staging area
creates a tree object representing current directory structure
creates a commit object pointing to this tree
stores author, message, timestamp, parent commit hash
updates branch pointer in
refs/heads/
And THAT'S IT. Your commit now exists as objects in the .git/objects/ folder.
How Git Uses Hashes โ Integrity on Steroids
Every single thing in Git is identified by a SHA-1 hash โ a 40-character hexadecimal string like 2b9b0a8hdec89a1667a4c5d8e9f0a1b2c3d4e5f6. Why is this genius?
Content-based addressing โ hash is generated FROM the content, same content = same hash, always
Integrity verification โ if even ONE bit changes, hash completely changes, Git detects corruption instantly
Deduplication โ same file in 10 commits? Git stores ONE blob
Distributed trust โ clone a repo and verify your copy is EXACTLY the same by comparing hashes
Branching โ It's Just Pointers
Here's a mind-blowing fact: branches in Git are just text files containing a commit hash. That's it. When you create a branch:
bash
git branch feature-xyz
Git just creates a file at .git/refs/heads/feature-xyz containing the current commit hash. When you switch branches with git checkout feature-xyz, Git updates the HEAD file to point to refs/heads/feature-xyz. That's why branching in Git is INSTANT. No copying files, no duplicating data. Just updating a pointer. How does Git know which branch you're on?
bash
cat .git/HEAD
Output: ref: refs/heads/main HEAD points to a branch, and that branch points to a commit. Simple.
The Dangerous HARD โ Reset vs Revert
Now here's where things get spicy.
git reset --hard <commit> This command makes the HEAD pointer go to the specified commit. But in the process, the commits after that are LOST. Like, if you have commits A -> B -> C -> D (HEAD) and you do git reset --hard B, commits C and D? Gone. PUFF. UN-REVERTABLE (well, technically recoverable with reflog but that's advanced shit).
git reset <commit> (without --hard) This also moves HEAD back, but the changes from those commits are kept in staging area. They're not deleted abruptly. So there's still scope to commit them again. Much safer.
git revert <commit> This is the SAFE way. Instead of deleting commits, it creates a NEW commit that undoes the changes from the specified commit. Say there's a bug in the 3rd commit, and after that you've done new feature updates. Using reset would lose those feature commits too. Using revert creates a new commit that just removes the buggy changes while keeping everything else.
Reset ka Problem: Commits after the reset point are LOST. Revert is the Good Boi: Creates a new commit without the buggy commit's changes.
Before revert: O -- O -- BUG -- O -- O -- HEAD
After revert: O -- O -- BUG -- O -- O -- FIX (new commit that undoes BUG)
Building Your Mental Model
Stop memorizing commands. Start understanding the model:
Git is a database of objects โ blobs, trees, commits
everything is identified by hashes โ content-addressable
branches are just pointers โ lightweight, instant
HEAD tells you where you are โ points to current branch
staging area (index) is your prep zone โ between working directory and commits
Once you understand this, commands start making sense:
git add-> creates blobs, updates indexgit commit-> creates tree + commit objects, updates branch pointergit checkout-> moves HEAD, updates working directorygit reset-> moves branch pointer (dangerous without care)git revert-> creates new commit that undoes changes (safe)
Wrapping Up
The .git folder isn't magic. It's just a well-organized database of objects and pointers. Understanding this makes you a BETTER developer because you know WHY commands work the way they do, you can recover from mistakes, and you can debug Git issues instead of just deleting and re-cloning. Next time you run git commit, remember โ you're not just "saving". You're creating a blob, building a tree, generating a commit object, updating refs, and moving HEAD. Pretty cool when you think about it. Now go explore your .git folder. I dare you.



