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) ...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
...
AbortingMoving 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 ++
...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.
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 ...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, 5fcc5c3There 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.