- Description: Notes on Pro Git (2nd ed.) Chapter 3 — branches as movable pointers, branch + merge basics, merge strategies + conflicts, branch management, branching workflows (long-running, topic, trunk-based), remote branches (tracking, upstream, pruning), and rebasing (incl. the golden rule).
- My Notion Note ID: K2B-2-3
- Created: 2020-06-02
- Updated: 2026-05-19
- License: Reuse is very welcome. Please credit Yu Zhang and link back to the original on yuzhang.io
Table of Contents
1. Branches in a Nutshell
- Branch = lightweight movable pointer to a commit.
- Commit object = SHA-1 + author + message + tree pointer + parent pointer(s).
HEAD = pointer to the branch currently checked out.
- Creating a branch = creating a new pointer (cheap — no copies).
1.1 Parent notation
<ref>^n — n-th parent (only meaningful for merge commits, which have >1 parent).
<ref>~n — first parent, n times (i.e., ~3 = ^^^).
^ alone = ^1; ~ alone = ~1.
- Combinable:
HEAD~3^2 = grandparent's grandparent's second parent.
@{upstream} / @{u} — shorthand for the tracked upstream.
@{n} — n-th prior position of HEAD (reflog index).
2. Basic Branching and Merging
2.1 git branch
git branch — list branches; * marks current.
git branch <name> — create (doesn't switch).
git branch -v / -vv — last commit per branch (-vv shows tracking).
git branch --merged / --no-merged — relative to current HEAD.
git branch -d <name> — delete (refuses if unmerged).
git branch -D <name> — force delete.
git branch -m <old> <new> — rename.
2.2 git checkout / git switch
git checkout <branch> — switch.
git checkout -b <branch> — create + switch.
git checkout -b <branch> <start> — branch off specific commit/tag.
git checkout -b <local> <remote>/<branch> — create tracking branch.
git checkout -- <file> — discard worktree changes (legacy; see Ch 2 § 4).
- Modern split (Git 2.23+):
git switch <branch> — switch only.
git switch -c <branch> — create + switch.
git restore <file> — discard changes (no overloading).
2.3 git merge
git merge <branch> — merge <branch> into current.
- Strategies:
- Fast-forward: target is an ancestor of source → just move pointer (no merge commit).
- Three-way merge (recursive): find common ancestor + diverging tips → new merge commit with two parents.
git merge --no-ff <branch> — always create merge commit (preserves topic branch history).
git merge --ff-only — refuse non-fast-forward (CI safety).
git merge --squash <branch> — apply changes as a single staged set (no merge commit).
2.4 Conflicts
- Markers in the working tree:
<<<<<<< ... ======= — current branch (HEAD).
======= ... >>>>>>> — incoming branch.
- Resolve manually →
git add <file> → git commit.
git merge --abort — cancel mid-merge.
git mergetool — open visual tool (configure: git config merge.tool <name>).
git checkout --ours <file> / --theirs <file> — pick a side wholesale.
3. Branch Management
git branch -u <remote>/<branch> — set upstream.
git branch -vv — show branch + upstream + ahead/behind.
- Cleanup dead branches:
git fetch --prune
git branch --merged main | grep -v '^\* ' | xargs git branch -d
4. Branching Workflows
4.1 Long-running branches
- Pattern: multiple permanent branches at different stability levels.
- Classic GitFlow:
main (or master) — only stable release-ready code.
develop (or next) — integration; tested but not yet released.
proposed / pu (optional) — bleeding-edge experimental.
- Commits "graduate" upward as they stabilize → merge develop → main on release.
- Mental model: branches as work silos where commits flow from unstable to stable.
4.2 Topic branches
- Short-lived branch per feature/bug.
- Cheap to create + discard (Git's killer feature).
- Enables:
- Context-switch without losing work.
- Per-topic code review (focused diff).
- Multiple parallel approaches → keep best, discard rest.
- Lifecycle:
git switch -c iss91
git switch main
git merge iss91
git branch -d iss91
4.3 Integration vs trunk-based
- Integration (GitFlow): topic → develop → main with release branches. Heavyweight; suits long release cycles.
- Trunk-based: short topic branches merged frequently to main; release from main; favored for CI/CD shops. Uses feature flags for incomplete work.
- All branching happens locally → no server roundtrip required.
5. Remote Branches
<remote>/<branch> = remote-tracking branch: local read-only pointer to remote state at last sync.
- Updated by
git fetch <remote> (or git pull).
- Local and remote can diverge silently between fetches.
- Example:
origin/main may lag behind actual remote main if you haven't fetched.
5.1 Pushing
git push origin <branch> — push local <branch> to origin/<branch>.
- Refspec long form:
git push origin refs/heads/<branch>:refs/heads/<branch>.
- Push to different name:
git push origin <local>:<remote-name>.
- First push with tracking:
git push -u origin <branch> (sets upstream so future pull/push need no args).
5.2 Tracking branches (= upstream)
- When set,
git pull / git push operate against upstream without specifying remote/branch.
- Auto-created by:
git clone (sets origin/main ↔ main).
git checkout -b <local> <remote>/<branch>.
git checkout --track <remote>/<branch>.
git checkout <branch> when name uniquely matches a remote.
- Manual:
git branch -u <remote>/<branch> on existing local branch.
- Inspect:
git branch -vv (shows tracking + ahead/behind).
5.3 Deleting remote branches
git push origin --delete <branch> (or legacy :refs/heads/<branch>).
- Server keeps data until GC.
5.4 Pruning stale remote-tracking refs
- After someone deletes a remote branch, your local
origin/<branch> lingers.
git fetch --prune → cleans up.
git remote prune origin → same thing, explicit.
6. Rebasing
git rebase <base> — replay current branch's commits on top of <base>.
- Produces linear history vs merge bubbles.
git rebase <base> <topic> — checkout topic then rebase.
git rebase --onto <newbase> <upstream> <branch> — surgical: take commits from <upstream>..<branch> and replay on <newbase> (extract a sub-branch from a chain).
- Interactive:
git rebase -i <base> — reorder/squash/edit/drop commits.
- Conflicts during rebase: resolve →
git add → git rebase --continue (or --skip / --abort).
6.1 Golden rule
- Never rebase commits that exist outside your repository (i.e., that others may have based work on).
- Rebasing rewrites SHAs → collaborators get duplicate history.
6.2 Rebase vs merge
- Merge preserves topology (true history).
- Rebase produces clean linear history.
- Common team convention: rebase before pushing a topic branch, merge (or squash-merge) into main.
7. References