Closed6

Git互換の次世代バージョン管理システムJujutsuを試す

slowhandslowhand

Jujutsuとは?

Jujutsu docs

Rust製の Git 互換 VCS「Jujutsu(jj)」は、既存の Git リポジトリをそのまま扱えるため、今のホスティングやワークフローを崩さず導入できます。

変更は自動でコミットされ、さらにリポジトリ全体の操作を記録する「オペレーションログ」により、任意のタイミングで undo/redo が可能で作業を安全に巻き戻せます。

ステージングエリアや固定ブランチを排した設計で jj splitjj squash による履歴整形がワンコマンドで行え、レビュー前に“完璧な履歴”を簡単に作れます。

インストール

早速インストール&セットアップを行っていきたいと思います。

Installation and setup - Jujutsu docs

Macでの動作確認を行なっている為、Homebrew でインストールします。

$ brew install jj
# ....
$ jj --version
jj 0.28.2

実際の使い方に関しては公式ドキュメントにもある👇のドキュメントを参考に進めていきたいと思います。

Introduction - Steve's Jujutsu Tutorial

slowhandslowhand

リポジトリ作成

早速適当なリポジトリを作成してみたいと思います。

$ mkdir jj-example
$ cd jj-example
$ jj git init
Initialized repo in "."

この時点で .jj ディレクトリが作成され中身は以下の様な構成になっています。

$ erd -H -y inverted -L 3 ".jj"
136.0 KiB .jj
124.0 KiB ├─ repo
 84.0 KiB │  ├─ store
 68.0 KiB │  │  ├─ git
  8.0 KiB │  │  ├─ extra
  4.0 KiB │  │  ├─ git_target
  4.0 KiB │  │  └─ type
 20.0 KiB │  ├─ index
  8.0 KiB │  │  ├─ segments
  8.0 KiB │  │  ├─ operations
  4.0 KiB │  │  └─ type
 12.0 KiB │  ├─ op_store
  4.0 KiB │  │  ├─ views
  4.0 KiB │  │  ├─ type
  4.0 KiB │  │  └─ operations
  4.0 KiB │  ├─ submodule_store
  4.0 KiB │  │  └─ type
  4.0 KiB │  └─ op_heads
  4.0 KiB │     ├─ type
        - │     └─ heads
 12.0 KiB └─ working_copy
  4.0 KiB    ├─ tree_state
  4.0 KiB    ├─ type
  4.0 KiB    └─ checkout

.jj/repo/store/git 内にまるッとgitの構成ファイルが含まれているようでした 👀

$ ls .jj/repo/store/git
config  description  HEAD  hooks  info  objects  refs
slowhandslowhand

実際にリポジトリ上で作業してみる

まずは git status に相当する jj st を作成したばかりのリポジトリで実行してみます。

$ jj st      
The working copy has no changes.
Working copy  (@) : unkvksyx ff0e2d03 (empty) (no description set)
Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set)

見慣れない感じですが、何も差分がない状態なのは分かります。

早速node.jsの簡単なアプリを作っていきたいと思います。

$ node -v 
v22.9.0
$ npm -v
11.3.0
$ npm init -y       
Wrote to /Users/..../jj-example/package.json:

{
  "name": "jj-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "commonjs"
}

この時点で jj st を実施してみます。

$ ls                   
package.json
$ jj st
Working copy changes:
A package.json
Working copy  (@) : unkvksyx 11c38355 (no description set)
Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set)

Working copy(empty) がきえてハッシュ値が変化してます ff0e2d0311c38355

ここで jj log で履歴を見てみます。

$ jj log
@  unkvksyx (no email set) 2025-05-xx xx:xx:xx 11c38355
│  (no description set)
◆  zzzzzzzz root() 00000000

先ほどの変化したハッシュ値 11c38355 が最新になっています。

ここで package.json を修正して jj st を実施してみます。

$ jj st        
Working copy changes:
A package.json
Working copy  (@) : unkvksyx 147002bb (no description set)
Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set)

先ほどとハッシュ値が変化しました 147002bb

jj log を実施すると

$ jj log
@  unkvksyx (no email set) 2025-05-xx xx:xx:xx 147002bb
│  (no description set)
◆  zzzzzzzz root() 00000000

最新のハッシュ値が 11c38355 から 147002bb になっています。

この様に変更がある度にコミットが上書きされ新しいハッシュ値になっている挙動の様です。

ちなみに置き換え前のコミットは jj evolog で確認する事ができます。

$ jj evolog
@  unkvksyx (no email set) 2025-05-xx xx:xx:xx 147002bb
│  (no description set)
○  unkvksyx hidden (no email set) 2025-05-xx xx:xx:xx 11c38355
│  (no description set)
○  unkvksyx hidden (no email set) 2025-05-xx xx:xx:xx ff0e2d03
   (empty) (no description set)
slowhandslowhand

コミットに分かりやすい説明文をつける

最新のコミット値 147002bb に対して jj describe で説明文を付けてみます。

$ jj st                      
Working copy changes:
A package.json
Working copy  (@) : unkvksyx 147002bb (no description set)
Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set)
$ jj describe -m "hello world"
# ...
$ jj st                       
Working copy changes:
A package.json
Working copy  (@) : unkvksyx 5d847a45 hello world
Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set)

(no description set)hello world に変わっています。

ここで jj evolog を実施すると

$ jj evolog
@  unkvksyx (no email set) 2025-05-xx xx:xx:xx 5d847a45
│  hello world
○  unkvksyx hidden (no email set) 2025-05-xx xx:xx:xx 147002bb
│  (no description set)
○  unkvksyx hidden (no email set) 2025-05-xx xx:xx:xx 11c38355
│  (no description set)
○  unkvksyx hidden (no email set) 2025-05-xx xx:xx:xx ff0e2d03
   (empty) (no description set)

新しいコミットが追加されてます。

slowhandslowhand

新しい履歴を始める

jj new コマンドで新しい履歴を始めることが出来ます。

$ jj new
Working copy  (@) now at: uopsnzms fb4ee9a9 (empty) (no description set)
Parent commit (@-)      : unkvksyx 5d847a45 hello world
$ jj log   
@  uopsnzms (no email set) 2025-05-xx xx:xx:xx fb4ee9a9
│  (empty) (no description set)
○  unkvksyx (no email set) 2025-05-xx xx:xx:xx 5d847a45
│  hello world
◆  zzzzzzzz root() 00000000

新しく uopsnzms が作成され、そこにコミットが積まれていく様です。

何か編集して jj evolog を確認すると uopsnzms にコミットが積まれているのが分かります。

$ jj evolog
@  uopsnzms (no email set) 2025-05-xx xx:xx:xx 1ecef4e8
│  (no description set)
○  uopsnzms hidden (no email set) 2025-05-xx xx:xx:xx fb4ee9a9
   (empty) (no description set)
slowhandslowhand

undoで修正を元に戻す

ここで package.json を修正します。修正diffは以下になります。

$ jj diff                     
Modified regular file package.json:
   1    1: {
   2    2:   "name": "jj-example",
   3    3:   "version": "1.0.0",
   4    4:   "description": "jj-example",
   5    5:   "main": "index.js",
   6    6:   "scripts": {
   7    7:     "test": "echo \"Error: no test specified\" && exit 1"

ここで jj undo して修正を元に戻してみます。

$ jj undo  
Working copy  (@) now at: uopsnzms fb4ee9a9 (empty) (no description set)
Parent commit (@-)      : unkvksyx 5d847a45 hello world
Added 0 files, modified 1 files, removed 0 files
$ jj st    
The working copy has no changes.
Working copy  (@) : uopsnzms fb4ee9a9 (empty) (no description set)
Parent commit (@-): unkvksyx 5d847a45 hello world

変更が無くなって先ほど jj new した直後に戻っています。

このスクラップは4ヶ月前にクローズされました