Beyond Code & Karma · Version Control
How git really works — internals, the DAG, and the philosophy of version control through Chitragupta's cosmic ledger.
Chapter 01 — The Foundation
Git internals surprise most developers: git is not a change tracker.
It is a content-addressable object store. Every file version you
ever commit exists as an immutable object, addressed by the SHA-1 hash of its
contents. The working directory is just a view — the real repository lives in
.git/objects/.
git diff is computed, never stored. Every commit is a complete
picture of your entire project at that exact moment.
Chapter 02 — Under the Hood
Everything Git knows lives in .git/. Delete it and Git is gone — your
working files remain, but all history, branches, and refs are lost. Understanding
this directory is understanding Git.
| Object | Contains | Created by |
|---|---|---|
| blob | Raw file contents (no name/path) | git add |
| tree | Directory listing — blob refs + subtree refs | git commit |
| commit | Tree ref + parent refs + author + message | git commit |
| tag | Commit ref + annotation + optional signature | git tag -a |
# Every file version is stored as a blob — raw content, nothing more git cat-file -p a1b2c3d # Output: the exact bytes of the file at that version # The SHA is derived from the content itself — Chitragupta's seal
# A tree is a directory snapshot — blob refs + subtree refs git cat-file -p HEAD^{tree} # 100644 blob a1b2c3d README.md # 040000 tree e4f5a6b src # Every directory level is its own tree object
# A commit wraps a tree snapshot + metadata git cat-file -p HEAD # tree e4f5a6b7c8d9e0f1 # parent a1b2c3d4e5f6a7b8 ← points to previous karma # author Deveshwar Jaiswal # committer Deveshwar Jaiswal # # feat: add authentication # Each commit is a complete snapshot — never a diff
git checkout is instant regardless
of history length.
objects/ — the content-addressable store (all blobs, trees, commits, tags)refs/heads/ — one file per branch, containing a SHArefs/remotes/ — remote-tracking refs (snapshots of remote branches)HEAD — current branch or detached SHAindex — the staging area (binary file)config — repo-level configurationlogs/ — reflog: every HEAD movement for 90 daysChapter 03 — The Graph
Every commit points to its parent(s). This forms a Directed Acyclic Graph — the data structure underlying every Git operation. Branches, merges, rebases, and cherry-picks are all just ways of reading, writing, or rearranging nodes in this graph.
# HEAD is just a text file cat .git/HEAD # ref: refs/heads/main ← attached (normal state) # A branch is also just a text file — 41 bytes cat .git/refs/heads/main # a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 # Detached HEAD — contains a SHA directly cat .git/HEAD # a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 ← wandering soul
refs/heads/ containing a single SHA. When you commit,
the current branch file is updated to the new SHA. That's it.
origin/main lives in refs/remotes/origin/main.
Chapter 04 — Operations
Creates an immutable commit object — blob + tree + commit — addressed by SHA. The current branch pointer advances. The SHA is content-derived: same tree + same parent + same message = same SHA, always.
# Each commit is a karma — permanently sealed by Chitragupta git add src/auth.ts git commit -m "feat: add JWT validation" # [main a1b2c3d] feat: add JWT validation # SHA is deterministic — same tree + same parent + same message = same SHA
Use: whenever a logical unit of work is complete. Commit early, commit often — history is cheap and rebasing lets you clean it up before sharing.
Avoid: committing broken states to shared branches. On private branches, commit freely and squash/rebase before merging.
Creates a 41-byte text file — nearly free. A branch is a movable pointer to a commit, nothing more. Deleting a branch deletes only the pointer; the commits remain until garbage collection.
# A branch is a dharmic path — a parallel reality that costs nothing git checkout -b feature/auth # 41 bytes — that's the entire cost git branch -v # * feature/auth a1b2c3d feat: add JWT validation # main a1b2c3d feat: add JWT validation
Use: always — one branch per feature, fix, or experiment. Branch names are free.
Avoid: long-lived branches that diverge significantly from main. The longer a branch lives, the harder the eventual merge becomes.
When main hasn't advanced since the branch was created, Git simply moves the main pointer forward — no merge commit, no new node in the DAG.
# Fast-forward — paths that never diverged rejoin cleanly git checkout main git merge feature/auth # Updating a1b2c3d..b2c3d4e # Fast-forward — no merge commit, no karma clash
Use: the default for short-lived branches that haven't diverged. Produces a clean linear history.
Avoid using --no-ff unless: you explicitly want a merge commit to mark the integration point (useful in release workflows).
When both branches have diverged, Git finds their common ancestor (the merge base) and creates a new commit with two parents. The merge commit preserves full history.
# 3-way merge — two dharmas converge, a new moment is born git merge feature/auth # Merge made by the 'ort' strategy. # The merge commit has two parents — it carries both histories git log --graph --oneline # * m7n8o9p Merge branch 'feature/auth' # |\ # | * b2c3d4e feat: add JWT validation # * | c3d4e5f fix: hotfix # |/ # * a1b2c3d init
Use: integrating long-lived branches (e.g. release branches) where the divergence history is meaningful.
Avoid: for everyday feature branches where you want a clean linear history — rebase first, then fast-forward merge.
Replays your commits on top of a new base. Each commit gets a new SHA — same diff, new parent, new fingerprint. History becomes linear. This is Maya: the perceived history changes, the underlying actions do not.
# Maya — the perceived history rewrites, the actions are unchanged git rebase main # First, rewinding head to replay your work on top of it... # Applying: feat: add JWT validation # New SHA — same diff, new parent, new fingerprint # The old commit is abandoned (no refs). Reflog preserves it.
Use: to keep feature branches up to date with main, and to produce a clean linear history before merging.
Never rebase: commits that have been pushed to a shared remote. It rewrites SHAs — anyone who based work on the old SHAs will face conflicts.
Copies a single commit's diff to the current branch. Creates a new commit with a new SHA — same changes, new moment in the ledger.
# Selective karma — one action carried to another path git cherry-pick a1b2c3d # [main b2c3d4e] feat: fix critical bug # Same diff, new SHA — a new moment with the same intention # The source branch is untouched
Use: to apply a specific bug fix from one branch to another without merging all of that branch's history.
Avoid: cherry-picking the same commit repeatedly across branches — it creates duplicate changes with different SHAs, which causes confusion during eventual merges.
Moves HEAD (and the current branch pointer) to a target commit. The three modes control what happens to the index (staging area) and working tree.
# --soft: turn back the clock, keep your preparations git reset --soft HEAD~1 # HEAD moves back. Changes stay staged. Ready to recommit.
# --mixed (default): return to before you staged git reset HEAD~1 # HEAD moves back. Index cleared. Working tree unchanged. # Your edits remain — just unstaged.
# --hard: pralaya — the dissolution git reset --hard HEAD~1 # HEAD moves back. Index cleared. Working tree wiped. # The commits still live in reflog for 90 days — nothing is truly lost.
--soft: undo the last commit, keep changes staged. Good for combining multiple commits into one.
--mixed: undo the last commit, unstage changes. Good for re-staging selectively.
--hard: discard everything back to a known good state. The reflog preserves all commits for 90 days — you can recover.
Never reset public commits (pushed to shared remote). Use git revert instead — it creates a new commit that undoes the change, preserving history.
Saves the current dirty state (staged + unstaged changes) to a stack and restores the working tree to the last commit. The Samskara of Git — latent impressions stored below the surface.
# Samskara — latent impressions stored below the surface git stash push -m "WIP: auth refactor" # Working tree is clean. The impressions wait. git stash pop # The samskara surfaces — changes restored to working tree
Use: when interrupted mid-task and needing to switch context quickly.
Prefer a branch for anything longer than a few minutes — stash entries are easy to forget and don't show up in git log.
Multiple working directories, one repository. All worktrees share the same
.git/objects/ — the same Chitragupta keeping all ledgers. The
Lokas (realms) of your codebase, coexisting simultaneously.
# Multiple lokas — realms of the same codebase, existing simultaneously git worktree add ../hotfix-dir hotfix/critical # ../hotfix-dir is now checked out to hotfix/critical branch # Both dirs share .git/objects — same Chitragupta keeps both ledgers git worktree list # /path/to/repo a1b2c3d [main] # /path/to/hotfix-dir b2c3d4e [hotfix/critical]
Use: when you need to work on a hotfix while keeping a long-running feature branch's working directory intact. Also excellent for running tests on multiple branches simultaneously.
Avoid: checking out the same branch in two worktrees simultaneously — Git prevents this as it would cause index conflicts.
Chapter 05 — Interactive
Step through 8 scenarios — commit flow, branching, merge, rebase, cherry-pick, reset, detached HEAD, and worktrees — and watch the commit graph update in real time.
Chapter 06 — The Cosmic Parallel
Every commit you make is an act recorded by Chitragupta —
Yama's scribe who keeps the cosmic ledger of every soul's actions with perfect
accuracy, never erasing, never forgetting. Git's object store is the
Akashic Record of your codebase:
immutable, content-addressed, eternal. Even git reset --hard cannot
truly destroy — it only moves the pointer. The commits still exist until
garbage collection (the great dissolution, Pralaya) sweeps them away.
The git reflog is your personal akashic record — every past HEAD
position preserved for 90 days.
And every commit is a karma — an action with consequences that propagate through the DAG. Branches are dharmic paths. Merges are karma resolutions. Rebase is Maya — the history looks different, but the underlying actions are unchanged.
| Git concept | Deity / Concept | Why |
|---|---|---|
| Commit log / SHA | Chitragupta | Yama's scribe — records every action with perfect, immutable accuracy |
| git init / first commit | Brahma | The first act of creation — the repository before any commit |
| git stash / stored refs | Vishnu | The preserver — holds what exists between active cycles |
| git reset --hard | Shiva | The transformer — clears the working state to begin again |
| Remote / origin | Brahman | The universal source — local repos are avatars of the remote |
| Worktree | Loka (realm) | Multiple concurrent realms of the same codebase |
| Merge conflict | Karma clash | Two dharmic paths with contradictory consequences — requires conscious resolution |
| git reflog | Akashic Records | Nothing is ever truly lost — every past HEAD position is recoverable |
| Rebase | Maya | The perceived history changes; the underlying actions do not |
| Detached HEAD | Wandering soul | Present in a moment outside any named path — commits here are lost without a branch |
Chapter 07 — Did You Know
git branch writes ~41 bytes to disk.
git rebase rewrites commit SHAs because the parent pointer changes —
same diff, different history, different hash. That's why you never rebase public commits.
git reflog retains every HEAD position for 90 days by default.
You can recover from almost any reset --hard or detached HEAD incident.