Commits are nodes; branches are pointers
Once you accept that commits are snapshots, the next move is to see how snapshots connect. Every commit (except the first) records the hash of its parent. Merge commits record two parents. The result is a Directed Acyclic Graph: directed (each link points only to the past), acyclic (you cannot follow links and end up where you started), graph (parallel branches and merges create real graph topology, not just a line).
Picture it. A ← B ← C ← D is a linear chain on main. Now you branch feature at B and add E ← F. The graph forks. When you merge feature back into main, you create a new commit G with two parents — D and F. Future history walks from G can reach all earlier work through either parent. Nothing is deleted; nothing is overwritten. The graph just grows.
Branches and tags are 41-byte files holding a single hash. Creating feature is writing one file. Switching to it changes HEAD to point at it. Deleting it removes the pointer but leaves the commits, which Git's garbage collector will eventually sweep if no other ref points at them. This is the answer to "how is branching so cheap?" — there is almost nothing to copy.
Most powerful Git commands — log, blame, bisect, rebase, cherry-pick — are graph operations. Once you read commands as graph instructions, the names stop feeling random. git log feature..main means "commits reachable from main but not from feature." That is set difference on the DAG.