docs: add git howto collection
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
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -2,7 +2,7 @@
|
||||
|
||||
## Topics to Write
|
||||
|
||||
- [ ] git — common workflows, rebase, stash, bisect
|
||||
- [x] git — config, daily workflow, stash, remotes, branching, rebase, bisect, recovery
|
||||
- [x] ansible — playbook patterns, inventory, vault, variables, roles
|
||||
- [ ] podman — build, run, compose, volumes
|
||||
- [x] jq — filters, select, map, slurp, recipes, @format
|
||||
|
||||
271
topics/git-branching.md
Normal file
271
topics/git-branching.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# 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)
|
||||
258
topics/git.md
Normal file
258
topics/git.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# Git
|
||||
|
||||
> Distributed version control — track, branch, merge, and collaborate.
|
||||
|
||||
## Config
|
||||
|
||||
```bash
|
||||
# Identity
|
||||
git config --global user.name "Your Name"
|
||||
git config --global user.email "you@example.com"
|
||||
|
||||
# Editor
|
||||
git config --global core.editor vim
|
||||
|
||||
# Default branch name
|
||||
git config --global init.defaultBranch main
|
||||
|
||||
# Useful defaults
|
||||
git config --global pull.rebase true
|
||||
git config --global push.autoSetupRemote true
|
||||
git config --global rerere.enabled true
|
||||
git config --global diff.algorithm histogram
|
||||
git config --global merge.conflictstyle zdiff3
|
||||
|
||||
# Aliases
|
||||
git config --global alias.st status
|
||||
git config --global alias.co checkout
|
||||
git config --global alias.br branch
|
||||
git config --global alias.lg "log --oneline --graph --all"
|
||||
|
||||
# Show current config
|
||||
git config --list --show-origin
|
||||
```
|
||||
|
||||
### Config Scope
|
||||
|
||||
| Flag | File | Purpose |
|
||||
|------------|-------------------------|------------------|
|
||||
| `--system` | `/etc/gitconfig` | All users |
|
||||
| `--global` | `~/.gitconfig` | Current user |
|
||||
| `--local` | `.git/config` | Current repo |
|
||||
|
||||
Local overrides global overrides system.
|
||||
|
||||
## Init and Clone
|
||||
|
||||
```bash
|
||||
git init
|
||||
git init --bare repo.git # server-side (no working tree)
|
||||
git clone https://github.com/user/repo.git
|
||||
git clone --depth 1 https://... # shallow (latest commit only)
|
||||
git clone --branch v2.0 https://... # specific branch/tag
|
||||
```
|
||||
|
||||
## Daily Workflow
|
||||
|
||||
```bash
|
||||
# Status
|
||||
git status
|
||||
git status -s # short format
|
||||
|
||||
# Stage
|
||||
git add file.txt # specific file
|
||||
git add src/ # directory
|
||||
git add -p # interactive hunk staging
|
||||
git add -u # stage modified/deleted, not new
|
||||
|
||||
# Unstage
|
||||
git restore --staged file.txt
|
||||
git reset HEAD file.txt # older syntax, same effect
|
||||
|
||||
# Discard working tree changes
|
||||
git restore file.txt
|
||||
git checkout -- file.txt # older syntax
|
||||
|
||||
# Commit
|
||||
git commit -m "feat: add login page"
|
||||
git commit -am "fix: typo" # stage tracked + commit
|
||||
git commit --amend # rewrite last commit
|
||||
git commit --amend --no-edit # amend without changing message
|
||||
git commit --allow-empty -m "trigger" # empty commit (CI triggers)
|
||||
```
|
||||
|
||||
## Diff
|
||||
|
||||
```bash
|
||||
# Working tree vs staging
|
||||
git diff
|
||||
|
||||
# Staging vs last commit
|
||||
git diff --cached
|
||||
git diff --staged # same thing
|
||||
|
||||
# Between commits
|
||||
git diff abc123..def456
|
||||
git diff HEAD~3..HEAD
|
||||
|
||||
# Between branches
|
||||
git diff main..feature
|
||||
|
||||
# Specific file
|
||||
git diff -- path/to/file.txt
|
||||
|
||||
# Stats only
|
||||
git diff --stat
|
||||
git diff --name-only
|
||||
git diff --name-status # with A/M/D markers
|
||||
|
||||
# Word-level diff
|
||||
git diff --word-diff
|
||||
```
|
||||
|
||||
## Log
|
||||
|
||||
```bash
|
||||
# Compact
|
||||
git log --oneline
|
||||
git log --oneline -10 # last 10
|
||||
|
||||
# Graph
|
||||
git log --oneline --graph --all
|
||||
|
||||
# Detailed
|
||||
git log -p # with diffs
|
||||
git log --stat # with file stats
|
||||
|
||||
# Filter
|
||||
git log --author="alice"
|
||||
git log --since="2025-01-01"
|
||||
git log --after="2 weeks ago"
|
||||
git log --grep="fix:" # search commit messages
|
||||
git log -S "function_name" # search for string in diffs (pickaxe)
|
||||
git log -G "regex_pattern" # search diffs with regex
|
||||
git log -- path/to/file # commits touching file
|
||||
|
||||
# Format
|
||||
git log --pretty=format:"%h %an %ar %s"
|
||||
git log --pretty=format:"%C(yellow)%h%Creset %s %C(dim)(%ar)%Creset"
|
||||
|
||||
# Show single commit
|
||||
git show abc123
|
||||
git show HEAD~2:path/to/file # file at specific commit
|
||||
```
|
||||
|
||||
## Stash
|
||||
|
||||
```bash
|
||||
# Save work in progress
|
||||
git stash
|
||||
git stash push -m "wip: api refactor"
|
||||
git stash push path/to/file # stash specific files
|
||||
|
||||
# List stashes
|
||||
git stash list
|
||||
|
||||
# Restore
|
||||
git stash pop # apply + remove from stash
|
||||
git stash apply # apply, keep in stash
|
||||
git stash apply stash@{2} # specific stash
|
||||
|
||||
# Inspect
|
||||
git stash show # stat
|
||||
git stash show -p # full diff
|
||||
|
||||
# Drop
|
||||
git stash drop stash@{0}
|
||||
git stash clear # drop all
|
||||
|
||||
# Stash untracked files too
|
||||
git stash -u
|
||||
git stash --include-untracked
|
||||
```
|
||||
|
||||
## Remotes
|
||||
|
||||
```bash
|
||||
# List
|
||||
git remote -v
|
||||
|
||||
# Add
|
||||
git remote add origin https://github.com/user/repo.git
|
||||
git remote add upstream https://github.com/original/repo.git
|
||||
|
||||
# Change URL
|
||||
git remote set-url origin git@github.com:user/repo.git
|
||||
|
||||
# Fetch
|
||||
git fetch # default remote
|
||||
git fetch --all # all remotes
|
||||
git fetch --prune # remove stale remote branches
|
||||
|
||||
# Pull
|
||||
git pull # fetch + merge (or rebase if configured)
|
||||
git pull --rebase # fetch + rebase
|
||||
|
||||
# Push
|
||||
git push
|
||||
git push -u origin main # set upstream
|
||||
git push origin --delete feature-branch # delete remote branch
|
||||
git push --tags # push all tags
|
||||
git push origin v1.0 # push specific tag
|
||||
```
|
||||
|
||||
## Tags
|
||||
|
||||
```bash
|
||||
# List
|
||||
git tag
|
||||
git tag -l "v1.*"
|
||||
|
||||
# Create
|
||||
git tag v1.0 # lightweight
|
||||
git tag -a v1.0 -m "Release 1.0" # annotated (preferred)
|
||||
git tag -a v1.0 abc123 # tag specific commit
|
||||
|
||||
# Delete
|
||||
git tag -d v1.0
|
||||
git push origin --delete v1.0 # delete remote tag
|
||||
|
||||
# Show
|
||||
git show v1.0
|
||||
```
|
||||
|
||||
## .gitignore
|
||||
|
||||
```gitignore
|
||||
# Patterns
|
||||
*.log # all .log files
|
||||
build/ # directory
|
||||
!important.log # exception (don't ignore this one)
|
||||
**/temp # temp in any subdirectory
|
||||
doc/*.txt # doc/notes.txt but not doc/sub/notes.txt
|
||||
```
|
||||
|
||||
```bash
|
||||
# Ignore already-tracked file
|
||||
git rm --cached file.txt # untrack without deleting
|
||||
echo "file.txt" >> .gitignore
|
||||
|
||||
# Debug ignore rules
|
||||
git check-ignore -v path/to/file
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `git pull` without `--rebase` creates merge commits — set `pull.rebase true` globally
|
||||
- `git add .` stages everything including untracked — review with `git status` first
|
||||
- `--amend` rewrites history — never amend commits already pushed to shared branches
|
||||
- `git stash` does not stash untracked files unless `-u` is passed
|
||||
- `-S` (pickaxe) finds where a string was added/removed, not where it appears
|
||||
- `git log -- file` stops at renames — add `--follow` to track across renames
|
||||
- Tags aren't pushed by default — use `--tags` or push individually
|
||||
|
||||
## See Also
|
||||
|
||||
- `git-branching` — branches, merge, rebase, cherry-pick, recovery
|
||||
- [Pro Git book](https://git-scm.com/book/en/v2)
|
||||
- `git help <command>` — built-in manual pages
|
||||
Reference in New Issue
Block a user