lazygit — branch 洞察與歷史手術速查表¶
Terminology rule (zh-TW pages)
技術名詞首次出現以「中文 (English original)」格式呈現,例:變基
(rebase)。不自創翻譯——若無公認譯名直接保留英文(如 fixup、
reflog)。代碼、API 名、CLI flag、套件名、檔名一律不翻。
lazygit 是這裡使用的 git TUI(透過 lazyvim_deps role 安裝;綁定為 lg)。日常操作(stage、commit、branch)很直覺——這頁專收難記的 rebase/amend「手術」,把 lazygit 按鍵與等價的 CLI 並排列出,讓你兩種方式都能做。
黃金守則:只改寫尚未 push 的 commit。 以下歷史手術配方會改寫歷史(產生新的 SHA);統計與洞察介面則是唯讀。若某個 commit 已在共享 remote 上,別改寫——否則你得用
git push --force-with-lease並和他人協調。
受管理的 pull 行為¶
此 dotfiles repo 把 Git 的全域基準設為:
所以 LazyGit 一般的 p pull 會以 rebase 方式執行,且工作區 (working-tree) 的髒變更會在 rebase 前被 stash、rebase 後再套用回來。若重新套用的 stash 發生衝突,Git 會保留該 autostash 而非丟棄;請檢查 git status 與 git stash list,解決工作區衝突、確認你的變更已回來之後,再丟掉 autostash。
變更統計與導覽¶
受管理的設定啟用以下顯示選項:
| 設定 | 效果 |
|---|---|
gui.showNumstatInFilesView: true |
在每個變更檔案旁顯示新增/刪除行數 |
gui.filterMode: fuzzy |
/ 使用模糊比對 (fuzzy matching),字元按順序出現即可,不必連續 |
gui.expandFocusedSidePanel: true |
目前操作的側邊面板自動增高(預設權重為 2) |
短字串的模糊搜尋可能出現較多結果;切換焦點時,面板高度會跟著改變。
Diff 分割沿用上游預設 auto,搭配既有 delta renderer。
檔案樹、commit graph、自動 fetch、commit 訊息長度提示都已由上游預設啟用。
檔案旁的行數是工作區相對 HEAD 的差異,涵蓋已暫存 (staged) 與未暫存
(unstaged) 的變更,但不分成兩組數字。選取 commit 時,主 diff 面板本來
就會顯示該 commit 的 --stat 統計。
在 Files 按 Alt+s(小寫 s,不加 multiplexer prefix),開啟唯讀的
Change statistics popup:
| 區塊 | 等價指令 |
|---|---|
| Staged | git diff --cached --shortstat |
| Unstaged | git diff --shortstat |
| Overall vs HEAD | git diff HEAD --shortstat |
Popup 統計整個 repository,不受目前選取檔案或所在子目錄影響。 沒有變更的區塊會明確顯示零檔案、零行數。 Overall 是重新比較,不是前兩組相加:staged 與 unstaged 的編輯可能互相抵消。
不包含尚未追蹤 (untracked) 的檔案。二進位檔案的變更會計入檔案數, 但不計入文字增刪行數。尚無第一個 commit 時,popup 使用 empty tree, 並明確標示比較基準;原生檔案行數需要 HEAD。 Git 失敗時會呈現錯誤,不會替換成零。Helper 停用 external diff/textconv, 不執行 fetch、stage 或 commit。
Helper 原始檔是 dot_config/lazygit/executable_change-statistics.sh,部署到
~/.config/lazygit/change-statistics.sh。在 Files 按 ? 也能找到這個快捷鍵。
macOS 的 Ghostty/cmux 請使用左側 Option 作為 Alt。
Branch 面板與 I Branch insights¶
受管理的設定讓 Local branches 面板更有資訊量,但不把低訊號的 commit hash 塞進有限寬度:
- Nerd Font v3 圖示讓檔案與 pull request indicator 更直覺。
- 依常見 prefix 為 branch 名稱上色(
feat/、fix/、docs/、維護、 worktree 與 automation branch)。 - 預設依最近使用順序 (recency) 排列。
- 右側
↓N顯示 branch 比 LazyGit 偵測到的 base branch 落後幾個 commit。
↓N 很有用,但它不是 merged 標記。Branch 即使落後 main,仍可能含有
main 沒有的 commit。同樣地,原本的 upstream ✓ 只表示 local 與 upstream
同步,不代表 branch 已被 main 包含。
在 Local branches 面板按 I,再選:
| 按鍵 | 報告 | 網路 |
|---|---|---|
g |
以 local 與 remote-tracking main 做精確 Git containment 判斷 | 不使用 |
p |
同一份報告,再透過一次 gh pr list 補近期 GitHub PR 狀態 |
GitHub |
報告完全唯讀且不會 fetch。要依賴 REM 欄位前,先按 LazyGit 的 refresh
鍵,或等待 auto-fetch 更新 remote-tracking refs。
Local base: main
Remote base: origin/main
Local main vs origin/main: ahead 1, behind 0
SEL LOC REM BASE- BASE+ UPSTREAM WORKTREE DATE BRANCH PR
Y Y 12 0 gone - 2026-08-20 fix/old MERGED->main#42
> Y N 0 1 up1 repo-wt 2026-09-01 feat/new OPEN->main#43
LOC/REM:branch tip 是否為 local / remote main 的 ancestor。Y是git merge-base --is-ancestor對 history containment 的精確定義。BASE-:只有 comparison base 擁有的 commit 數,也就是 branch 落後量。BASE+:只有 branch 擁有的 commit 數;非零代表尚未完整包含於該 base。UPSTREAM:=、upN、downN、downN/upN、gone或-。WORKTREE:此 branch 被目前或另一個 worktree checkout 時的末層目錄名。PR:best-effort GitHub 狀態。MERGED與REM刻意分開,因為 squash merge 與 rebase merge 不會保留相同的 commit ancestry。
Base 依序從 origin/HEAD、main、master 推斷。以其他 trunk 為主的 repo
可以只在該 repo 設定,不必改全域 dotfiles:
這個設定也可以指定 upstream/trunk 一類的 remote-tracking ref。
心智模型:兩種不同的「fixup」¶
fixup 這個字出現在兩個毫不相關的 lazygit 操作裡——搞混它們是弄壞歷史的頭號原因:
| 目標 | lazygit | 實際做的事 |
|---|---|---|
| 把工作區變更塞進某個既有 commit | A(Commits 面板)= amend commit with staged changes |
底層跑 git commit --fixup + git rebase --autosquash |
| 把兩個既有 commit合併成一個 | f / c(Commits 面板)= fixup / squash |
把選取的 commit 併入下面那個(較舊的) |
所以 A =「把我的編輯放進那個舊 commit」;f =「把這兩個 commit 黏在一起」。想加檔案卻按了 f,會把相鄰的 commit 攪在一起。
配方:看某個檔案的歷史(哪些 commit 改過它)¶
唯讀查詢——不會改寫歷史,即使對已 push 的 commit 也安全。
lazygit
1. <ctrl+s>(全域)→ View options for filtering the commit log → 輸入路徑 (path)。Commits 面板此時只列出動過該檔的 commit;在任一 commit 上按 <enter> 可深入看該檔的 diff。再按一次 <ctrl+s> 清除過濾。
lazygit 的過濾不追蹤 rename,而且得一個個 commit 打開——要認真瀏覽檔案歷史,專用工具更順手:
CLI
tig path/to/file # 最佳:範圍限定該檔的 log,<enter> 開每個 commit 的 diff,會追 rename
git log --follow -p -- path/to/file # 追 rename + 每次都顯示完整 diff(這裡會走 delta)
git log --follow --oneline -- path/to/file # 快速看「哪些 commit 動過它」
配方:把一個未 commit 的檔案塞進較舊的 commit¶
lazygit
1. Files 面板:只在你要的那個檔案上按 <space>。別按 a——那是 stage all,會把不相關的編輯一起掃進 amend。
2. Commits 面板:選取目標 commit → A。
CLI
git add path/to/file
git commit --fixup=<target-sha>
git rebase --autosquash --autostash <target-sha>~1
# 非互動(跳過編輯器):前面加上 GIT_SEQUENCE_EDITOR=true
配方:把單一檔案從某個 commit 拉回工作區¶
上一則的反向操作——把單一檔案從未 push 的 commit 退回成「not staged」變更。lazygit 的 custom patch 是原生工具。
lazygit
1. Commits 面板:選取該 commit → <enter> 檢視其檔案。
2. 反白該檔 → <space>(把整個檔案加入 custom patch——會被標記)。
3. <ctrl+p> → View custom patch options → move patch out into index。這會改寫該 commit、移除該檔,並把變更 stage 起來。
4. Files 面板:在該檔上按 <space> 以 unstage——現在它是一筆 Changes not staged 的編輯。
在 patch 選單裡,你要的是
move patch out into index。remove patch from original commit會丟棄該變更(遺失)——想保留就別選它。
CLI
git rebase -i <sha>~1 # 把 <sha> 標成 'edit',存檔離開
git reset HEAD^ -- path/to/file # 只把那個檔案退出 commit -> 工作區變更
git commit --amend --no-edit # 不含它、重做該 commit
git rebase --continue
配方:把工作區變更分叉成新檔案、還原原檔¶
你改了一個檔案,但想把這些編輯留成一個獨立的新檔案,同時把原檔重設回 HEAD(例如把一個實驗分叉成副本)。沒有單一按鍵,但兩步就好:複製會抓住改過的內容,接著 discard 還原原檔。
lazygit
1. :(Execute shell command)→ cp path/to/file path/to/file.new——這份複製抓的是當前、已修改的內容。: 的 shell 在 repo root 執行。
2. Files 面板:選原檔 → d → discard → 還原回 HEAD。
3. 之後就在 path/to/file.new 上繼續改。
CLI
cp path/to/file path/to/file.new # 已修改的內容 -> 新檔
git restore path/to/file # 原檔回到 HEAD(舊版 git 用 git checkout -- <file>)
想之後重新套用這個變更、而不是分叉它?
git stash一步就能存下編輯並還原原檔——但它會落在 stash list,不是新檔案。
配方:從搞砸的 rebase 中恢復¶
lazygit——z undo/Z redo(適用於 branch/commit 操作;工作區必須乾淨)。更深層的恢復請透過 CLI 用 reflog:
CLI
- 陷阱:
git reset --hard會刪掉被 stage 成新增 (new add) 的檔案(例如剛git add的 plan 檔)——先備份。純 untracked 的檔案它不會動。 - 之後再把任何想留的未 commit WIP 套回來(例如事前
git diff > /tmp/wip.patch,事後git apply /tmp/wip.patch)。
地雷 (Footguns)¶
a= lazygit 的 stage ALL。 它會默默把不相關的編輯(例如一個臨時的設定調整)掃進你接下來的 amend/fixup。用<space>只 stage 一個檔案。- 上述任一操作後,該 commit 的 SHA 會改變。對本機 commit 沒問題;正常 push(只有本來就已 push 過才需要 force)。
- 檔案部分 staged 時的 commit 紀律:先
git reset清掉 index,再git add你確切要的內容,然後才git commit。
參見¶
- git diff 工作流程
- 各工具的技巧/配方放在
docs/tools/<tool>.md——這頁是 git/lazygit 配方的落腳處。