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:
user
2026-02-21 20:48:58 +01:00
parent 953883c43a
commit 60f9c85f3f
3 changed files with 530 additions and 1 deletions

View File

@@ -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
View 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
View 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