git-advanced-workflows
進階 Git 技巧:互動式 rebase、cherry-pick、bisect、worktree 和 reflog 救援
中文翻譯
--- name: git-advanced-workflows description: 精通進階 Git 工作流程,包含 rebase、cherry-pick、bisect、worktree 與 reflog,用來維持乾淨的歷史並從任何狀況中還原。適用於管理複雜的 Git 歷史、在功能 branch 上協作,或排查 repository 問題的時候。 --- # Git 進階工作流程 精通進階 Git 技巧,維持乾淨的歷史、有效協作,並且有信心地從任何狀況中還原。 ## 什麼時候用這個 Skill - 在 merge 之前整理 commit 歷史 - 把特定 commit 套用到其他 branch - 找出引入 bug 的 commit - 同時處理多個功能 - 從 Git 的失誤或遺失的 commit 中還原 - 管理複雜的 branch 工作流程 - 準備乾淨的 PR 供 review - 同步分歧的 branch ## 核心概念 ### 1. 互動式 Rebase 互動式 rebase 是 Git 歷史編輯的瑞士刀。 **常見操作:** - `pick`:保留 commit 原樣 - `reword`:修改 commit 訊息 - `edit`:修改 commit 的內容 - `squash`:和前一個 commit 合併 - `fixup`:和 squash 一樣,但捨棄訊息 - `drop`:完全移除 commit **基本用法:** ```bash # Rebase 最近 5 個 commit git rebase -i HEAD~5 # Rebase 目前 branch 上所有的 commit git rebase -i $(git merge-base HEAD main) # Rebase 到特定 commit 上 git rebase -i abc123 ``` ### 2. Cherry-Picking 把特定 commit 從一個 branch 套用到另一個 branch,不用 merge 整個 branch。 ```bash # Cherry-pick 單一 commit git cherry-pick abc123 # Cherry-pick 一段範圍的 commit(不含起點) git cherry-pick abc123..def456 # Cherry-pick 但不 commit(只放進 staging) git cherry-pick -n abc123 # Cherry-pick 並修改 commit 訊息 git cherry-pick -e abc123 ``` ### 3. Git Bisect 在 commit 歷史上做二分搜尋,找出引入 bug 的 commit。 ```bash # 開始 bisect git bisect start # 把目前的 commit 標記為壞的 git bisect bad # 標記已知正常的 commit git bisect good v1.0.0 # Git 會 checkout 中間的 commit,請測試它 # 然後標記為好或壞 git bisect good # 或:git bisect bad # 持續進行直到找到 bug # 完成後 git bisect reset ``` **自動化 Bisect:** ```bash # 用腳本自動測試 git bisect start HEAD v1.0.0 git bisect run ./test.sh # test.sh 正常時應該 exit 0,異常時 exit 1-127(125 除外) ``` ### 4. Worktree 同時在多個 branch 上工作,不用 stash 或切換。 ```bash # 列出現有的 worktree git worktree list # 為功能 branch 新增 worktree git worktree add ../project-feature feature/new-feature # 新增 worktree 並建立新 branch git worktree add -b bugfix/urgent ../project-hotfix main # 移除 worktree git worktree remove ../project-feature # 清除過期的 worktree git worktree prune ``` ### 5. Reflog 你的安全網:追蹤所有 ref 的移動,連被刪除的 commit 也包含在內。 ```bash # 查看 reflog git reflog # 查看特定 branch 的 reflog git reflog show feature/branch # 還原被刪除的 commit git reflog # 找出 commit hash git checkout abc123 git branch recovered-branch # 還原被刪除的 branch git reflog git branch deleted-branch abc123 ``` ## 詳細模式與實作範例 詳細的模式文件放在 `references/details.md`,上面這一層導覽不夠用的時候再去讀那份檔案。 ## 最佳實務 1. **一律使用 --force-with-lease**:比 --force 安全,避免覆蓋別人的工作 2. **只 rebase 本機的 commit**:不要 rebase 已經 push 並共享出去的 commit 3. **寫有描述性的 commit 訊息**:未來的你會感謝現在的你 4. **Atomic commit**:每個 commit 應該只做一個邏輯上的變更 5. **Force push 之前先測試**:確認改寫歷史沒有弄壞任何東西 6. **隨時留意 Reflog**:Reflog 是你的安全網,但從目前 tip 無法到達的 commit,其紀錄預設 30 天後就會過期(`gc.reflogExpireUnreachable`),可到達的紀錄則是 90 天後(`gc.reflogExpire`) 7. **有風險的操作之前先開 Branch**:做複雜的 rebase 之前先建立備份 branch ```bash # 安全的 force push git push --force-with-lease origin feature/branch # 在有風險的操作之前先建立備份 git branch backup-branch git rebase -i main # 如果出了問題 git reset --hard backup-branch ``` ## 常見陷阱 - **Rebase 公開的 Branch**:會讓協作者遇到歷史衝突 - **沒有 lease 的 Force Push**:可能會覆蓋隊友的工作 - **在 Rebase 中遺失工作**:小心解決衝突,rebase 之後要測試 - **忘記清理 Worktree**:被遺棄的 worktree 會占用磁碟空間 - **實驗前沒有備份**:一律建立安全用的 branch - **在髒的 Working Directory 上做 Bisect**:bisect 之前先 commit 或 stash ## 還原指令 ```bash # 中止進行中的操作 git rebase --abort git merge --abort git cherry-pick --abort git bisect reset # 把檔案還原成特定 commit 的版本 git restore --source=abc123 path/to/file # 復原上一個 commit,但保留變更 git reset --soft HEAD^ # 復原上一個 commit,並捨棄變更 # 警告:--hard 也會刪除未 commit 的變更(已 staged 和未 staged 的), # 而且 reflog 無法救回它們。先檢查 `git status` 並 stash。 git reset --hard HEAD^ # 盡快還原被刪除的 branch。預設情況下,git gc 可以在 HEAD 的 reflog # 中未 merge 的 commit 紀錄滿 30 天後清除它們,從每筆紀錄被記錄 # 的時間開始算,不是從刪除時開始算 # 刪除 branch 也會刪除它自己的 reflog;去搜尋 HEAD 的 reflog git reflog git branch recovered-branch abc123 ```
英文原文
--- name: git-advanced-workflows description: Master advanced Git workflows including rebasing, cherry-picking, bisect, worktrees, and reflog to maintain clean history and recover from any situation. Use when managing complex Git histories, collaborating on feature branches, or troubleshooting repository issues. --- # Git Advanced Workflows Master advanced Git techniques to maintain clean history, collaborate effectively, and recover from any situation with confidence. ## When to Use This Skill - Cleaning up commit history before merging - Applying specific commits across branches - Finding commits that introduced bugs - Working on multiple features simultaneously - Recovering from Git mistakes or lost commits - Managing complex branch workflows - Preparing clean PRs for review - Synchronizing diverged branches ## Core Concepts ### 1. Interactive Rebase Interactive rebase is the Swiss Army knife of Git history editing. **Common Operations:** - `pick`: Keep commit as-is - `reword`: Change commit message - `edit`: Amend commit content - `squash`: Combine with previous commit - `fixup`: Like squash but discard message - `drop`: Remove commit entirely **Basic Usage:** ```bash # Rebase last 5 commits git rebase -i HEAD~5 # Rebase all commits on current branch git rebase -i $(git merge-base HEAD main) # Rebase onto specific commit git rebase -i abc123 ``` ### 2. Cherry-Picking Apply specific commits from one branch to another without merging entire branches. ```bash # Cherry-pick single commit git cherry-pick abc123 # Cherry-pick range of commits (exclusive start) git cherry-pick abc123..def456 # Cherry-pick without committing (stage changes only) git cherry-pick -n abc123 # Cherry-pick and edit commit message git cherry-pick -e abc123 ``` ### 3. Git Bisect Binary search through commit history to find the commit that introduced a bug. ```bash # Start bisect git bisect start # Mark current commit as bad git bisect bad # Mark known good commit git bisect good v1.0.0 # Git will checkout middle commit - test it # Then mark as good or bad git bisect good # or: git bisect bad # Continue until bug found # When done git bisect reset ``` **Automated Bisect:** ```bash # Use script to test automatically git bisect start HEAD v1.0.0 git bisect run ./test.sh # test.sh should exit 0 for good, 1-127 (except 125) for bad ``` ### 4. Worktrees Work on multiple branches simultaneously without stashing or switching. ```bash # List existing worktrees git worktree list # Add new worktree for feature branch git worktree add ../project-feature feature/new-feature # Add worktree and create new branch git worktree add -b bugfix/urgent ../project-hotfix main # Remove worktree git worktree remove ../project-feature # Prune stale worktrees git worktree prune ``` ### 5. Reflog Your safety net - tracks all ref movements, even deleted commits. ```bash # View reflog git reflog # View reflog for specific branch git reflog show feature/branch # Restore deleted commit git reflog # Find commit hash git checkout abc123 git branch recovered-branch # Restore deleted branch git reflog git branch deleted-branch abc123 ``` ## Detailed patterns and worked examples Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient. ## Best Practices 1. **Always Use --force-with-lease**: Safer than --force, prevents overwriting others' work 2. **Rebase Only Local Commits**: Don't rebase commits that have been pushed and shared 3. **Descriptive Commit Messages**: Future you will thank present you 4. **Atomic Commits**: Each commit should be a single logical change 5. **Test Before Force Push**: Ensure history rewrite didn't break anything 6. **Keep Reflog Aware**: Reflog is your safety net, but entries for commits not reachable from the current tip expire after 30 days by default (`gc.reflogExpireUnreachable`), and reachable entries after 90 days (`gc.reflogExpire`) 7. **Branch Before Risky Operations**: Create backup branch before complex rebases ```bash # Safe force push git push --force-with-lease origin feature/branch # Create backup before risky operation git branch backup-branch git rebase -i main # If something goes wrong git reset --hard backup-branch ``` ## Common Pitfalls - **Rebasing Public Branches**: Causes history conflicts for collaborators - **Force Pushing Without Lease**: Can overwrite teammate's work - **Losing Work in Rebase**: Resolve conflicts carefully, test after rebase - **Forgetting Worktree Cleanup**: Orphaned worktrees consume disk space - **Not Backing Up Before Experiment**: Always create safety branch - **Bisect on Dirty Working Directory**: Commit or stash before bisecting ## Recovery Commands ```bash # Abort operations in progress git rebase --abort git merge --abort git cherry-pick --abort git bisect reset # Restore file to version from specific commit git restore --source=abc123 path/to/file # Undo last commit but keep changes git reset --soft HEAD^ # Undo last commit and discard changes # WARNING: --hard also deletes uncommitted changes (staged and unstaged), # and the reflog cannot recover them. Check `git status` and stash first. git reset --hard HEAD^ # Recover a deleted branch soon. By default, git gc can prune HEAD's reflog # entries for unmerged commits once they're 30 days old, counted from when # each entry was recorded, not from the deletion # Deleting a branch also deletes its own reflog; search HEAD's reflog git reflog git branch recovered-branch abc123 ```