Timelines

branching and reuniting - and why the flat printout is a view, not the truth

$ git branch payments-desk
$ git log --oneline --decorate -1
adeac3f (HEAD -> main, payments-desk) ...
one commit, two names - real output

A branch begins as nothing but a name. The ledger opens with one commit, and git branch payments-desk writes a second name for that same moment - no copying, no new commit, no thicker repository. The decorated log says it plainly: one id, both names on it. Twenty ideas cost twenty names.

$ git switch docs-desk
error: Your local changes to the following files ...
    index.md
...
Aborting
the guard: stopped BEFORE touching anything

Moving between branches is git switch's job, and it moves carefully. With an unsaved edit that would collide, the walk simply refuses - nothing touched, nothing lost. Clean edits ride along instead. The refusal message still says "checkout" (switch shares the older machinery); trust the behavior, not the wording: refuse, never overwrite.

$ git merge docs-desk
Updating adeac3f..efe50bc
Fast-forward
 index.md | 2 ++
...
the slide: a name moved, nothing was created

Some merges are not merges at all. When docs-desk simply continued main's line, git merge docs-desk found nothing to combine: it slid main's name forward to the newest commit and said so - Fast-forward - a name moved to an existing commit. No new commit exists. When you want the branch's existence on the record anyway, --no-ff files a real merge commit deliberately.

the knot: one commit, two parent threads - real ids
the knot: one commit, two parent threads - real ids

When both lines have moved, the merge is real. git finds the base - the commit both lines grew from - compares each side against it, combines what does not collide, and files one merge commit - a new commit with two parents. Both old tips survive as its parents; nothing is rewritten. The knot in the drawing is exactly that merge commit: 51923ce holding de1bf50 and bc7e5ed under one seal.

$ git log --oneline --graph --all
...
*   f58c7b4 reconcile: payments desk rulings
|\
| * d65824c add the postage line
| * 3b93359 raise the copy rate
* | 57853c4 discount the copy rate ...
the graph, asked for by name
reconciled - sealed by the bureau
reconciled - sealed by the bureau

After that merge, be careful what you believe. git log prints a flat list, and the flat list is a view - the graph never rearranged itself. A commit remembers its parents, never a branch; the printout is just one reading order, and timestamps prove nothing about ancestry. Ancestry orders history, not time - each branch's clocks advance on their own. When the flat list confuses you, ask for the graph by name.

# BEFORE   e0b1319, 8e84750
$ git rebase main
# AFTER    88f2b64, 5fcc5c3
re-filed: same notes, new numbers
the re-filed record: the NEW number on its face
the re-filed record: the NEW number on its face

There is a second way to reunite lines, and it does something merge never does: git rebase re-files your commits onto the new tip as brand-new commits. Same work, same notes, new ids - e0b1319 became 88f2b64 in the run below. The old commits linger unreferenced until cleanup. The rule that keeps teams sane: never re-file commits others already hold.

One case remains, and it deserves its own room: both sides changing the same line since the base, to different results. That is the classic merge conflict - git asking a question - and reading one calmly is the next chapter's whole job.