Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions chapters/playbook/diffing.md
Original file line number Diff line number Diff line change
@@ -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.
69 changes: 69 additions & 0 deletions chapters/playbook/history.md
Original file line number Diff line number Diff line change
@@ -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.
65 changes: 65 additions & 0 deletions chapters/playbook/hooks.md
Original file line number Diff line number Diff line change
@@ -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.
36 changes: 31 additions & 5 deletions chapters/playbook/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
57 changes: 57 additions & 0 deletions chapters/playbook/remote-management.md
Original file line number Diff line number Diff line change
@@ -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 <url>
```

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:<user>/<repo>.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.
63 changes: 63 additions & 0 deletions chapters/playbook/selectors.md
Original file line number Diff line number Diff line change
@@ -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.
Loading
Loading