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
272 lines
6.9 KiB
Markdown
272 lines
6.9 KiB
Markdown
# Git Branching
|
|
|
|
> Branches, merging strategies, rebasing, and history recovery.
|
|
|
|
## Branches
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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 --hard` is **permanent** unless you know the reflog hash
|
|
- `git branch -D` force-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 `--squash` does not record the branch as merged — git won't know it was integrated
|
|
- Reflog is **local only** — it doesn't sync to remotes
|
|
- `revert` of a merge commit needs `-m 1` to specify which parent to keep
|
|
|
|
## See Also
|
|
|
|
- `git` — core workflow, config, stash, remotes, tags
|
|
- [Pro Git: Branching](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell)
|