AI 生成聲明: 本文初稿由 Gemini 2.5 Flash AI 生成, 再由個人手動修改而成。

Git 改變了世界,卻也留下了無數「分支地獄」的故事,這點你大概也心有戚戚焉吧。今天我想從兩個被低估的 Git 外掛工具聊起,一步步帶你走向一個更現代、更人性化的版本控制未來 —— Jujutsu (jj)


引言:Git 的輝煌與隱憂

你是否曾經:

  • 為了改一個 typo,敲了 git rebase -i HEAD~5,然後工作目錄瞬間爆炸?
  • 在 10 個依賴分支之間切來切去,忘記自己正在做什麼?
  • 看著 git log 像聖誕樹一樣亂七八糟,卻無從下手?

Git 無疑是偉大的,只是它的設計來自 2005 年。那個年代沒有 stacked diff、沒有 PR stack、也沒有即時 CI。
到了今天,我想我們需要的已經不只是「能用」,而是「好用」囉。

接下來這篇文章,會帶你走過一條進化之路

evolution-path.svg

從小修小補,到系統性革新。


git-revise —— 讓歷史編輯不再「破壞」

問題:git rebase 的副作用

$ git rebase -i HEAD~3
# 衝突!工作目錄被打斷,stash 忘記了,崩潰中...

rebase 雖然能重寫歷史,可是它會強制中斷你的工作流,這實在是頗惱人。

git-rebase-loop.svg

圖1:傳統 git rebase 常導致工作流循環中斷


解法:git-revise

git-revise 是 Git 的子命令,專注於非破壞性提交編輯。它在記憶體中操作,不影響工作目錄

# 安裝
pipx install git-revise

# 修復最近一個 commit 的拼字錯誤
git revise -m "Fix typo in login button"

# 分割最後一個大 commit 成兩個小塊
git revise --split
git-revise-workflow.svg

圖2:git-revise 在記憶體中安全編輯,工作流不中斷

靈感來源git-revise 是 jj 創始人 Martin von Zweigbergk 早期作品之一。

它讓「修補歷史」從痛苦變成愉悅,不過說穿了它只解決了單點問題。那分支管理呢?還是一團亂啦。


git-branchstack —— 自動化分支堆疊機制

問題:分支依賴地獄

# 手動流程
git checkout main
git checkout -b feature/login
# ... coding ...
git checkout -b feature/login-validation  # 依賴 login
git checkout feature/login
# 切來切去,build 重跑,頭暈

當團隊用上 stacked diff(像 Gerrit、Phabricator)的時候,這種切來切去簡直是災難一場。

branch-dependency-hell.svg

圖3:傳統 Git 分支切換形成雜亂的依賴網


解法:git-branchstack

這是一個輕量級堆疊分支管理器,核心概念:

用 commit message 的 [topic] tag 自動建立分支堆疊

安裝

pipx install git-branchstack
pipx install git-revise  # 建議一起用

實戰範例

假設你在 local-dev 分支上有 3 個 commits:

# 用 git-revise 加上 topic tags
git revise --interactive --edit

編輯後的 commit message:

[auth] Add login endpoint
[auth] Validate JWT token
[ui] Update login button style

執行:

git branchstack
branchstack-structure.svg

圖4:git branchstack 自動建立清晰的堆疊結構

推送整個堆疊

# 設定 alias 更方便
git config alias.bspush '!git push -u origin $(git branchstack --list-local)'

git bspush

來源:git-branchstack GitHub

它讓「分支堆疊」從手動變成自動,只是說到底它仍然是 Git 的外掛,沒辦法改變核心的體驗。


Jujutsu (jj) 的架構革新與核心設計

jj = git-revise 的靈魂 + git-branchstack 的堆疊 + Git 的相容性 + 全新設計

jj 由 Google 工程師 Martin von Zweigbergk 開發,現在已經在 Google 內部逐步取代舊的 VCS 了,這點實在是頗具參考性。

核心創新對比

概念 Git jj
提交單位 不可變 commit 可變 change
歷史追蹤 線性 log 操作日誌 (operation log)
分支管理 手動切換 自動書籤 + 堆疊
衝突處理 手動 內建多方解析器
相容性 - 100% Git 互通
jj-core-model.svg

圖5:jj 的 changes + bookmarks + operation log 核心架構


Changes 而非 Commits

# jj:提交是「活的」
jj new               # 創建新 change
echo "fix" >> file   # 修改
jj amend             # 更新當前 change(像 git amend)
jj split             # 輕鬆分割 change
jj-amend-flow.svg

圖6:jj amend 即時更新 change,無需 rebase

所有操作都在記憶體中,不中斷工作流


操作日誌 (Operation Log)

jj op log
@  abc123  2分鐘前  new change
├─ def456  5分鐘前  amend change
├─ ghi789  10分鐘前 rebase -d main
jj-op-log-timeline.svg

圖7:jj op log 提供完整操作歷史,永不迷路

你永遠都知道「系統到底怎麼變成這樣的」,再也不用對著 reflog 抓頭髮了。


自動堆疊書籤(進階版)

# 從 main 開始
jj new main -m "[auth] Add login"
jj bookmark create auth   # 手動標記(僅此一次)

# 繼續堆疊
jj new -m "[ui] Update button"
jj bookmark create ui     # 標記上層

jj log 顯示

$ jj log
@  ooo  [ui] Update login button
│  │   (你正在編輯)
├─ ooo  [auth] Add login endpoint
│  │
○──○──○ main
jj-log-stacked-bookmarks.svg

圖8:jj log 內建堆疊視覺化,無需額外工具

小提醒:bookmark 需手動 create,但一旦建立,後續 amend/rebase自動移動上層,無需手動調整。

推送整個堆疊

jj git push --all-bookmarks

對比:Git vs jj 的 rebase

動作 Git jj
重新基於 main git rebase main jj rebase -d main
工作目錄中斷?
歷史可回溯? 靠 reflog 內建 op log
分支堆疊保留? 手動 自動
git-vs-jj-rebase.svg

圖9:jj rebase 自動調整堆疊,Git 需手動修補


快速上手範例

# 1. 安裝(需要 Rust)
cargo install jj

# 2. 從現有 Git repo 啟動
cd my-project
jj git init

# 3. 開始使用
jj log
jj new -m "fix typo"
echo "hello" >> file
jj amend
jj git push
jj-quickstart-steps.svg

圖10:從 Git 遷移到 jj 的 3 步流程

官方文檔:github.com/jj-vcs/jj


結論:擁抱進化,別讓工具綁住你

工具 定位 適合對象
git-revise 局部修補 想提升 rebase 體驗
git-branchstack 堆疊管理 stacked diff 團隊
Jujutsu (jj) 全面替代 追求未來 VCS 的人
adoption-journey.svg

git-revise 的單點改善,到 git-branchstack 的堆疊管理,jj 把這些概念整合為一套完整的模型。當然,我不建議你盲目地拋棄手邊熟悉的工具,不過真的值得花個半天玩玩看。

下次 rebase 又把你搞到崩潰時,不妨試試 jj 吧。

老實說,用過之後你大概不會想回去了 :-)