Git 在 2005 年被 Linus Torvalds 為 Linux kernel 開發打造出來,二十年後幾乎壟斷了整個版本控制的市場。但長期使用過的人都知道,Git 的介面層積累了一大堆粗糙邊角:staging area 兩層心智模型、rebase 中間卡在衝突動彈不得、reflog 得靠一段 SHA-1 才能救回被丟掉的 commit、branch 命名一改就要重推遠端。Jujutsu(jj) 由 Google 工程師 Martin von Zweigbergk 主導開發,用 Rust 從介面層把版本控制重寫一次,目前在 GitHub 累積超過 30,000 顆星,Google 內部也在逐步用它取代 Piper 跟 Mercurial 的混用局面。
jj 不是「另一個 Git」,是不同的心智模型
從 Perforce 到 Git,版本控制的核心概念一直是 commit + branch + working tree 三層。jj 把 working copy 本身當成一個匿名 commit:任何時候編輯檔案,jj 都會在後台把變更自動寫進當前的 commit,不需要主動 git add、也不需要 git commit -am。
這個轉變聽起來像小改動,實際用起來會發現整個流程都變順了。要拆 commit 就 jj split,要把某段改動塞回歷史某個 commit 就用 jj absorb——0.42 版新加入的自動化指令,會分析每一段 diff 該歸到哪個祖先 commit 底下。過去在 Git 裡需要 git add -p + git commit --amend + git rebase -i 三個步驟才能完成的事,在 jj 通常一到兩個指令就搞定。
衝突當一等公民,而不是工作流程的斷點
Git 的 rebase 一遇到衝突就會停在半途,倉庫進入一個尷尬的中間狀態——不能切 branch、不能開新工作、只能修完再說。這個設計在小型 rebase 還能忍,碰到大型 rebase 或 stack of commits 就變成惡夢。
jj 把衝突視為 commit 的一種合法狀態。帶著衝突的 commit 可以被 log、被 push、被 rebase 到其他地方,只是內容裡會標記出未解決的區塊。實務上這代表可以先把整個 rebase 一口氣跑完,再回頭一個個處理衝突;也可以暫時放著先去做別的事,之後再回來收尾。工作流程不會因為一個衝突就整個凍結。
搭配的還有自動 rebase:修改某個 commit 之後,所有子孫 commit 會自動 rebase 上來,中間就算產生新的衝突也不會阻斷流程。
jj undo 把 reflog 提升到日常操作
Git 有 reflog,但它只記錄 HEAD 移動,rebase 中丟失的 commit 得靠一段 SHA-1 hash 才能撈回來,多數人根本不敢碰。jj 把每一個操作都寫進 operation log,包括 describe、rebase、squash、split、abandon。要撤銷任何一步,直接 jj undo 就會回到操作前的完整狀態。
這對嘗試新工作流程的門檻降低非常多。過去在 Git 裡試 git rebase --onto 前得先開個備份 branch 保底,在 jj 直接跑就是了,錯了就 undo。
Bookmarks 取代 branches,把指標跟開發線分開
Git 的 branch 綁死了兩件事:一個可移動的指標跟一條開發線。這在多人協作時經常造成混淆——本地 main 跟 remote origin/main 的關係、rebase 之後要不要 force push、branch 一改名遠端還留著舊的。
jj 把可移動的指標抽出來稱為 bookmark,開發線本身透過 revset 語言查詢。這樣的分離讓「哪些 commit 屬於這個 feature」跟「這個 bookmark 現在指向哪」變成兩個獨立問題。實務上多數時候不需要主動建 bookmark,jj 會自動追蹤變更集,直到要 push 才需要命名。
Git 相容性:底層仍然是 .git
jj 的殺手級設計是把介面層跟儲存層徹底分開。目前 jj 用 gitoxide 讀寫 Git 的物件資料庫,.git 目錄跟純 Git 專案完全一樣。這代表:
- 同一個 repo 可以同時用 jj 跟 git 操作,隊友完全不需要換工具
- GitHub、GitLab、Forgejo 的 PR/MR 流程都能直接用,push 上去就是標準 Git commit
- CI/CD pipeline 不需要任何改動,checkout 出來的就是普通 Git 倉庫
這種相容策略把導入成本壓到極低。個別開發者可以在團隊沒察覺的情況下切換到 jj,其他人繼續用 Git,兩邊互不干擾。
導入 jj 的實務路徑
在 Debian/Ubuntu 上安裝目前還是靠 Cargo:
1 | cargo install --locked --bin jj jj-cli |
macOS 用 Homebrew:
1 | brew install jj |
裝完之後,把既有的 Git repo 接進來:
1 | cd existing-git-repo |
--colocate 讓 jj 跟 git 共用同一個 .git 目錄,是多數情況下推薦的模式。之後 jj log 看當前變更集,jj new 開新的工作 commit,jj describe -m "訊息" 加描述,jj git push -b <bookmark> 把 bookmark 推上去。
要注意的是剛切過來時 jj log 預設只顯示最近的變更,看不到完整 Git 歷史。這是刻意的——jj 認為「已經跟遠端同步過的祖先 commit」不是日常關注的範圍。要看完整歷史用 jj log -r ::@。
還沒完成的部分
jj 目前的痛點集中在生態系。IDE 整合方面,VSCode 有社群外掛但功能還在補;JetBrains 系列的 Git 整合完全用不上;GitLens 這類進階視覺化工具沒有對應版本。純命令列使用者感受不到,重度依賴 IDE 工作流程的人得等一段時間。
在 GitHub 上開 PR 仍然要靠 gh CLI 或網頁介面,jj 本身還沒有 jj pr create 這類指令。以及 LFS 支援目前是社群 patch,官方版還沒 merge。
不過這些都是圍繞在核心引擎周邊的補完,不影響 jj 本身的可用性。實際使用過幾週之後再回頭用 git,多數人會覺得很多過去習以為常的操作其實比想像中麻煩。
什麼樣的團隊該現在就切
個人專案跟小型團隊:值得馬上試。jj 的心智模型比 Git 簡單,撤銷成本近乎零,實驗新工作流程完全沒有心理負擔。
已經有成熟 Git workflow 的中型團隊:可以在部分開發者身上先試用,利用 --colocate 模式的相容性做小範圍實驗,不會影響其他人的日常。
重度依賴 IDE 整合的 Enterprise 環境:可以再等一兩個版本。核心引擎已經穩定,但 IDE 支援還在快速演進,7 月釋出的 0.43.0 版本仍在密集迭代。
Google 已經在內部大規模驗證 jj 的穩定性,Meta、Mozilla 這些原本用 Mercurial 的組織也開始把 jj 納入內部工具鏈。二十年沒動的版本控制介面層,這次真的有人願意重寫一次——而且技術路線走得夠聰明,讓遷移成本壓到最低。
想找一個穩定的環境來自架 Forgejo、GitLab 或搭配 jj 的開發環境?NCSE Network 提供搭載 Intel Xeon Gold CPU 跟 NVMe SSD 的臺灣本地 VPS,是方電訊機房直連,適合放置團隊的程式碼倉庫跟 CI/CD 服務。前往 ncse.tw 了解方案細節。