From 1231553c2b469f0e74b8abc79dbdd98b04fcfabd Mon Sep 17 00:00:00 2001 From: zlei9 Date: Sun, 29 Mar 2026 09:43:31 +0800 Subject: [PATCH] Initial commit with translated description --- SKILL.md | 533 +++++++++++++++++++++++++++++++++++++++++++++++++++++ _meta.json | 6 + 2 files changed, 539 insertions(+) create mode 100644 SKILL.md create mode 100644 _meta.json diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..30d7639 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,533 @@ +--- +name: git-workflows +description: "超越add/commit/push的高级git操作。在rebase、bisect调试bug、使用worktrees进行并行开发、使用reflog恢复、管理子树/子模块、解决合并冲突、跨分支cherry-pick或使用monorepos时使用。" +metadata: {"clawdbot":{"emoji":"🌿","requires":{"bins":["git"]},"os":["linux","darwin","win32"]}} +--- + +# Git Workflows + +Advanced git operations for real-world development. Covers interactive rebase, bisect, worktree, reflog recovery, subtrees, submodules, sparse checkout, conflict resolution, and monorepo patterns. + +## When to Use + +- Cleaning up commit history before merging (interactive rebase) +- Finding which commit introduced a bug (bisect) +- Working on multiple branches simultaneously (worktree) +- Recovering lost commits or undoing mistakes (reflog) +- Managing shared code across repos (subtree/submodule) +- Resolving complex merge conflicts +- Cherry-picking commits across branches or forks +- Working with large monorepos (sparse checkout) + +## Interactive Rebase + +### Squash, reorder, edit commits + +```bash +# Rebase last 5 commits interactively +git rebase -i HEAD~5 + +# Rebase onto main (all commits since diverging) +git rebase -i main +``` + +The editor opens with a pick list: + +``` +pick a1b2c3d Add user model +pick e4f5g6h Fix typo in user model +pick i7j8k9l Add user controller +pick m0n1o2p Add user routes +pick q3r4s5t Fix import in controller +``` + +Commands available: +``` +pick = use commit as-is +reword = use commit but edit the message +edit = stop after this commit to amend it +squash = merge into previous commit (keep both messages) +fixup = merge into previous commit (discard this message) +drop = remove the commit entirely +``` + +### Common patterns + +```bash +# Squash fix commits into their parent +# Change "pick" to "fixup" for the fix commits: +pick a1b2c3d Add user model +fixup e4f5g6h Fix typo in user model +pick i7j8k9l Add user controller +fixup q3r4s5t Fix import in controller +pick m0n1o2p Add user routes + +# Reorder commits (just move lines) +pick i7j8k9l Add user controller +pick m0n1o2p Add user routes +pick a1b2c3d Add user model + +# Split a commit into two +# Mark as "edit", then when it stops: +git reset HEAD~ +git add src/model.ts +git commit -m "Add user model" +git add src/controller.ts +git commit -m "Add user controller" +git rebase --continue +``` + +### Autosquash (commit messages that auto-arrange) + +```bash +# When committing a fix, reference the commit to squash into +git commit --fixup=a1b2c3d -m "Fix typo" +# or +git commit --squash=a1b2c3d -m "Additional changes" + +# Later, rebase with autosquash +git rebase -i --autosquash main +# fixup/squash commits are automatically placed after their targets +``` + +### Abort or continue + +```bash +git rebase --abort # Cancel and restore original state +git rebase --continue # Continue after resolving conflicts or editing +git rebase --skip # Skip the current commit and continue +``` + +## Bisect (Find the Bug) + +### Binary search through commits + +```bash +# Start bisect +git bisect start + +# Mark current commit as bad (has the bug) +git bisect bad + +# Mark a known-good commit (before the bug existed) +git bisect good v1.2.0 +# or: git bisect good abc123 + +# Git checks out a middle commit. Test it, then: +git bisect good # if this commit doesn't have the bug +git bisect bad # if this commit has the bug + +# Repeat until git identifies the exact commit +# "abc123 is the first bad commit" + +# Done — return to original branch +git bisect reset +``` + +### Automated bisect (with a test script) + +```bash +# Fully automatic: git runs the script on each commit +# Script must exit 0 for good, 1 for bad +git bisect start HEAD v1.2.0 +git bisect run ./test-for-bug.sh + +# Example test script +cat > /tmp/test-for-bug.sh << 'EOF' +#!/bin/bash +# Return 0 if bug is NOT present, 1 if it IS +npm test -- --grep "login should redirect" 2>/dev/null +EOF +chmod +x /tmp/test-for-bug.sh +git bisect run /tmp/test-for-bug.sh +``` + +### Bisect with build failures + +```bash +# If a commit doesn't compile, skip it +git bisect skip + +# Skip a range of known-broken commits +git bisect skip v1.3.0..v1.3.5 +``` + +## Worktree (Parallel Branches) + +### Work on multiple branches simultaneously + +```bash +# Add a worktree for a different branch +git worktree add ../myproject-hotfix hotfix/urgent-fix +# Creates a new directory with that branch checked out + +# Add a worktree with a new branch +git worktree add ../myproject-feature -b feature/new-thing + +# List worktrees +git worktree list + +# Remove a worktree when done +git worktree remove ../myproject-hotfix + +# Prune stale worktree references +git worktree prune +``` + +### Use cases + +```bash +# Review a PR while keeping your current work untouched +git worktree add ../review-pr-123 origin/pr-123 + +# Run tests on main while developing on feature branch +git worktree add ../main-tests main +cd ../main-tests && npm test + +# Compare behavior between branches side by side +git worktree add ../compare-old release/v1.0 +git worktree add ../compare-new release/v2.0 +``` + +## Reflog (Recovery) + +### See everything git remembers + +```bash +# Show reflog (all HEAD movements) +git reflog +# Output: +# abc123 HEAD@{0}: commit: Add feature +# def456 HEAD@{1}: rebase: moving to main +# ghi789 HEAD@{2}: checkout: moving from feature to main + +# Show reflog for a specific branch +git reflog show feature/my-branch + +# Show with timestamps +git reflog --date=relative +``` + +### Recover from mistakes + +```bash +# Undo a bad rebase (find the commit before rebase in reflog) +git reflog +# Find: "ghi789 HEAD@{5}: checkout: moving from feature to main" (pre-rebase) +git reset --hard ghi789 + +# Recover a deleted branch +git reflog +# Find the last commit on that branch +git branch recovered-branch abc123 + +# Recover after reset --hard +git reflog +git reset --hard HEAD@{2} # Go back 2 reflog entries + +# Recover a dropped stash +git fsck --unreachable | grep commit +# or +git stash list # if it's still there +git log --walk-reflogs --all -- stash # find dropped stash commits +``` + +## Cherry-Pick + +### Copy specific commits to another branch + +```bash +# Pick a single commit +git cherry-pick abc123 + +# Pick multiple commits +git cherry-pick abc123 def456 ghi789 + +# Pick a range (exclusive start, inclusive end) +git cherry-pick abc123..ghi789 + +# Pick without committing (stage changes only) +git cherry-pick --no-commit abc123 + +# Cherry-pick from another remote/fork +git remote add upstream https://github.com/other/repo.git +git fetch upstream +git cherry-pick upstream/main~3 # 3rd commit from upstream's main +``` + +### Handle conflicts during cherry-pick + +```bash +# If conflicts arise: +# 1. Resolve conflicts in the files +# 2. Stage resolved files +git add resolved-file.ts +# 3. Continue +git cherry-pick --continue + +# Or abort +git cherry-pick --abort +``` + +## Subtree and Submodule + +### Subtree (simpler — copies code into your repo) + +```bash +# Add a subtree +git subtree add --prefix=lib/shared https://github.com/org/shared-lib.git main --squash + +# Pull updates from upstream +git subtree pull --prefix=lib/shared https://github.com/org/shared-lib.git main --squash + +# Push local changes back to upstream +git subtree push --prefix=lib/shared https://github.com/org/shared-lib.git main + +# Split subtree into its own branch (for extraction) +git subtree split --prefix=lib/shared -b shared-lib-standalone +``` + +### Submodule (pointer to another repo at a specific commit) + +```bash +# Add a submodule +git submodule add https://github.com/org/shared-lib.git lib/shared + +# Clone a repo with submodules +git clone --recurse-submodules https://github.com/org/main-repo.git + +# Initialize submodules after clone (if forgot --recurse) +git submodule update --init --recursive + +# Update submodules to latest +git submodule update --remote + +# Remove a submodule +git rm lib/shared +rm -rf .git/modules/lib/shared +# Remove entry from .gitmodules if it persists +``` + +### When to use which + +``` +Subtree: Simpler, no special commands for cloners, code lives in your repo. + Use when: shared library, vendor code, infrequent upstream changes. + +Submodule: Pointer to exact commit, smaller repo, clear separation. + Use when: large dependency, independent release cycle, many contributors. +``` + +## Sparse Checkout (Monorepo) + +### Check out only the directories you need + +```bash +# Enable sparse checkout +git sparse-checkout init --cone + +# Select directories +git sparse-checkout set packages/my-app packages/shared-lib + +# Add another directory +git sparse-checkout add packages/another-lib + +# List what's checked out +git sparse-checkout list + +# Disable (check out everything again) +git sparse-checkout disable +``` + +### Clone with sparse checkout (large monorepos) + +```bash +# Partial clone + sparse checkout (fastest for huge repos) +git clone --filter=blob:none --sparse https://github.com/org/monorepo.git +cd monorepo +git sparse-checkout set packages/my-service + +# No-checkout clone (just metadata) +git clone --no-checkout https://github.com/org/monorepo.git +cd monorepo +git sparse-checkout set packages/my-service +git checkout main +``` + +## Conflict Resolution + +### Understand the conflict markers + +``` +<<<<<<< HEAD (or "ours") +Your changes on the current branch +======= +Their changes from the incoming branch +>>>>>>> feature-branch (or "theirs") +``` + +### Resolution strategies + +```bash +# Accept all of ours (current branch wins) +git checkout --ours path/to/file.ts +git add path/to/file.ts + +# Accept all of theirs (incoming branch wins) +git checkout --theirs path/to/file.ts +git add path/to/file.ts + +# Accept ours for ALL files +git checkout --ours . +git add . + +# Use a merge tool +git mergetool + +# See the three-way diff (base, ours, theirs) +git diff --cc path/to/file.ts + +# Show common ancestor version +git show :1:path/to/file.ts # base (common ancestor) +git show :2:path/to/file.ts # ours +git show :3:path/to/file.ts # theirs +``` + +### Rebase conflict workflow + +```bash +# During rebase, conflicts appear one commit at a time +# 1. Fix the conflict in the file +# 2. Stage the fix +git add fixed-file.ts +# 3. Continue to next commit +git rebase --continue +# 4. Repeat until done + +# If a commit is now empty after resolution +git rebase --skip +``` + +### Rerere (reuse recorded resolutions) + +```bash +# Enable rerere globally +git config --global rerere.enabled true + +# Git remembers how you resolved conflicts +# Next time the same conflict appears, it auto-resolves + +# See recorded resolutions +ls .git/rr-cache/ + +# Forget a bad resolution +git rerere forget path/to/file.ts +``` + +## Stash Patterns + +```bash +# Stash with a message +git stash push -m "WIP: refactoring auth flow" + +# Stash specific files +git stash push -m "partial stash" -- src/auth.ts src/login.ts + +# Stash including untracked files +git stash push -u -m "with untracked" + +# List stashes +git stash list + +# Apply most recent stash (keep in stash list) +git stash apply + +# Apply and remove from stash list +git stash pop + +# Apply a specific stash +git stash apply stash@{2} + +# Show what's in a stash +git stash show -p stash@{0} + +# Create a branch from a stash +git stash branch new-feature stash@{0} + +# Drop a specific stash +git stash drop stash@{1} + +# Clear all stashes +git stash clear +``` + +## Blame and Log Archaeology + +```bash +# Who changed each line (with date) +git blame src/auth.ts + +# Blame a specific line range +git blame -L 50,70 src/auth.ts + +# Ignore whitespace changes in blame +git blame -w src/auth.ts + +# Find when a line was deleted (search all history) +git log -S "function oldName" --oneline + +# Find when a regex pattern was added/removed +git log -G "TODO.*hack" --oneline + +# Follow a file through renames +git log --follow --oneline -- src/new-name.ts + +# Show the commit that last touched each line, ignoring moves +git blame -M src/auth.ts + +# Show log with file changes +git log --stat --oneline -20 + +# Show all commits affecting a specific file +git log --oneline -- src/auth.ts + +# Show diff of a specific commit +git show abc123 +``` + +## Tags and Releases + +```bash +# Create annotated tag (preferred for releases) +git tag -a v1.2.0 -m "Release 1.2.0: Added auth module" + +# Create lightweight tag +git tag v1.2.0 + +# Tag a past commit +git tag -a v1.1.0 abc123 -m "Retroactive tag for release 1.1.0" + +# List tags +git tag -l +git tag -l "v1.*" + +# Push tags +git push origin v1.2.0 # Single tag +git push origin --tags # All tags + +# Delete a tag +git tag -d v1.2.0 # Local +git push origin --delete v1.2.0 # Remote +``` + +## Tips + +- `git rebase -i` is the single most useful advanced git command. Learn it first. +- Never rebase commits that have been pushed to a shared branch. Rebase your local/feature work only. +- `git reflog` is your safety net. If you lose commits, they're almost always recoverable within 90 days. +- `git bisect run` with an automated test is faster than manual binary search and eliminates human error. +- Worktrees are cheaper than multiple clones — they share `.git` storage. +- Prefer `git subtree` over `git submodule` unless you have a specific reason. Subtrees are simpler for collaborators. +- Enable `rerere` globally. It remembers conflict resolutions so you never solve the same conflict twice. +- `git stash push -m "description"` is much better than bare `git stash`. You'll thank yourself when you have 5 stashes. +- `git log -S "string"` (pickaxe) is the fastest way to find when a function or variable was added or removed. diff --git a/_meta.json b/_meta.json new file mode 100644 index 0000000..b9da627 --- /dev/null +++ b/_meta.json @@ -0,0 +1,6 @@ +{ + "ownerId": "kn7f6g2r31qsb1ts8cf5x7rpk180fn9j", + "slug": "git-workflows", + "version": "1.0.0", + "publishedAt": 1770158556308 +} \ No newline at end of file