Two reference files covering: - git.md — config, daily workflow, diff, log, stash, remotes, tags - git-branching.md — branches, merge, rebase, cherry-pick, bisect, reflog, reset, revert, worktrees
6.9 KiB
6.9 KiB
Git Branching
Branches, merging strategies, rebasing, and history recovery.
Branches
# List
git branch # local
git branch -r # remote
git branch -a # all
git branch -v # with last commit
git branch --merged # merged into current
git branch --no-merged # not yet merged
# Create
git branch feature-login
git checkout -b feature-login # create + switch
git switch -c feature-login # modern syntax
# Switch
git switch main
git checkout main # older syntax
# Rename
git branch -m old-name new-name
git branch -m new-name # rename current
# Delete
git branch -d feature-login # safe (refuses if unmerged)
git branch -D feature-login # force delete
# Cleanup stale remote tracking branches
git fetch --prune
git remote prune origin # same effect
Merge
# Merge branch into current
git merge feature-login
# Merge with commit message
git merge feature-login -m "feat: integrate login"
# No fast-forward (always create merge commit)
git merge --no-ff feature-login
# Fast-forward only (fail if not possible)
git merge --ff-only feature-login
# Abort in-progress merge
git merge --abort
# Squash (combine all commits, don't auto-commit)
git merge --squash feature-login
git commit -m "feat: login feature"
Merge Strategies
| Strategy | When to use |
|---|---|
| Fast-forward | Linear history, no divergence |
--no-ff |
Preserve branch topology in history |
--squash |
Collapse noisy branch into single commit |
ours |
Keep our side entirely, discard theirs |
recursive / ort |
Default for diverged branches |
Conflict Resolution
# After merge conflict
git status # shows conflicted files
# Edit files, resolve markers:
# <<<<<<< HEAD
# our changes
# =======
# their changes
# >>>>>>> feature-branch
# Mark resolved
git add resolved-file.txt
git merge --continue
# or
git commit
# Use theirs/ours for a file
git checkout --theirs path/to/file
git checkout --ours path/to/file
Rebase
# Rebase current branch onto main
git rebase main
# Interactive rebase (rewrite last N commits)
git rebase -i HEAD~5
# Continue after resolving conflicts
git rebase --continue
# Abort rebase
git rebase --abort
# Rebase onto specific base
git rebase --onto main feature-base feature-branch
# Auto-squash fixup commits
git commit --fixup abc123
git rebase -i --autosquash main
Interactive Rebase Commands
| Command | Effect |
|---|---|
pick |
Keep commit as-is |
reword |
Keep commit, edit message |
edit |
Pause at commit for amending |
squash |
Merge into previous commit, combine messages |
fixup |
Merge into previous commit, discard message |
drop |
Remove commit entirely |
reorder |
Move lines to reorder commits |
Rebase vs Merge
| Merge | Rebase | |
|---|---|---|
| History | Preserves branch topology | Linear, clean |
| Conflicts | Resolve once | May resolve per commit |
| Shared branches | Safe | Dangerous (rewrites history) |
| Use case | Integrating feature | Cleaning up before merge |
Cherry-Pick
# Apply specific commit to current branch
git cherry-pick abc123
# Multiple commits
git cherry-pick abc123 def456
# Range (exclusive start)
git cherry-pick abc123..def456
# Without committing (stage only)
git cherry-pick --no-commit abc123
# Abort
git cherry-pick --abort
Bisect
# Start binary search for a bug
git bisect start
git bisect bad # current commit is broken
git bisect good v1.0 # this tag/commit was working
# Git checks out middle commit — test it, then:
git bisect good # if this commit works
git bisect bad # if this commit is broken
# Repeat until git finds the first bad commit
# Done
git bisect reset
# Automated bisect with a test script (exit 0 = good, exit 1 = bad)
git bisect start HEAD v1.0
git bisect run ./test-script.sh
Reflog — Recovery Safety Net
# Show reflog (all recent HEAD movements)
git reflog
git reflog show feature-branch # specific branch
# Recover deleted branch
git reflog # find the commit hash
git branch recovered-branch abc123
# Undo a rebase
git reflog # find pre-rebase HEAD
git reset --hard abc123
# Recover amended commit
git reflog # find pre-amend HEAD
git branch pre-amend abc123
# Reflog expires after 90 days (default)
Reset
# Soft — undo commit, keep staged
git reset --soft HEAD~1
# Mixed (default) — undo commit, unstage, keep working tree
git reset HEAD~1
# Hard — undo commit, discard everything
git reset --hard HEAD~1
# Reset to specific commit
git reset --hard abc123
# Reset single file
git restore --staged file.txt # preferred
git reset HEAD file.txt # older syntax
| Mode | Commit | Staging | Working Tree |
|---|---|---|---|
--soft |
Undo | Keep | Keep |
--mixed |
Undo | Undo | Keep |
--hard |
Undo | Undo | Undo |
Revert
# Create a new commit that undoes a previous one (safe for shared history)
git revert abc123
git revert HEAD # undo last commit
git revert abc123..def456 # range
# Without auto-commit
git revert --no-commit abc123
Worktrees
# Work on multiple branches simultaneously
git worktree add ../hotfix hotfix-branch
git worktree add ../experiment -b experiment
# List
git worktree list
# Remove
git worktree remove ../hotfix
# Prune stale entries
git worktree prune
Gotchas
- Never rebase commits already pushed to shared branches — it rewrites history
git reset --hardis permanent unless you know the reflog hashgit branch -Dforce-deletes — if unmerged, that work is only in reflog (90 days)- Cherry-pick creates a new commit with a different hash — it duplicates, not moves
- Bisect requires a clean working tree — stash or commit first
- Merge
--squashdoes not record the branch as merged — git won't know it was integrated - Reflog is local only — it doesn't sync to remotes
revertof a merge commit needs-m 1to specify which parent to keep
See Also
git— core workflow, config, stash, remotes, tags- Pro Git: Branching