Git Reference
Git version control patterns. From daily basics to repository surgery.
Topics
| Topic | Description |
|---|---|
Status, diff, log, add, commit |
|
Create, switch, merge, rebase, conflicts |
|
Blame, bisect, log search, show — inspecting the past |
|
Reset, revert, amend, interactive rebase, cherry-pick, reflog |
|
Save, retrieve, inspect work-in-progress |
|
Push, pull, fetch, multi-remote, SSH |
|
Lightweight, annotated, versioning, release tagging |
|
Multiple working directories, parallel work |
|
Repository surgery — remove secrets, extract projects |
|
Aliases, hooks, .gitignore, settings |
Inspecting State
git status
git diff
git diff --staged
git log --oneline -10
git log --graph --all --oneline
git blame -L 40,60 src/domus_api/main.py
git show abc1234
Staging & Committing
git add -A
git add -p
This walks through each change and asks y/n/s/e — stage this hunk? Split it? Edit it? The senior-engineer move: never git add -A blindly. Use -p to review what you’re committing.
git commit -m "feat: add association graph endpoints"
git commit -m "$(cat <<'EOF'
feat: association engine Phase 1 — core data structure
AssociationGraph class with bidirectional dicts.
22 tests, all passing.
EOF
)"
git add forgotten-file.py
git commit --amend
| Never amend a commit that’s already been pushed. It rewrites history. Use a new commit instead. |
Branches
git branch -a
git checkout -b feature/association-engine
git checkout main
git branch -d feature/old-branch
git branch -D feature/abandoned-experiment
Merging & Rebasing
git merge feature/association-engine
git rebase main
git cherry-pick abc1234
Undoing Things
git reset --soft HEAD~1
git reset HEAD~1
git reset --hard HEAD~1
git reset --hard origin/main
--hard destroys uncommitted work. Check git stash first.
|
git reflog
If you accidentally reset --hard, the reflog has the commit hash. You can git reset --hard <hash> to recover.
Stash — Save Work Without Committing
git stash
git stash push -m "WIP: association engine CLI"
git stash list
git stash apply
git stash pop
Remotes
git remote -v
git push -u origin main
git fetch --all --prune
git remote set-url origin git@github.com:EvanusModestus/association-engine.git
This is the fix when gh repo create defaults to HTTPS but your SSH agent is loaded.
Tags
git tag -a v0.1.0 -m "Association Engine — core data structure"
git push --follow-tags
git tag -l
Worktrees — Multiple Working Directories
git worktree add ../association-engine-fix hotfix-branch
git worktree list
git worktree remove ../association-engine-fix
GitHub CLI (gh)
gh repo create association-engine --private --source . --remote origin --push
git remote set-url origin git@github.com:EvanusModestus/association-engine.git
master, GitHub expects maingit branch -m master main
git push -u origin main
cd ~/atelier/_projects/personal/my-project
uv init .
git add -A && git commit -m "feat: initial commit"
gh repo create my-project --private --source . --remote origin --push
git remote set-url origin git@github.com:EvanusModestus/my-project.git
git branch -m master main
git push -u origin main
Configuration & Debugging
git config --list --show-origin
git check-ignore -v path/to/file
git filter-repo --analyze
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sort -k3 -rn | head -20
GitHub CLI (gh) — Automation & API
gh is not just for creating repos. It’s a full GitHub API client with jq-pipeable JSON output.
Repository Management
gh repo create association-engine --private --source . --remote origin --push
git remote set-url origin git@github.com:EvanusModestus/association-engine.git
git branch -m master main
git push -u origin main
gh repo list --limit 20 --json name,pushedAt | jq -r '.[] | "\(.pushedAt)\t\(.name)"' | sort -r
gh repo clone EvanusModestus/domus-api
gh repo view EvanusModestus/domus-api --json name,description,defaultBranchRef | jq
Pull Requests
gh pr create --title "feat: association graph endpoints" --body "Adds /associations API"
gh pr list
gh pr list --json number,title,state,author | jq '[.[] | {number, title, author: .author.login}]'
gh pr view 42
gh pr checks 42
gh pr merge 42 --squash --delete-branch
Issues
gh issue create --title "Add YAML persistence to association engine" --label "enhancement"
gh issue list
gh issue list --json number,title,labels --limit 50 | jq '[.[] | {number, title, labels: [.labels[].name]}]'
GitHub API — Raw Power
gh api gives you direct access to any GitHub REST or GraphQL endpoint. This is where it gets powerful.
gh api repos/EvanusModestus/domus-api | jq '{name, stars: .stargazers_count, size: .size, language}'
gh api user/repos --paginate | jq -r '.[] | "\(.size)\t\(.language)\t\(.name)"' | sort -rn | head -20
gh api repos/EvanusModestus/domus-api/commits --jq '.[].commit.message' | head -10
gh api repos/EvanusModestus/domus-api/pulls/1/comments | jq '[.[] | {user: .user.login, body: .body[:80]}]'
gh api repos/EvanusModestus/domus-captures/issues | jq '[.[] | {number, title, labels: [.labels[].name]}]'
Cross-Repo Automation
gh repo list --limit 50 --json name,pushedAt,defaultBranchRef | jq -r '.[] | "\(.pushedAt[:10])\t\(.name)"' | sort -r
gh repo list --language python --json name,language | jq -r '.[] | "\(.language)\t\(.name)"'
gh repo list --limit 100 --json nameWithOwner | jq -r '.[].nameWithOwner' | xargs -I{} gh repo clone {}
gh release create v0.1.0 --generate-notes --title "Association Engine v0.1.0"
gh + jq Patterns
gh repo list --limit 100 --json language | jq -r '.[].language' | sort | uniq -c | sort -rn
gh repo list --limit 50 --json name,diskUsage | jq -r '.[] | "\(.diskUsage)\t\(.name)"' | sort -rn | head -10
gh repo list --limit 100 --json name | jq -r '.[].name' > /tmp/my-repos.txt
Multi-Repo Operations
git -C ~/atelier/_bibliotheca/domus-captures push &
git -C ~/atelier/_projects/personal/domus-api push &
git -C ~/atelier/_projects/personal/association-engine push &
wait
status variable)for d in ~/atelier/_bibliotheca/domus-*/ ~/atelier/_projects/personal/*/; do
[[ -d "$d/.git" ]] || continue
changed=$(git -C "$d" status --porcelain | wc -l)
ahead=$(git -C "$d" rev-list --count @{upstream}..HEAD 2>/dev/null || echo "?")
printf "%-35s %s files changed, %s unpushed\n" "$(basename "$d")" "$changed" "$ahead"
done