I built my own Git clone. It was way simpler than I expected.
I built a mini version of Git from scratch — complete with init, add, commit, branch, log,checkout and status. Here is what I learned under…
I built my own Git clone. It was way simpler than I expected.
I built a mini version of Git from scratch — complete with init, add, commit, branch, log,checkout and status. Here is what I learned under the hood.
My Very First Blog Post.

I want this tutorial to focus on concepts rather than a lot of code. I’m writing it the way I wish someone had explained Git to me before I learned how to use it. We won’t be talking about every single Git command. Instead, in the first part, we will look at how basic Git works, and in the second part, we will dive into how Git operates under the hood. This will give you the foundation to understand how all the other commands work (hopefully🤞).
What the hell is Git useful for?
Git is a super useful tool for developers. It helps us to work with code more efficiently. Here are the daily situations where Git can be a lifesaver:
- I want to add new functionality to my website and then compare new vs old versions. ✅
- Me and my teammate want to work on the same website, while each of us are building different parts. ✅
- You break production (which you absolutely will 😂) and then use Git in order to check super fast what part of the code was responsible for this behavior.
…AND MANY MORE.
How the hell is Git doing it?
Git is very smart; it knows every change you make to your files. HOW?
Well, I hate to break this to you, but Git is not this automatic robot that actually saves everything magically when you make a change to any part of your codebase.
ANSWER: We are the main heroes. Git is just a CLI tool helping us save desired changes.
OKAY, BUT WHAT IS GIT SAVING?
When we want to save a file’s current snapshot, Git will take this file’s content, pick a new box, and put this new file in it. If multiple files were selected, Git will save all of them.
Git internally has multiple main commands that help us execute its functionality. These are the 4 essential commands we need to understand:
**init** — Creates a folder called.gitin the working directory. The Git engine and every saved file by Git live in this folder. This is the very first command we run in a repo.**add** — Tells Git to track certain specified files. For example:git add .tracks every file in the directory, whilegit add example.txttracks only that specific file.**commit** — Tells Git to look for all tracked files, put their current snapshots in a box, zip it up, and store it as a new commit. Think of a commit as just a locked box.**checkout** — Creates a new branch. A branch is like a different room we use in the.gitwarehouse to store all our new boxes.
This way, Git will always have a version of your files zipped up and stored. If anything goes wrong, we can always jump back in time and check that snapshot.
This was a super simple walkthrough of the absolute basics. We didn’t deeply touch branches yet, but I wanted to focus on the core foundation first.
Now lets solve mystery of Git and reverse engineer .git folder:

Git works by using structure of simple texts, bytes and folders. this way it can track which branch you are looking at, which commit we are on and many more…
lets reverse engineer our minimal Git clone, based on the structure provided in graph:

- 1. HEAD Just a file that contains a pointer to the branch you are currently on. It has literally the simplest structure:
ref: refs/heads/{current-branch-name}. By observing this file and updating it on every checkout, Git knows exactly which room in the warehouse you are standing in. - 2. refs Just a folder containing a subfolder called
heads, which itself contains files named after your branches. Every branch you've checked out lives here, and each file points directly to the latest commit hash for that specific branch. - 3. objects This folder acts as the database for your entire repository. Simply put, it contains every commit you have ever made and all of your file snapshots stored as subfolders.
- 4. index The file responsible for the
git addcommand. It saves the temporary information that maps your tracked files directly with their unique hashes.
WAIT, WHAT THE HELL ARE THE HASHES, DUDE?
Instead of using normal, human-readable names, Git relies entirely on hashing. We hash filenames, commits, and everything inside the objects folder.
Folder names have a very specific structure to give Git a massive performance boost: when we track a file or make a commit, Git takes the first two characters of the generated hash to create a subfolder, and uses the remaining characters to name the file inside that folder.
Files contain different content based on whether they were used for a staging operation, a commit operation, or something else.
Here are the main file types you will see:
BLOB (Binary Large Object)
It’s simple: it just stores the compressed raw content of a staged file. Your original file content is compressed to binary and stored safely.
- Example: It’s a byte-formatted file containing the exact code or text taken from your staged file. That’s it.
TREE
This is a file in the objects directory that maps out your folder structure. Think of it as a directory listing that maps: hash | filename or tree hash | directory name. It points to the snapshot hashes created during staging.
- Example of a tree file structure:
{mode} {type} {sha-1 hash} filename1.txt
{mode} {type} {sha-1 hash} filename2.txt
{mode} {type} {sha-1 hash} filename3.txt
- mode: Info about the file type and execution permissions.
- type: Info about what type of file this hash points to (usually a
treeor ablob). - sha-1 hash: The unique hash connected to that specific blob or sub-tree.
- filenames: The name of the original file or folder.
COMMIT
The commit file ties everything together. It looks like this:
- message: The commit message you passed as an argument during
git commit -m. - tree: The hash of the newly assembled tree containing all modified file and folder hashes.
- parent: The hash of the previous commit that came before this one.
⚠️ SUPER IMPORTANT: The content in every file is compressed into bytes format instead of storing it directly with UTF-8 or normal text formats. In a custom clone, you’d use something like the
zliblibrary for this compression.
HOW THE HELL DOES THE INDEX FILE WORK?
To make this completely clear, when you execute git add filename.txt, here are the exact steps happening under the hood:
- Git prepares a unique hash name for
filename.txtbased on its content and type (blob). - It compresses the content of
filename.txtinto bytes and creates a new file named after that hash. It stores it using the 2-character folder split inside theobjectsdirectory. - It updates the
indexfile to map your human-readablefilename.txtpath directly to that new hash.
Congrats! You are now tracking your file.
What if we want to add a whole directory? (Like git add .)
Git will recursively loop through all files in the directory and update each individual file using the exact same staging strategy explained above.
HOW THE HELL DO BRANCHES WORK?
As we established, the HEAD file contains a pointer to the branch Git is looking at right now.
- Example content:
ref: refs/heads/main
The refs/heads folder contains exactly one file for every branch created in the system.
- File Name = The name of the branch.
- File Content = The exact hash of the latest commit on that branch.
The Polished Intro
Why am I writing this? I want to become a better writer and share knowledge. But honestly, I am also writing this for myself — as a personal guide I can look back at in the future whenever I need a quick summary of how this technology works under the hood.
A quick disclaimer: As I write this, I am half-asleep. I wasted the entire past week coping hard, waiting for the “perfect moment” to write the “perfect first blog post.” But honestly? Fuck perfectionism.
Refusing to take action because of perfectionism is a curse. Get rid of it. Do the shitty work over and over again, because each time, it will get a little better. Repetition is what leads to mastery, and the biggest problem with perfectionism is that it limits your repetition count. 🫶😄
메타데이터
- post_id
- 322a322eeea9
- slug
- i-built-my-own-git-clone-it-was-way-simpler-than-i-expected-322a322eeea9
- url
- https://medium.com/@jamaspishvilinika12/i-built-my-own-git-clone-it-was-way-simpler-than-i-expected-322a322eeea9
- canonical_url
- https://medium.com/@jamaspishvilinika12/i-built-my-own-git-clone-it-was-way-simpler-than-i-expected-322a322eeea9
- author_url
- https://medium.com/@jamaspishvilinika12
- status
- ok
- fetched_at
- 2026-06-09 15:37:30