Published September 5, 2026
4 min read
Intermediate
Developer ToolsInteractive visualizer

Git Internals Visualized: Commits, Branches, HEAD, Merge & Rebase

Manipulate a simplified commit graph to see how Git objects, branches, HEAD, merge, rebase, reset, and cherry-pick fit together.

Git Commit Graph Simulator

Open in Engineering Lab
Loading visualizer...

Git becomes much easier to reason about when you stop picturing branches as folders. Git stores immutable objects, while small movable references tell it which commit a name currently identifies.

A Git branch is primarily a movable reference to a commit, not a separate copy of your repository.

The simulator above is a simplified conceptual model. Use it to create commits, move between refs, merge histories, replay a commit, cherry-pick a change, and reset a branch. It intentionally does not implement conflicts, the reflog, every reset mode, or Git's complete object database.

From working tree to commit

The working tree is the checked-out set of files you edit. The index, often called staging, is the exact snapshot proposed for the next commit. A commit records that snapshot plus metadata and parent commit identifiers.

Running git add updates entries in the index. Running git commit writes any needed objects, creates a commit object, and advances the current branch ref. This is why staging can contain only part of your working-tree changes.

The object model

Git addresses objects by the hash of their content. At an accessible level, the important objects form this shape:

TEXT
Commit
Tree
 ├─ Blob   app.ts
 ├─ Blob   README.md
 └─ Tree   src/
      └─ Blob   index.ts

A blob stores file content, not its filename. A tree maps names to blobs and other trees. A commit points to a root tree, parent commit or commits, author information, and a message. Reusing unchanged objects is one reason Git does not need a separate full copy for every branch.

Refs, branches, and HEAD

A local branch such as main is a ref whose value is a commit identifier. HEAD normally points symbolically to the currently checked-out branch. When you commit, Git moves that branch forward and HEAD follows it.

TEXT
A ← B ← C
       main
       HEAD

In detached HEAD state, HEAD points directly to a commit instead of a branch ref. New commits are valid, but no branch name automatically retains them. Create a branch before switching away if you want an easy durable name for that work.

Switch and checkout

git switch feature moves HEAD to the feature ref and updates the index and working tree to match its commit, subject to safety checks for local changes. The older git checkout command can switch branches and restore paths; the newer commands separate those intentions more clearly.

Creating a branch is cheap because Git mainly creates a ref. The commits reachable from both names remain shared.

Merge creates a shared descendant

A fast-forward merge can move a ref when the target already descends from it. When histories diverge, a normal merge can create a commit with two parents. That merge commit preserves the fact that the histories joined.

TEXT
A ← B ← C ← G
     \       ↖
      D ← E ──┘

Git merges snapshots using a common ancestor; it does not merely paste two latest files together. Conflicts occur when Git cannot safely combine overlapping changes, and the index records the unresolved stages until you resolve them.

Rebase rewrites identity

Rebase finds commits unique to the current branch, resets the branch conceptually onto a new base, and replays those changes as new commits. Their content may be similar, but their parents and hashes differ.

Use rebase to produce a linear local story when rewriting those commits is safe. Avoid rebasing shared commits that collaborators already build upon unless the team has explicitly coordinated the rewrite.

Reset and cherry-pick

git reset moves a branch ref. Its soft, mixed, and hard modes differ in whether the index and working tree also change; the simulator only demonstrates ref movement. Before a destructive hard reset, check whether the work is committed or otherwise recoverable.

git cherry-pick <commit> applies a chosen commit's change onto the current position and creates a new commit. Like rebase, the result has a new identity even when the patch is equivalent.

A practical recovery workflow

When history surprises you, inspect before mutating:

BASH
git status
git log --graph --decorate --oneline --all
git reflog

The graph answers which commits exist and which refs reach them. The reflog records recent local ref movements and often makes an apparently lost commit recoverable. Create a temporary branch at the commit before experimenting further.

Key takeaways

  • Commits are immutable snapshots linked to parent commits.
  • Branches are movable refs; HEAD identifies what is currently checked out.
  • Merge usually preserves divergence with a two-parent commit.
  • Rebase and cherry-pick create new commit identities.
  • Reset moves a ref, with mode-dependent effects on the index and working tree.
  • Inspect the graph and reflog before rewriting or discarding work.