From d94dd9ef2496d0404fe18e296f00e3cb8bec0765 Mon Sep 17 00:00:00 2001 From: Branimir Georgiev Date: Sat, 25 Apr 2026 18:10:55 +0300 Subject: [PATCH] feat: add 6 new playbook recipe pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add recipes for subtrees, hooks, remote management, diffing, history, and selectors — covering all Git commands taught in the tutorial that were missing from the playbook. Co-Authored-By: Claude Opus 4.6 (1M context) --- chapters/playbook/diffing.md | 67 +++++++++++++++++++++++++ chapters/playbook/history.md | 69 ++++++++++++++++++++++++++ chapters/playbook/hooks.md | 65 ++++++++++++++++++++++++ chapters/playbook/index.md | 36 ++++++++++++-- chapters/playbook/remote-management.md | 57 +++++++++++++++++++++ chapters/playbook/selectors.md | 63 +++++++++++++++++++++++ chapters/playbook/subtrees.md | 44 ++++++++++++++++ 7 files changed, 396 insertions(+), 5 deletions(-) create mode 100644 chapters/playbook/diffing.md create mode 100644 chapters/playbook/history.md create mode 100644 chapters/playbook/hooks.md create mode 100644 chapters/playbook/remote-management.md create mode 100644 chapters/playbook/selectors.md create mode 100644 chapters/playbook/subtrees.md diff --git a/chapters/playbook/diffing.md b/chapters/playbook/diffing.md new file mode 100644 index 0000000..01938bb --- /dev/null +++ b/chapters/playbook/diffing.md @@ -0,0 +1,67 @@ +--- +title: "Diffing" +description: "Git recipes for comparing unstaged changes, staged changes, branches, commits, and specific files." +section: "playbook/diffing" +order: 85 +--- + +## Diffing + +### Show unstaged changes + +```text +$ git diff +``` + +Compares working tree against the index (staged snapshot). + +### Show staged changes + +```text +$ git diff --staged +``` + +Compares the index against the last commit — shows what will go into +the next commit. + +### Compare two branches + +```text +$ git diff main feature/name +``` + +Shows all differences between the tips of both branches. + +### Compare two commits + +```text +$ git diff abc1234 def5678 +``` + +### Show changes introduced by a single commit + +```text +$ git diff HEAD~1 HEAD +``` + +Or use `git show` for the same result with commit metadata: + +```text +$ git show HEAD +``` + +### Diff a specific file + +```text +$ git diff -- path/to/file +$ git diff --staged -- path/to/file +``` + +### Diff with statistics only + +```text +$ git diff --stat main feature/name +``` + +Shows a summary of changed files and line counts without the full +patch. diff --git a/chapters/playbook/history.md b/chapters/playbook/history.md new file mode 100644 index 0000000..0ed3ff7 --- /dev/null +++ b/chapters/playbook/history.md @@ -0,0 +1,69 @@ +--- +title: "History" +description: "Git recipes for viewing, formatting, and filtering commit history — log output, author filters, date ranges, and path-based searches." +section: "playbook/history" +order: 86 +--- + +## History + +### Compact one-line log + +```text +$ git log --oneline +``` + +### Graph view with branches + +```text +$ git log --oneline --graph --all +``` + +Shows the full branch topology in ASCII art. + +### Filter by author + +```text +$ git log --author="Branko" --oneline +``` + +Matches against the author name or email. Supports regex. + +### Filter by date range + +```text +$ git log --after="2025-01-01" --before="2025-06-30" --oneline +``` + +### Filter by file path + +```text +$ git log -- path/to/file --oneline +``` + +Shows only commits that modified the specified file. + +### Custom format + +```text +$ git log --format="%h %an %s" -10 +``` + +Common placeholders: `%h` (short hash), `%an` (author name), +`%s` (subject), `%ar` (relative date), `%d` (refs). + +### Show changes in each commit + +```text +$ git log -p -3 +``` + +Combines log output with the full diff for the last 3 commits. + +### Count commits per author + +```text +$ git shortlog -sn +``` + +Useful for understanding contribution distribution. diff --git a/chapters/playbook/hooks.md b/chapters/playbook/hooks.md new file mode 100644 index 0000000..a74774a --- /dev/null +++ b/chapters/playbook/hooks.md @@ -0,0 +1,65 @@ +--- +title: "Hooks" +description: "Git recipes for creating pre-commit and commit-msg hooks, sharing hooks across a team, and bypassing hooks when needed." +section: "playbook/hooks" +order: 83 +--- + +## Hooks + +### Create a pre-commit hook + +```text +$ cat > .git/hooks/pre-commit << 'EOF' +#!/bin/sh +# Reject commits that contain TODO +if git diff --cached --quiet -S "TODO"; then + exit 0 +fi +echo "Error: commit contains TODO" +exit 1 +EOF +$ chmod +x .git/hooks/pre-commit +``` + +The hook runs before every commit. A non-zero exit code aborts the +commit. + +### Create a commit-msg hook + +```text +$ cat > .git/hooks/commit-msg << 'EOF' +#!/bin/sh +# Enforce minimum message length +if [ $(wc -c < "$1") -lt 10 ]; then + echo "Error: commit message too short" + exit 1 +fi +EOF +$ chmod +x .git/hooks/commit-msg +``` + +Receives the commit message file as `$1`. Useful for enforcing +message conventions. + +### Share hooks with the team + +```text +$ mkdir .githooks +$ cp .git/hooks/pre-commit .githooks/ +$ git config core.hooksPath .githooks +$ git add .githooks/ +$ git commit -m "Add shared hooks" +``` + +Everyone who clones the repo runs `git config core.hooksPath .githooks` +to activate the shared hooks. + +### Bypass a hook + +```text +$ git commit --no-verify -m "WIP: skip hooks" +$ git push --no-verify +``` + +Use sparingly — hooks exist for a reason. diff --git a/chapters/playbook/index.md b/chapters/playbook/index.md index 6a06504..5a4847d 100644 --- a/chapters/playbook/index.md +++ b/chapters/playbook/index.md @@ -11,21 +11,47 @@ This chapter is a quick-reference collection of recipes for common Git tasks. Each recipe shows the problem, the commands to solve it, and what to watch out for. -For command syntax, see [Appendix](../08-appendix.md). For definitions, -see [Glossary](../09-glossary.md). +For command syntax, see the [official Git reference](https://git-scm.com/docs). +For definitions, see [Glossary](../09-glossary.md). -## Recipes +## Everyday | Recipe | What you'll find | |--------|-----------------| | [Undoing Changes](undoing-changes.md) | Discard, unstage, reset, revert, and recover lost commits | +| [Diffing](diffing.md) | Unstaged, staged, between branches, commits, and files | +| [History](history.md) | Log formatting, filtering by author, date, and path | +| [Stashing](stashing.md) | Save and restore work in progress | + +## Branching and Merging + +| Recipe | What you'll find | +|--------|-----------------| | [Branching](branching.md) | Create, delete, rename, and inspect branches | | [Merging](merging.md) | Fast-forward, no-ff, squash, conflict resolution | | [Rebasing](rebasing.md) | Linearize history and squash commits interactively | -| [Remote Operations](remote-operations.md) | Push, pull, force push safely, sync forks | | [Cherry-Picking](cherry-picking.md) | Apply individual commits across branches | -| [Stashing](stashing.md) | Save and restore work in progress | + +## Remote + +| Recipe | What you'll find | +|--------|-----------------| +| [Remote Operations](remote-operations.md) | Push, pull, force push safely, sync forks | +| [Remote Management](remote-management.md) | Add, rename, remove remotes, switch URL, SSH setup | + +## Project Structure + +| Recipe | What you'll find | +|--------|-----------------| | [Tagging](tagging.md) | Create, push, and delete annotated tags | | [Submodules](submodules.md) | Add, clone, update, and remove submodules | +| [Subtrees](subtrees.md) | Add, pull, push, and remove subtrees | + +## Advanced + +| Recipe | What you'll find | +|--------|-----------------| +| [Selectors](selectors.md) | Tilde, caret, double-dot, triple-dot, reflog refs | +| [Hooks](hooks.md) | Pre-commit, commit-msg, sharing hooks, bypassing | | [Debugging](debugging.md) | Bisect, blame, and search commit history | | [Configuration](configuration.md) | Identity, defaults, aliases, and diagnostics | diff --git a/chapters/playbook/remote-management.md b/chapters/playbook/remote-management.md new file mode 100644 index 0000000..0a8ef46 --- /dev/null +++ b/chapters/playbook/remote-management.md @@ -0,0 +1,57 @@ +--- +title: "Remote Management" +description: "Git recipes for adding, renaming, and removing remotes, switching remote URLs, and setting up SSH authentication." +section: "playbook/remote-management" +order: 84 +--- + +## Remote Management + +### List remotes + +```text +$ git remote -v +``` + +Shows all configured remotes with their fetch and push URLs. + +### Add a remote + +```text +$ git remote add upstream +``` + +Common when working with forks — `origin` is your fork, `upstream` +is the original repository. + +### Rename a remote + +```text +$ git remote rename origin old-origin +``` + +### Remove a remote + +```text +$ git remote remove upstream +``` + +Also removes all remote-tracking branches for that remote. + +### Switch a remote URL (HTTPS to SSH) + +```text +$ git remote set-url origin git@github.com:/.git +``` + +### Set up SSH authentication + +```text +$ ssh-keygen -t ed25519 -C "you@example.com" +$ eval "$(ssh-agent -s)" +$ ssh-add ~/.ssh/id_ed25519 +$ ssh -T git@github.com # verify connection +``` + +Add the public key (`~/.ssh/id_ed25519.pub`) to your GitHub account +under Settings > SSH Keys. diff --git a/chapters/playbook/selectors.md b/chapters/playbook/selectors.md new file mode 100644 index 0000000..56a8d02 --- /dev/null +++ b/chapters/playbook/selectors.md @@ -0,0 +1,63 @@ +--- +title: "Selectors" +description: "Git recipes for navigating history with tilde, caret, double-dot, triple-dot, and reflog selectors." +section: "playbook/selectors" +order: 87 +--- + +## Selectors + +### Navigate to a parent commit (tilde) + +```text +$ git show HEAD~1 # parent +$ git show HEAD~3 # great-grandparent +``` + +Tilde follows the first-parent chain. `HEAD~3` means "go back 3 +commits along the first parent." + +### Select a specific parent (caret) + +```text +$ git show HEAD^1 # first parent +$ git show HEAD^2 # second parent (merge commits) +``` + +Caret selects which parent of a merge commit to follow. Only +meaningful on merge commits — `^1` and `^2` differ. + +### Combine tilde and caret + +```text +$ git show HEAD~1^2 # second parent of the previous commit +``` + +### Commits on one branch but not another (double-dot) + +```text +$ git log main..feature --oneline +``` + +Shows commits reachable from `feature` that are not reachable from +`main` — what would be merged. + +### Symmetric difference (triple-dot) + +```text +$ git log --left-right main...feature --oneline +``` + +Shows commits on either branch but not both. The `--left-right` +flag marks each commit with `<` (left) or `>` (right). + +### Reflog selectors + +```text +$ git show HEAD@{1} # previous position of HEAD +$ git show main@{yesterday} # where main was yesterday +$ git show HEAD@{2.hours.ago} # HEAD two hours ago +``` + +Reflog entries expire after 90 days (reachable) or 30 days +(unreachable) by default. diff --git a/chapters/playbook/subtrees.md b/chapters/playbook/subtrees.md new file mode 100644 index 0000000..ba8b23c --- /dev/null +++ b/chapters/playbook/subtrees.md @@ -0,0 +1,44 @@ +--- +title: "Subtrees" +description: "Git recipes for adding, pulling, pushing, and removing subtrees — embedding external repositories without submodules." +section: "playbook/subtrees" +order: 82 +--- + +## Subtrees + +### Add a subtree + +```text +$ git subtree add --prefix=libs/utils main --squash +$ git commit -m "Add utils subtree" +``` + +The `--squash` flag merges all upstream history into a single commit. + +### Pull updates from the upstream repository + +```text +$ git subtree pull --prefix=libs/utils main --squash +``` + +Fetches upstream changes and merges them into the subtree directory. + +### Push changes back to the upstream repository + +```text +$ git subtree push --prefix=libs/utils main +``` + +Extracts commits that touch the subtree directory and pushes them +upstream. + +### Remove a subtree + +```text +$ git rm -r libs/utils +$ git commit -m "Remove utils subtree" +``` + +Unlike submodules, there is no metadata to clean up — just remove +the directory.