Git Specialist
Complete Git CLI mastery -- from daily workflows to deep internals.
Workflow
- Identify the scenario -- what is the user trying to achieve (recovery, history rewrite, workflow optimization, debugging, performance)?
- Choose the safest approach -- prefer non-destructive commands; warn before any destructive operation (
--force, filter-repo, reset --hard)
- Explain with concrete examples -- show exact commands with realistic output
- Offer alternatives -- show both the quick way and the "proper" way when they differ
Safety Rules
- Always warn before history-rewriting commands on shared branches
- Prefer
--force-with-lease over --force
- Suggest creating a backup branch before destructive operations:
git branch backup/before-rewrite
- Recommend
git stash or git worktree before risky operations
Core Topics Quick Reference
| Area |
Key Commands |
Notes |
| Branching |
branch, switch, checkout -b |
Prefer switch/restore over checkout (Git 2.23+) |
| History |
log, reflog, shortlog, log --graph |
reflog is the safety net -- it tracks HEAD movements for ~90 days |
| Rewriting |
rebase -i, commit --amend, filter-repo |
Interactive rebase is the Swiss army knife for local history |
| Merging |
merge, rebase, cherry-pick |
Know when each is appropriate; prefer rebase for linear history on feature branches |
| Recovery |
reflog, fsck, cherry-pick, reset |
Almost nothing is truly lost if it was committed |
| Debugging |
bisect, blame, log -S, log -G |
bisect automates binary search for regressions |
| Stash |
stash push, stash pop, stash apply |
Use -m "message" and --include-untracked |
| Worktrees |
worktree add, worktree list |
Multiple working directories from one repo -- no more stash juggling |
| Patches |
format-patch, am, apply, diff |
Email-based workflow; also useful for selective transfers |
| Performance |
sparse-checkout, shallow clone, partial clone, maintenance |
Essential for large monorepos |
| Hooks |
pre-commit, commit-msg, pre-push |
Automate quality gates; use core.hooksPath for shared hooks |
| Config |
config, alias, .gitattributes |
Three scopes: --system, --global, --local |
| Subprojects |
submodule, subtree |
Subtree is simpler; submodule gives exact version pinning |
| Internals |
cat-file, rev-parse, ls-tree, hash-object |
Understand the object model: blob, tree, commit, tag |
Power-User Tricks
History Navigation & Search
# Find which commit introduced/removed a string (pickaxe)
git log -S "functionName" --oneline
git log -G "regex_pattern" --oneline
# Show commits that touched a specific function (requires language support)
git log -L :functionName:path/to/file.cs
# Compact graph view with author and relative date
git log --graph --oneline --decorate --all --date=relative --format="%C(yellow)%h%Creset %C(cyan)%ad%Creset %s %C(green)(%an)%Creset"
# Find all commits by a coauthor
git log --all --grep="Co-authored-by:.*Name"
# Commits on branch-a but not on main
git log main..branch-a --oneline
# Find the merge commit that brought a commit into main
git log --ancestry-path --merges <commit>..main | tail -1
Interactive Rebase Mastery
# Rebase last N commits interactively
git rebase -i HEAD~5
# Autosquash: combine fixup commits automatically
git commit --fixup=<target-sha>
git rebase -i --autosquash main
# Reword the root commit
git rebase -i --root
# Rebase onto a different base (transplant a branch)
git rebase --onto new-base old-base feature-branch
# Abort a rebase safely
git rebase --abort
Recovery & Undo
# Undo last commit, keep changes staged
git reset --soft HEAD~1
# Undo last commit, keep changes unstaged
git reset --mixed HEAD~1
# Recover a dropped stash
git fsck --unreachable | grep commit | cut -d' ' -f3 | xargs git show --stat
# Recover deleted branch
git reflog | grep "branch-name"
git checkout -b branch-name <sha-from-reflog>
# Undo a rebase (find pre-rebase HEAD in reflog)
git reflog
git reset --hard HEAD@{n}
# Revert a merge commit (undo merge without rewriting history)
git revert -m 1 <merge-commit-sha>
# Restore a single file from another commit
git restore --source=<commit> -- path/to/file
Stash Power Moves
# Stash only specific files (interactive)
git stash push -p -m "partial stash"
# Stash including untracked files
git stash push --include-untracked -m "with untracked"
# Apply stash to a new branch
git stash branch new-branch-name stash@{0}
# Show stash diff without applying
git stash show -p stash@{0}
# Drop all stashes
git stash clear
Worktree Workflow
# Add a worktree for parallel work (no stash needed)
git worktree add ../hotfix-branch hotfix/issue-123
# List all worktrees
git worktree list
# Remove a worktree after merging
git worktree remove ../hotfix-branch
# Bare repo + worktrees pattern (useful for multiple long-lived branches)
git clone --bare repo.git .bare
echo "gitdir: ./.bare" > .git
git worktree add main
git worktree add develop
Bisect (Automated Bug Hunting)
# Manual bisect
git bisect start
git bisect bad # current commit is broken
git bisect good v1.0.0 # this tag was working
# Git checks out a middle commit -- test it, then:
git bisect good # or git bisect bad
# Repeat until the culprit is found
# Fully automated bisect with a test script
git bisect start HEAD v1.0.0
git bisect run dotnet test --filter "TestName"
# Bisect with a custom script
git bisect run bash -c 'grep -q "expected" output.txt'
# Reset after bisect
git bisect reset
Advanced Diff & Blame
# Word-level diff (great for prose/docs)
git diff --word-diff
# Diff between branches, only file names
git diff main..feature --name-only
# Diff of staged changes only
git diff --cached
# Ignore whitespace in diff
git diff -w
# Blame with line range
git blame -L 10,20 path/to/file
# Blame ignoring whitespace and move detection
git blame -w -M -C path/to/file
# Blame ignoring specific revisions (e.g., formatting commits)
echo "<formatting-sha>" > .git-blame-ignore-revs
git config blame.ignoreRevsFile .git-blame-ignore-revs
git blame path/to/file
Aliases (Productivity Boosters)
# Set up useful aliases
git config --global alias.st "status -sb"
git config --global alias.co "checkout"
git config --global alias.sw "switch"
git config --global alias.last "log -1 --stat"
git config --global alias.unstage "restore --staged"
git config --global alias.graph "log --graph --oneline --decorate --all"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.undo "reset --soft HEAD~1"
git config --global alias.wip "!git add -A && git commit -m 'WIP [skip ci]'"
git config --global alias.unwip "reset --soft HEAD~1"
git config --global alias.cleanup "!git branch --merged main | grep -v main | xargs -r git branch -d"
git config --global alias.fresh "!git fetch --prune && git rebase origin/main"
git config --global alias.who "shortlog -sne"
git config --global alias.find "log --all -S"
Large Repo Performance
# Sparse checkout (only check out what you need)
git sparse-checkout init --cone
git sparse-checkout set src/my-service tests/my-service
# Partial clone (skip blobs until needed)
git clone --filter=blob:none <url>
# Shallow clone (limited history)
git clone --depth=1 <url>
git fetch --deepen=10 # get more history later
# Enable filesystem monitor for large repos
git config core.fsmonitor true
git config core.untrackedcache true
# Run background maintenance
git maintenance start
# Commit graph for faster log/merge-base
git commit-graph write --reachable
Patches & Selective Transfer
# Create patch files from commits
git format-patch main..feature -o patches/
# Apply patches
git am patches/*.patch
# Apply a diff as patch (without commit metadata)
git diff main..feature -- src/ | git apply
# Create a bundle (portable repo snapshot)
git bundle create repo.bundle --all
git clone repo.bundle restored-repo
# Archive a specific ref
git archive --format=zip -o release.zip HEAD src/
Hooks & Automation
# Share hooks via core.hooksPath (team-wide)
git config core.hooksPath .githooks
# Pre-commit: lint staged files only
# .githooks/pre-commit
#!/bin/sh
git diff --cached --name-only --diff-filter=d | grep '\.cs$' | xargs dotnet format --include
# Commit-msg: enforce conventional commits
# .githooks/commit-msg
#!/bin/sh
if ! grep -qE "^(feat|fix|build|chore|docs|style|refactor|test)\(.+\): .+" "$1"; then
echo "Commit message must follow: type(scope): description"
exit 1
fi
Rerere (Reuse Recorded Resolution)
# Enable rerere globally (remember conflict resolutions)
git config --global rerere.enabled true
# After resolving a conflict, Git remembers the resolution
# Next time the same conflict occurs, it's resolved automatically
# Review recorded resolutions
git rerere status
git rerere diff
Anti-Patterns
| Anti-Pattern |
Do Instead |
git push --force on shared branches |
git push --force-with-lease or git revert |
git add . blindly |
git add -p or review with git diff first |
| Giant monolithic commits |
Small, atomic commits with clear messages |
| Merging main into feature branch repeatedly |
Rebase feature branch onto main |
| Deleting branches without checking merge status |
git branch -d (safe) not -D (force) |
Using git checkout for everything |
git switch (branches) + git restore (files) |
| Storing secrets in Git history |
Use .gitignore, git-crypt, or environment variables |
git reset --hard without backup |
Create a backup branch first, or use reflog |
Ignoring .gitattributes |
Set text=auto, define merge drivers for lock files |
| Manual conflict resolution every time |
Enable rerere for repeated resolutions |
Troubleshooting Checklist
| Symptom |
Likely Cause |
Fix |
| "detached HEAD" |
Checked out a commit/tag directly |
git switch - or git switch branch-name |
| Merge conflicts on every rebase |
Diverged significantly from base |
Rebase in smaller steps or use rerere |
| "refusing to merge unrelated histories" |
Repos with no common ancestor |
--allow-unrelated-histories if intentional |
| Push rejected (non-fast-forward) |
Remote has commits you don't have |
git pull --rebase then push |
.gitignore not working |
File already tracked |
git rm --cached <file> then commit |
| Huge repo, slow operations |
Too many files/large blobs |
sparse-checkout, partial clone, git-lfs |
| Lost commits after rebase |
History rewritten |
git reflog to find pre-rebase SHA |
| Wrong author on commits |
Misconfigured user |
git commit --amend --author="Name <email>" or rebase -i with exec |
| Binary files causing merge conflicts |
No merge driver defined |
Set binary merge strategy in .gitattributes |
| Submodule not updating |
Submodule pointer stale |
git submodule update --init --recursive |
Advanced Reference
For in-depth coverage of specific topics, load references/advanced-topics.md. Topics include:
- Git internals (object model, packfiles, refs)
git filter-repo for history surgery
- Signing commits and tags with GPG/SSH
- Git LFS setup and migration
- Monorepo strategies (sparse-checkout, worktrees, CODEOWNERS)
- Advanced merge strategies and custom merge drivers
- Git notes for metadata without changing history
- Shallow clone workflows for CI/CD
- Multi-remote workflows (fork + upstream)
1---2name: git-specialist3description: Deep Git command-line expertise covering the full spectrum from everyday workflows to advanced power-user techniques. Use when the user needs help with: Git commands, branching strategies, rebasing, cherry-picking, interactive rebase, reflog recovery, bisect debugging, worktrees, subtrees, submodules, patch workflows, advanced log/diff/blame, stash tricks, hooks, aliases, large-repo performance, conflict resolution, history rewriting, Git internals, .gitattributes/.gitignore patterns, sparse checkout, or any Git CLI question. Triggers on: git, rebase, cherry-pick, merge conflict, reflog, bisect, worktree, stash, reset, revert, amend, squash, fixup, force push, git log, git diff, git blame, git hook, .gitignore, git alias, git subtree, git submodule, sparse-checkout, git filter-repo, git rerere, git notes, git bundle, git archive.4---5
6# Git Specialist
7
8Complete Git CLI mastery -- from daily workflows to deep internals.
9
10## Workflow
11
121. **Identify the scenario** -- what is the user trying to achieve (recovery, history rewrite, workflow optimization, debugging, performance)?
132. **Choose the safest approach** -- prefer non-destructive commands; warn before any destructive operation (`--force`, `filter-repo`, `reset --hard`)
143. **Explain with concrete examples** -- show exact commands with realistic output
154. **Offer alternatives** -- show both the quick way and the "proper" way when they differ
16
17## Safety Rules
18
19- Always warn before history-rewriting commands on shared branches
20- Prefer `--force-with-lease` over `--force`
21- Suggest creating a backup branch before destructive operations: `git branch backup/before-rewrite`
22- Recommend `git stash` or `git worktree` before risky operations
23
24## Core Topics Quick Reference
25
26| Area | Key Commands | Notes |
27|------|-------------|-------|
28| **Branching** | `branch`, `switch`, `checkout -b` | Prefer `switch`/`restore` over `checkout` (Git 2.23+) |
29| **History** | `log`, `reflog`, `shortlog`, `log --graph` | `reflog` is the safety net -- it tracks HEAD movements for ~90 days |
30| **Rewriting** | `rebase -i`, `commit --amend`, `filter-repo` | Interactive rebase is the Swiss army knife for local history |
31| **Merging** | `merge`, `rebase`, `cherry-pick` | Know when each is appropriate; prefer rebase for linear history on feature branches |
32| **Recovery** | `reflog`, `fsck`, `cherry-pick`, `reset` | Almost nothing is truly lost if it was committed |
33| **Debugging** | `bisect`, `blame`, `log -S`, `log -G` | `bisect` automates binary search for regressions |
34| **Stash** | `stash push`, `stash pop`, `stash apply` | Use `-m "message"` and `--include-untracked` |
35| **Worktrees** | `worktree add`, `worktree list` | Multiple working directories from one repo -- no more stash juggling |
36| **Patches** | `format-patch`, `am`, `apply`, `diff` | Email-based workflow; also useful for selective transfers |
37| **Performance** | `sparse-checkout`, `shallow clone`, `partial clone`, `maintenance` | Essential for large monorepos |
38| **Hooks** | `pre-commit`, `commit-msg`, `pre-push` | Automate quality gates; use `core.hooksPath` for shared hooks |
39| **Config** | `config`, `alias`, `.gitattributes` | Three scopes: `--system`, `--global`, `--local` |
40| **Subprojects** | `submodule`, `subtree` | Subtree is simpler; submodule gives exact version pinning |
41| **Internals** | `cat-file`, `rev-parse`, `ls-tree`, `hash-object` | Understand the object model: blob, tree, commit, tag |
42
43## Power-User Tricks
44
45### History Navigation & Search
46
47```bash
48# Find which commit introduced/removed a string (pickaxe)
49git log -S "functionName" --oneline
50git log -G "regex_pattern" --oneline
51
52# Show commits that touched a specific function (requires language support)
53git log -L :functionName:path/to/file.cs
54
55# Compact graph view with author and relative date
56git log --graph --oneline --decorate --all --date=relative --format="%C(yellow)%h%Creset %C(cyan)%ad%Creset %s %C(green)(%an)%Creset"
57
58# Find all commits by a coauthor
59git log --all --grep="Co-authored-by:.*Name"
60
61# Commits on branch-a but not on main
62git log main..branch-a --oneline
63
64# Find the merge commit that brought a commit into main
65git log --ancestry-path --merges <commit>..main | tail -1
66```
67
68### Interactive Rebase Mastery
69
70```bash
71# Rebase last N commits interactively
72git rebase -i HEAD~5
73
74# Autosquash: combine fixup commits automatically
75git commit --fixup=<target-sha>
76git rebase -i --autosquash main
77
78# Reword the root commit
79git rebase -i --root
80
81# Rebase onto a different base (transplant a branch)
82git rebase --onto new-base old-base feature-branch
83
84# Abort a rebase safely
85git rebase --abort
86```
87
88### Recovery & Undo
89
90```bash
91# Undo last commit, keep changes staged
92git reset --soft HEAD~1
93
94# Undo last commit, keep changes unstaged
95git reset --mixed HEAD~1
96
97# Recover a dropped stash
98git fsck --unreachable | grep commit | cut -d' ' -f3 | xargs git show --stat
99
100# Recover deleted branch
101git reflog | grep "branch-name"
102git checkout -b branch-name <sha-from-reflog>
103
104# Undo a rebase (find pre-rebase HEAD in reflog)
105git reflog
106git reset --hard HEAD@{n}
107
108# Revert a merge commit (undo merge without rewriting history)
109git revert -m 1 <merge-commit-sha>
110
111# Restore a single file from another commit
112git restore --source=<commit> -- path/to/file
113```
114
115### Stash Power Moves
116
117```bash
118# Stash only specific files (interactive)
119git stash push -p -m "partial stash"
120
121# Stash including untracked files
122git stash push --include-untracked -m "with untracked"
123
124# Apply stash to a new branch
125git stash branch new-branch-name stash@{0}
126
127# Show stash diff without applying
128git stash show -p stash@{0}
129
130# Drop all stashes
131git stash clear
132```
133
134### Worktree Workflow
135
136```bash
137# Add a worktree for parallel work (no stash needed)
138git worktree add ../hotfix-branch hotfix/issue-123
139
140# List all worktrees
141git worktree list
142
143# Remove a worktree after merging
144git worktree remove ../hotfix-branch
145
146# Bare repo + worktrees pattern (useful for multiple long-lived branches)
147git clone --bare repo.git .bare
148echo "gitdir: ./.bare" > .git
149git worktree add main
150git worktree add develop
151```
152
153### Bisect (Automated Bug Hunting)
154
155```bash
156# Manual bisect
157git bisect start
158git bisect bad # current commit is broken
159git bisect good v1.0.0 # this tag was working
160# Git checks out a middle commit -- test it, then:
161git bisect good # or git bisect bad
162# Repeat until the culprit is found
163
164# Fully automated bisect with a test script
165git bisect start HEAD v1.0.0
166git bisect run dotnet test --filter "TestName"
167
168# Bisect with a custom script
169git bisect run bash -c 'grep -q "expected" output.txt'
170
171# Reset after bisect
172git bisect reset
173```
174
175### Advanced Diff & Blame
176
177```bash
178# Word-level diff (great for prose/docs)
179git diff --word-diff
180
181# Diff between branches, only file names
182git diff main..feature --name-only
183
184# Diff of staged changes only
185git diff --cached
186
187# Ignore whitespace in diff
188git diff -w
189
190# Blame with line range
191git blame -L 10,20 path/to/file
192
193# Blame ignoring whitespace and move detection
194git blame -w -M -C path/to/file
195
196# Blame ignoring specific revisions (e.g., formatting commits)
197echo "<formatting-sha>" > .git-blame-ignore-revs
198git config blame.ignoreRevsFile .git-blame-ignore-revs
199git blame path/to/file
200```
201
202### Aliases (Productivity Boosters)
203
204```bash
205# Set up useful aliases
206git config --global alias.st "status -sb"
207git config --global alias.co "checkout"
208git config --global alias.sw "switch"
209git config --global alias.last "log -1 --stat"
210git config --global alias.unstage "restore --staged"
211git config --global alias.graph "log --graph --oneline --decorate --all"
212git config --global alias.amend "commit --amend --no-edit"
213git config --global alias.undo "reset --soft HEAD~1"
214git config --global alias.wip "!git add -A && git commit -m 'WIP [skip ci]'"
215git config --global alias.unwip "reset --soft HEAD~1"
216git config --global alias.cleanup "!git branch --merged main | grep -v main | xargs -r git branch -d"
217git config --global alias.fresh "!git fetch --prune && git rebase origin/main"
218git config --global alias.who "shortlog -sne"
219git config --global alias.find "log --all -S"
220```
221
222### Large Repo Performance
223
224```bash
225# Sparse checkout (only check out what you need)
226git sparse-checkout init --cone
227git sparse-checkout set src/my-service tests/my-service
228
229# Partial clone (skip blobs until needed)
230git clone --filter=blob:none <url>
231
232# Shallow clone (limited history)
233git clone --depth=1 <url>
234git fetch --deepen=10 # get more history later
235
236# Enable filesystem monitor for large repos
237git config core.fsmonitor true
238git config core.untrackedcache true
239
240# Run background maintenance
241git maintenance start
242
243# Commit graph for faster log/merge-base
244git commit-graph write --reachable
245```
246
247### Patches & Selective Transfer
248
249```bash
250# Create patch files from commits
251git format-patch main..feature -o patches/
252
253# Apply patches
254git am patches/*.patch
255
256# Apply a diff as patch (without commit metadata)
257git diff main..feature -- src/ | git apply
258
259# Create a bundle (portable repo snapshot)
260git bundle create repo.bundle --all
261git clone repo.bundle restored-repo
262
263# Archive a specific ref
264git archive --format=zip -o release.zip HEAD src/
265```
266
267### Hooks & Automation
268
269```bash
270# Share hooks via core.hooksPath (team-wide)
271git config core.hooksPath .githooks
272
273# Pre-commit: lint staged files only
274# .githooks/pre-commit
275#!/bin/sh
276git diff --cached --name-only --diff-filter=d | grep '\.cs$' | xargs dotnet format --include
277
278# Commit-msg: enforce conventional commits
279# .githooks/commit-msg
280#!/bin/sh
281if ! grep -qE "^(feat|fix|build|chore|docs|style|refactor|test)\(.+\): .+" "$1"; then
282 echo "Commit message must follow: type(scope): description"
283 exit 1
284fi
285```
286
287### Rerere (Reuse Recorded Resolution)
288
289```bash
290# Enable rerere globally (remember conflict resolutions)
291git config --global rerere.enabled true
292
293# After resolving a conflict, Git remembers the resolution
294# Next time the same conflict occurs, it's resolved automatically
295
296# Review recorded resolutions
297git rerere status
298git rerere diff
299```
300
301## Anti-Patterns
302
303| Anti-Pattern | Do Instead |
304|-------------|------------|
305| `git push --force` on shared branches | `git push --force-with-lease` or `git revert` |
306| `git add .` blindly | `git add -p` or review with `git diff` first |
307| Giant monolithic commits | Small, atomic commits with clear messages |
308| Merging main into feature branch repeatedly | Rebase feature branch onto main |
309| Deleting branches without checking merge status | `git branch -d` (safe) not `-D` (force) |
310| Using `git checkout` for everything | `git switch` (branches) + `git restore` (files) |
311| Storing secrets in Git history | Use `.gitignore`, `git-crypt`, or environment variables |
312| `git reset --hard` without backup | Create a backup branch first, or use `reflog` |
313| Ignoring `.gitattributes` | Set `text=auto`, define merge drivers for lock files |
314| Manual conflict resolution every time | Enable `rerere` for repeated resolutions |
315
316## Troubleshooting Checklist
317
318| Symptom | Likely Cause | Fix |
319|---------|-------------|-----|
320| "detached HEAD" | Checked out a commit/tag directly | `git switch -` or `git switch branch-name` |
321| Merge conflicts on every rebase | Diverged significantly from base | Rebase in smaller steps or use `rerere` |
322| "refusing to merge unrelated histories" | Repos with no common ancestor | `--allow-unrelated-histories` if intentional |
323| Push rejected (non-fast-forward) | Remote has commits you don't have | `git pull --rebase` then push |
324| `.gitignore` not working | File already tracked | `git rm --cached <file>` then commit |
325| Huge repo, slow operations | Too many files/large blobs | `sparse-checkout`, `partial clone`, `git-lfs` |
326| Lost commits after rebase | History rewritten | `git reflog` to find pre-rebase SHA |
327| Wrong author on commits | Misconfigured user | `git commit --amend --author="Name <email>"` or `rebase -i` with `exec` |
328| Binary files causing merge conflicts | No merge driver defined | Set binary merge strategy in `.gitattributes` |
329| Submodule not updating | Submodule pointer stale | `git submodule update --init --recursive` |
330
331## Advanced Reference
332
333For in-depth coverage of specific topics, load [references/advanced-topics.md](references/advanced-topics.md). Topics include:
334
335- Git internals (object model, packfiles, refs)
336- `git filter-repo` for history surgery
337- Signing commits and tags with GPG/SSH
338- Git LFS setup and migration
339- Monorepo strategies (sparse-checkout, worktrees, CODEOWNERS)
340- Advanced merge strategies and custom merge drivers
341- Git notes for metadata without changing history
342- Shallow clone workflows for CI/CD
343- Multi-remote workflows (fork + upstream)