Pijul という VCS を体験した

**まえがき**

今年は色々あって、時間も取れずアドベントカレンダーにいまいち乗り切れないまま11月となってしまった。
とはいえ、せっかくの機会なので、前年の様に手を動かすことにこだわらず、気軽に今年気になったツールの体験記や情報まとめでも記して行こうと思う。

# Pijul とは

https://pijul.org/

分散型バージョン管理システム (distributed version control system) 。 Git や Mercurial の仲間。
プロジェクト自体は約 3年前にスタートしていて、今年の 11月に 0.11 がリリースされた。まだまだ若い VSC。

# 特徴

その最大の特徴としては、**カテゴリー理論 (パッチ理論) をベースとしたデータモデルを採用している事** らしい。

## カテゴリー理論 (パッチ理論)

カテゴリー理論 (パッチ理論) について深掘りする心の余裕が無かったので、とにかく情報だけ集めた。

https://jneem.github.io/merging/
https://jneem.github.io/pijul/
https://arxiv.org/pdf/1311.3903.pdf
https://pijul.org/faq/
https://pijul.org/model/
http://darcs.net/Using/Model
https://news.ycombinator.com/item?id=13643025
https://news.ycombinator.com/item?id=18235798

何となく分かったことは、

- Git はスナップショットの履歴で、Pijul は変更差分 (パッチ) の集合
    - Git の Diff は、スナップショット同士の比較
    - Pijul の Diff は、お互いのパッチサブセットの差分の比較
- 各パッチ間の依存関係を自動判別・保存しておき、チェリーピッキングの際に自動解決される
    - Pijul のチェリーピッキングは、Git のブランチ同士のマージに近い？
    - Hunk レベルでの依存関係はこれで良いが、関数呼び出しなどの依存関係は結局のところ破綻する？
        - それらは一つのパッチに一緒に含めるべき、というルールを守れば起こらないのか

気軽にやろうと決意した前書きとは大きくかけ離れた難しさだ。。。
深掘りは来年やろう。

## Darcs との関係性

Pijul を語る上で欠かせないのが、この Darcs という VCS。
そもそも、Pijul は Darcs のパフォーマンス問題を解決するために実装されたコードがそのまま別ツールとしてリリースされたものらしい。
その為、Pijul はパッチ理論がベースにあるという点をはじめ多くの特徴を引き継いている。

http://darcs.net/

Darcs について調べると、

- チェリーピッキングが簡単で正しく適用される
- データモデルが直感的なので、操作も直感的

など他にない利点があったとの評価が多かったが、以下のような指摘もあった。

- パフォーマンス問題。プロジェクトが大きくなると重い
- Svn や Git とは違うコマンド体型
- Git や Mercurial のようなブランチ機能を持たない

特にパフォーマンス問題が大きかったようで、対策をとっている間に Git や Mercurial などの VCS や Github を中心としたエコシステムが発達してしまったので、広く人気を得ることができなかった ( Haskeller には人気のようだ )。

## Git との関係性

Pujul ドキュメント内でも Git は強く意識され、その対比で自身の特徴を説明するシーンが多い。

### 馴染んだコマンド体型

Pijul では、Git のコマンド体型に寄せてきていて、Git 経験者でも導入しやすいように心がけているように見える。
それでいて、非直感的なコマンドは変わってたり。
`git branch -d` → `pijul delete-branch` とか個人的に Pijul の方が分かりやすい。

### Git like なブランチ機能

元々、Darcs では『ブランチ=別リポジトリ (=別フォルダ )』のような考え方があったようだが、Pijul では一つのリポジトリ内でも状態を切り替えられる Git Likeなブランチ機能が導入されている。

Git のブランチは歴史の枝分かれといったイメージだが、Pijul のブランチは全パッチから抜き出したサブセットというイメージだ。

# インストール

とりあえず、使ってみないことには分からないのでインストールする。

- Windows 10 pro October 2018 Update

[Install - pijul](https://pijul.org/manual/installing.html)

Cargo で導入する方法もあるが、おすすめはしない。自分は引っかかりまくって時間をロスした。

おとなしく、PreBuild されたバイナリをインストールする。一緒に `vcruntime140.dll` も必要なので、そっちも落として `pijul-0.11.0.exe` と一緒に配置する。
[pijul.org/downloads](https://pijul.org/downloads/)

![2018-11-26_14h06_10.png](https://qiita-image-store.s3.amazonaws.com/0/20198/e09e293c-3ac6-7cb4-1840-ac4ad81e9de5.png)

起動するも上手く動かないが、どうやら `libssl-1_1-x64.dll` と `libcrypto-1_1-x64.dll` が必要なようだ。
自分は [scoop](https://qiita.com/kikuchi_kentaro/items/77793e4a21db6ffdb7cd) を使って `openssl` を導入していたので、その中の `lib` から拝借した。ちなみに、バージョンによっては含まれていないケースもあるらしい。`1.1.0h` には含まれていなかった。

これで、

```powershell
$ pijul -V
pijul 0.10.1
```

上手くいった。 `0.11.0` を入れたのに `0.10.1` なのはご愛嬌。

# 実践

ということで、実践しながら操作感を確かめていく。
最近お気に入りの nim プロジェクトを構築しながら Pijul でバージョン管理していく。

## 1. 初期化

まずは、プロジェクトを作成し、Pijul で管理するための初期化を行う。

### `pijul init`

https://pijul.org/manual/reference/init.html

```powershell
$ nimble init.

$ tree
# ├── sample_1202.nimble
# └── src
#    └── sample_1202.nim

$ pijul init

$ tree
# .
# ├── .pijul
# │  ├── hooks
# │  ├── id
# │  ├── local
# │  │  └── ignore
# │  ├── patches
# │  ├── pristine
# │  │  ├── db
# │  │  └── db.lock
# │  └── version
# ├── sample_1202.nimble
# └── src
#    └── sample_1202.nim
```

Git の `.git` フォルダに対応するのが、 `.pijul` フォルダかな。

## 2. 変更の追跡・記録・破棄

### `pijul status`

https://pijul.org/manual/reference/status.html

現在のリポジトリの状態を把握するには、`pijul status` が使える。

```powershell
$ pijul status
# On branch master
# 
# Untracked files:
#   (use "pijul add <file>..." to track them)
# 
#         src
#         sample_1202.nimble
#         src\sample_1202.nim
```

### `pijul add`

https://pijul.org/manual/reference/add.html

ファイルの変更を追跡するためには、`pijul add` をする必要がある。

```powershell
$ pijul add src\sample_1202.nim sample_1202.nimble

$ pijul status
# On branch master
# 
# Changes not yet recorded:
#   (use "pijul record ..." to record a new patch)
# 
#         new file:  sample_1202.nimble
#         new file:  src
#         new file:  src\sample_1202.nim
```

追跡が始まったが、まだ記録はされていない状態。

### `pijul record`

https://pijul.org/manual/reference/record.html

Git であれば、 `commit` コマンドを使うところだが、Pijul では `pijul record` で変更を記録する。

```powershell
$ pijul record
# added file sample_1202.nimble
# 
# Shall I record this change? (1/5) [ynkadi?] y
# 
# In file "sample_1202.nimble"
# 
# + # Package
# +
# + version       = "0.1.0"
# + author        = "username"
# + description   = "A new awesome nimble package"
# + license       = "MIT"
# + srcDir        = "src"
# + bin           = @["sample_1202"]
# +
# +
# + # Dependencies
# +
# + requires "nim >= 0.19.0"
# 
# Shall I record this change? (2/5) [ynkad?] y
# 
# added file src
# 
# Shall I record this change? (3/5) [ynkadi?] y
# 
# added file src\sample_1202.nim
# 
# Shall I record this change? (4/5) [ynkadi?] y
# 
# In file "src\\sample_1202.nim"
# 
# + # This is just an example to get you started. A typical binary package
# + # uses this file as the main entry point of the application.
# +
# + when isMainModule:
# +   echo("Hello, World!")
# 
# Shall I record this change? (5/5) [ynkad?] y
# 
# first commit
# What is the name of this patch? Recorded patch 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi

$ pijul status
# On branch master
# Nothing to record, working tree clean
```

変更は一つづつ `[ynkadi]` を聞かれ、このパッチに含めるかどうかを判断する必要がある。

```powershell
y: record this change
n: don't record this change
k: go back to the previous change
a: record all remaining changes
d: skip all remaining changes
```

一つ注意する点として、すべての Yes or No を判断した後、キャレットが左端で点滅しているので『処理待ちかな？』と思っていたら、どうやらコミットメッセージを待っているようなのだ。**これは気が付かない**。

![2018-11-23_12h19_41.png](https://qiita-image-store.s3.amazonaws.com/0/20198/40c54409-6259-e9e5-c30b-78156fbc04dc.png)
↑ この部分

`pijul record -m "first commit"` とメッセージをオプションで渡すこともできる。こっちのほうがびっくりしないのでオススメ。
また、すべての追跡対象の変更をパッチ化する場合には、`pijul record -a` で一発。

### `pijul log`

https://pijul.org/manual/reference/log.html

パッチの履歴を見る場合は `pijul log`。

```powershell
$ pijul log
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
```

### `pijul ls`

https://pijul.org/manual/reference/ls.html

追跡中のファイル一覧を確認する場合は `pijul ls`。

```powershell
$ pijul ls
# sample_1202.nimble
# src
# src\sample_1202.nim
```

### `pijul patch`

https://pijul.org/manual/reference/patch.html

パッチの内容を確認する場合は `pijul patch <<Patch Hash>>`。

```powershell
$ pijul patch 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# In "["sample_1202.nimble"]":
# From line 1:
# + # Package
# +
# + version       = "0.1.0"
# + author        = "username"
# + description   = "A new awesome nimble package"
# + license       = "MIT"
# + srcDir        = "src"
# + bin           = @["sample_1202"]
# +
# +
# + # Dependencies
# +
# + requires "nim >= 0.19.0"
# In "["src", "sample_1202.nim"]":
# From line 1:
# + # This is just an example to get you started. A typical binary package
# + # uses this file as the main entry point of the application.
# +
# + when isMainModule:
# +   echo("Hello, World!")
```

### `pijul diff`

https://pijul.org/manual/reference/diff.html

まだパッチ化されていないローカル変更の差分を確認する場合は `pijul diff` で可能。

まずは、`src\sample_1202.nim` ファイルを以下のように変更して

```diff
when isMainModule:
+   echo("Good Morning, World!")
  echo("Hello, World!")
+   echo("Good Night, World!")
```

差分を確認すると、

```powershell
$ pijul diff
# In file "src\\sample_1202.nim"
# 
# +   echo("Good Morning, World!")
# 
# +   echo("Good Night, World!")
```

### もう一度、`pijul record`

上記変更をした上で、もう一度パッチを作成する。
ポイントとしては、**Pijul は Git でいうインデックスが無いので、追跡対象ファイルの差分はすべて record の対象となる**。

```powershell
$ pijul status
# On branch master
# 
# Changes not yet recorded:
#   (use "pijul record ..." to record a new patch)
# 
#         modified:  src\sample_1202.nim

$ pijul record
# In file "src\\sample_1202.nim"
# 
# +   echo("Good Morning, World!")
# 
# Shall I record this change? (1/2) [ynkad?] y
# 
# +   echo("Good Night, World!")
# 
# Shall I record this change? (2/2) [ynkad?] y
# 
# second commit
# What is the name of this patch? Recorded patch 6mLyhM75oVJpzDBTkhBxPC3zjSztDCXE2PuSDsQHQiuHb2vXNLNDipbVBRTpeYfMgK9B1puQMgLfqgvD57SeH7xK
```

ここで一つ気がつくことは、**パッチは Hunk 単位で選択可能** ということ。
これは、`git add -p` と同様の機能が標準であるということ。賢く Hunk 化してくれるなら便利。

### `pijul unrecord`

https://pijul.org/manual/reference/unrecord.html

一度記録したパッチを無かったことにする場合、`pijul unrecord <<Patch Hash>>` を使う。

```powershell
$ pijul log
# Hash: 6mLyhM75oVJpzDBTkhBxPC3zjSztDCXE2PuSDsQHQiuHb2vXNLNDipbVBRTpeYfMgK9B1puQMgLfqgvD57SeH7xK
# Internal id: 6Qbvwo8Xm7Z
# Authors:
# 
# Timestamp: 2018-11-23 03:43:08.077835100 UTC
# 
#     second commit
# 
# 
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
# 

$ pijul unrecord 6mLyhM75oVJpzDBTkhBxPC3zjSztDCXE2PuSDsQHQiuHb2vXNLNDipbVBRTpeYfMgK9B1puQMgLfqgvD57SeH7xK

$ pijul log
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
# 

$ pijul diff
# In file "src\\sample_1202.nim"
# 
# +   echo("Good Morning, World!")
# 
# +   echo("Good Night, World!")
```

確かにパッチが記録されたという事実は削除されたが、ファイルの変更はそのままだった。
Git のようにインデックスが無いため完全に同等ではないが、 `git reset --mixed/--soft` 相当の機能と思われる。

### `pijul revert`

https://pijul.org/manual/reference/revert.html

記録されていない変更を無かったことにする場合は、`pujul revert` を使う。

```powershell
$ pijul diff
# In file "src\\sample_1202.nim"
# 
# +   echo("Good Morning, World!")
# 
# +   echo("Good Night, World!")

$ pijul revert
# In file "src\\sample_1202.nim"
# 
# +   echo("Good Morning, World!")
# 
# Shall I revert this change? (1/2) [ynkad?] y
# 
# +   echo("Good Night, World!")
# 
# Shall I revert this change? (2/2) [ynkad?] y

$ pijul diff
# 
```

`git reset --hard HEAD` みたいな感じだろうか。

### `pijul remove`

https://pijul.org/manual/reference/remove.html

追跡をやめたいファイルがある場合は、`pujul remove <<ファイル>>` を使う。

```powershell
$ nimble build
#   Verifying dependencies for sample_1202@0.1.0               
#   Building sample_1202/sample_1202.exe using c backend      

$ pijul status
# On branch master
# 
# Untracked files:
#   (use "pijul add <file>..." to track them)
# 
#         sample_1202.exe

$ pijul add sample_1202.exe

$ pijul status
# On branch master
# 
# Changes not yet recorded:
#   (use "pijul record ..." to record a new patch)
# 
#         new file:  sample_1202.exe

$ pijul remove sample_1202.exe

$ pijul status
# On branch master
# 
# Untracked files:
#   (use "pijul add <file>..." to track them)
# 
#         sample_1202.exe
```

ちなみに、いつも Untrackd files に出てくるのが邪魔だったら、明示的に無視することもできる。
`.ignore` か `.pijulignore` ファイルを置いて、その中に無視したいファイルを追加する。


```powershell
$ pijul status
# On branch master
# 
# Untracked files:
#   (use "pijul add <file>..." to track them)
# 
#         sample_1202.exe

$ echo "sample_1202.exe" > .pijulignore

$ pijul status
# On branch master
# 
# Untracked files:
#   (use "pijul add <file>..." to track them)
# 
#         .pijulignore
```

`.gitignore` の様にワイルドカードの指定も可能。

## 2. ブランチ操作

### `pijul fork`

https://pijul.org/manual/reference/fork.html

ブランチを作成するには、`pijul fork` を使う。

```powershell
$ pijul status
# On branch master
# Nothing to record, working tree clean
```

`master` ブランチをフォーク元として、新しく `newbranch` を作成する。

```powershell
$ pijul log
# Hash: 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV
# Internal id: 4NAHqDtPyoj
# Authors:
# 
# Timestamp: 2018-11-23 04:14:36.624109200 UTC
# 
#     add ignore file
# 
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
# 

$ pijul fork newbranch

$ pijul status
# On branch newbranch
# Nothing to record, working tree clean
```

試しに、`newbranch` の `src\sample_1202.nim` を修正してみる。

```powershell
$ pijul diff
# In file "src\\sample_1202.nim"  
#                                 
# -   echo("Hello, World!")       
# +   echo("Hello, Mars!")        
                                
$ pijul record
# In file "src\\sample_1202.nim"
# 
# -   echo("Hello, World!")
# +   echo("Hello, Mars!")
# 
# Shall I record this change? (1/1) [ynkad?] y
# 
# go to mars
# What is the name of this patch? Recorded patch 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC

$ pijul log
# Hash: 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC
# Internal id: Bve1Gm9QMuB
# Authors:
# 
# Timestamp: 2018-11-23 04:21:05.123480300 UTC
# 
#     go to mars
# 
# 
# Hash: 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV
# Internal id: 4NAHqDtPyoj
# Authors:
# 
# Timestamp: 2018-11-23 04:14:36.624109200 UTC
# 
#     add ignore file
# 
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
```

これで、`newbranch` には `7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC` が追加されたが、

```powershell
$ pijul log --branch master
# Hash: 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV
# Internal id: 4NAHqDtPyoj
# Authors:
# 
# Timestamp: 2018-11-23 04:14:36.624109200 UTC
# 
#     add ignore file
# 
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
```

`master` ブランチには、`7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC` が存在していない事が分かる。

### `pijul branches`

[公式ドキュメントに記載なし]

ブランチ一覧を表示するには、`pijul branches` を使う。

```powershell
$ pijul branches
#   master
# * newbranch
```

### `pijul checkout`

https://pijul.org/manual/reference/checkout.html

ブランチを変更するには、`pijul checkout` を使う。

```powershell
$ pijul branches
#   master
# * newbranch

$ pijul checkout master
# Current branch: "master"

$ pijul branches
# * master
#   newbranch
```

### `pijul apply`

https://pijul.org/manual/reference/apply.html

Pijul の醍醐味である、チェリーピッキングを行うには `pijul apply` を使う。

```powershell
$ pijul log --branch master
# Hash: 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV
# Internal id: 4NAHqDtPyoj
# Authors:
# 
# Timestamp: 2018-11-23 04:14:36.624109200 UTC
# 
#     add ignore file
# 
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
# 

$ pijul log --branch newbranch
# Hash: 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC
# Internal id: Bve1Gm9QMuB
# Authors:
# 
# Timestamp: 2018-11-23 04:21:05.123480300 UTC
# 
#     go to mars
# 
# 
# Hash: 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV
# Internal id: 4NAHqDtPyoj
# Authors:
# 
# Timestamp: 2018-11-23 04:14:36.624109200 UTC
# 
#     add ignore file
# 
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
#

```

この、`newbranch` の `7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC` を `master` にチェリーピッキングする。

```powershell
$ pijul branches
# * master
#   newbranch

$ pijul apply 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC

$ pijul log
# Hash: 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC
# Internal id: Bve1Gm9QMuB
# Authors:
# 
# Timestamp: 2018-11-23 04:21:05.123480300 UTC
# 
#     go to mars
# 
# 
# Hash: 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV
# Internal id: 4NAHqDtPyoj
# Authors:
# 
# Timestamp: 2018-11-23 04:14:36.624109200 UTC
# 
#     add ignore file
# 
# Hash: 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi
# Internal id: JA4E96crMn8
# Authors:
# 
# Timestamp: 2018-11-23 03:19:14.245532200 UTC
# 
#     first commit
#
```

チェリーピッキングされたパッチのハッシュは変更されておらず、またマージコミットのようなものも作成されていない。
とても自然だ。
( Fast-Forward なので、驚くのもアレなんだけど。もっと良い例にすれば良かった )

### `pijul delete-branch`

https://pijul.org/manual/reference/delete-branch.html

ブランチを削除するには `pijul delete-branch` を使う。

```powershell
$ pijul delete-branch newbranch

$ pijul branches
# * master
```

## 3. チーム開発

Git に Github があるように、Pijul には [Nest](https://nest.pijul.com/) (2018/11/27 現在停止中) がある。
Nest を使ってリモートリポジトリを利用したチーム開発をやってみる。

### `pijul key`

https://pijul.org/manual/reference/keys.html

Pijul では、２つの用途で SSH キーを利用する。

1. パッチへの署名
2. リモートリポジトリへのアクセス

**● パッチへの署名**

パッチへ署名するためのキーは、以下コマンドで作成できる。デフォルトで Ed25519 の鍵ペアが作られる。

```powershell
# グローバルキー
$ pijul key gen --signing

# ローカルキー
$ pijul key gen --signing --local
```

グローバルキーは `C:\Users\<<usename>>\.pijulconfig` に `sig_ed25519` と `sig_ed25519.pub` が作成される。
ローカルキーは `<<Project Root>>\.pijul` に `sig_ed25519` と `sig_ed25519.pub` が作成される。
ローカルキーが優先される。

どちらかの鍵が作られると、以降はすべてのパッチに署名がつく。
それを Pijul CLI から確認する方法は分からなかったが、 `<<Project Root>>\.pijul\patches` 以下に `<<Patch Hash>>.sig` という JSON ファイルが作成されている。

```json:<<パッチハッシュ>>.sig
{
  "hash":"<<パッチハッシュ>>",
  "signatures":{
    "<<公開鍵ハッシュ>>":"<<署名>>"
  }
}
```

**● リモートリポジトリへの登録**

```powershell
# グローバルキー
$ pijul key gen --ssh

# ローカルキー
$ pijul key gen --ssh --local
```

グローバルキーは `C:\Users\<<usename>>\.pijulconfig` の中に、ローカルキーは `<<Project Root>>\.pijul` の中に `id_ed25519` と `id_ed25519.pub` が作成される。

また、作成した鍵をリモートリポジトリに登録するためのコマンドも用意されている (サーバ落ちてるので使ったことはない)

```powershell
# グローバルキー
$ pijul key upload <url>

# ローカルキー
$ pijul key upload --local <url>
```

### `pijul clone`

https://pijul.org/manual/reference/clone.html

リポジトリを複製するためのコマンド。

```powershell
$ pijul clone https://nest.pijul.com/pijul_org/pijul
```

また、このコマンドは必ずしもリモートを対象とする必要はなく、あくまで url or path で表現されたリポジトリをコピーするためのコマンドであるため、ローカルディレクトリでも実は問題ない。

```powershell
$ pijul clone src_project copied_project
```

### `pijul push`, `pijul pull`

https://pijul.org/manual/reference/push.html
https://pijul.org/manual/reference/pull.html

リモートリポジトリからパッチを取得 / パッチを送信する為のコマンド。
現在、nest が使えないので、ローカルディレクトリで仮想的にやってみる。

```powershell
$ cd ..                                              

$ pijul clone sample_1202 other_sample_1202          
# Pulling patches: 100% (3/3), done.                    
# Applying patches: 100% (3/3), done.                   
                              
$ pijul clone sample_1202 remote_sample_1202         
# Pulling patches: 100% (3/3), done.                    
# Applying patches: 100% (3/3), done.                   
```

|||
|----|----|
| remote_sample_1202 | リモートリポジトリ |
| sample_1202 | ローカルリポジトリ 1 |
| other_sample_1202 | ローカルリポジトリ 2 |

`sample_1202` で変更して、push してみる。

```powershell
$ cd sample_1202                                            

$ pijul log --hash-only  # 長いので Hash だけ
# 6eFvL0vf4228RZ4zIMl3QYNkvtkEPmdR8nMm4hKlvTpqgILTodkJh2ukXlUuMHtJEBswp00QD8VTSlgwnpPW2zPhzx9LY8Z3cDjL
# 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC:0
# 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV:1
# 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi:2

$ pijul diff
# In file "src\\sample_1202.nim"
# 
# -   echo("Hello, Mars!")
# +   echo("Hello, Jupiter!")

$ pijul record
# In file "src\\sample_1202.nim"
# 
# -   echo("Hello, Mars!")
# +   echo("Hello, Jupiter!")
# 
# Shall I record this change? (1/1) [ynkad?] y
# 
# go to jupiter
# What is the name of this patch? Recorded patch 6PQoiSFhwaVz6H78rpH4ewhrm9AgxsSKCbnqU9taS8nN6S4X8So8TPH2zvkhuCMJY79LDcL6dpWC196csGMMqDZj

$ pijul log --hash-only
# 6eFvL0vf4228RZ4zIMl3QYNkvtkEPmdR8nMm4hKlvTpqgILTodkJh2ukXlUuMHtJEBswp00QD8VTSlgwnpPW2zPhzx9LY8Z3cDjL
# 6PQoiSFhwaVz6H78rpH4ewhrm9AgxsSKCbnqU9taS8nN6S4X8So8TPH2zvkhuCMJY79LDcL6dpWC196csGMMqDZj:0  # ← 増えてる
# 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC:1
# 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV:2
# 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi:3

$ pijul push ..\remote_sample_1202
# Hash: 6PQoiSFhwaVz6H78rpH4ewhrm9AgxsSKCbnqU9taS8nN6S4X8So8TPH2zvkhuCMJY79LDcL6dpWC196csGMMqDZj
# Internal id: 3F6x1mrWp6A
# Authors:
# 
# Timestamp: 2018-11-23 05:16:17.734130100 UTC
# 
#     go to jupiter
# 
# 
# Shall I push this patch? [ynkad?] y
```

`remote_sample_1202` を確認してみると、

```powershell
$ cd ..\remote_sample_1202

$ pijul log --hash-only
# gxrv4obMWGn54OFKHVx6542FWbKzz88yRvyxsAP24w5agr7JRBauQF79PHK2DlBa75noy5IG0IKh0eHkJWumbzEZStFWKx6tdFgd
# 6PQoiSFhwaVz6H78rpH4ewhrm9AgxsSKCbnqU9taS8nN6S4X8So8TPH2zvkhuCMJY79LDcL6dpWC196csGMMqDZj:0  # ← 増えてる
# 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV:1
# 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC:2
# 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi:3
```

`other_sample_1202` で pull してみる。

```powershell
$ cd ..\other_sample_1202

$ pijul log --hash-only
# jYdKkshCFAs1KFN27Te9oW3VzUQaCtF4l25VTAUuUmOi5lLpNthrS8ibdfKx3npjHylZOmCEhbyKwSv1fhAhKQSNQcBQKMhbMWPY
# 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV:0
# 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC:1
# 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi:2

$ pijul pull ..\remote_sample_1202
# Pulling patches: 100% (1/1), done.
# Hash: 6PQoiSFhwaVz6H78rpH4ewhrm9AgxsSKCbnqU9taS8nN6S4X8So8TPH2zvkhuCMJY79LDcL6dpWC196csGMMqDZj
# Authors:
# 
# Timestamp: 2018-11-23 05:16:17.734130100 UTC
# 
#     go to jupiter
# 
# 
# Shall I pull this patch? [ynkad?] y
# Applying patches: 100% (1/1), done.

$ pijul log --hash-only
# jYdKkshCFAs1KFN27Te9oW3VzUQaCtF4l25VTAUuUmOi5lLpNthrS8ibdfKx3npjHylZOmCEhbyKwSv1fhAhKQSNQcBQKMhbMWPY
# 6PQoiSFhwaVz6H78rpH4ewhrm9AgxsSKCbnqU9taS8nN6S4X8So8TPH2zvkhuCMJY79LDcL6dpWC196csGMMqDZj:0
# 6XBqejgpKyKETHqYuoEGdMmqJkJ6Lj1ZNrhaez9cbKJrCeyRdhbKPjPJX9nLFaKA7jUC24NjZZQgGqU61JEEXLvV:1
# 7RbjQKRMXL7MaC8naU29bGV1obYudvntGSVfEuDmpf9JAChhcbwb944hFQtdVcaujtcc4KCa1z3A8fPHNLpzNaZC:2
# 8AoNvRnRvhnTyMCZmdQbpdwqBr6Ax4WNsHYL7f55iHkGw7bttoUuoiDetQmmK7iWq53tecQwRTn1wFqMy7BpL7Pi:3

$ cat src\sample_1202.nim
# # This is just an example to get you started. A typical binary package
# # uses this file as the main entry point of the application.
# 
# when isMainModule:
#   echo("Hello, Jupiter!")
```

共有できている。

Git と違い、追跡ブランチが無いため `git fetch` して `git merge` みたいな操作はできない。そもそも、マージが起こらないということであれば、その必要もないのか。

感覚としては、リモートリポジトリも一つのブランチで、pull はリモートリポジトリの未取得パッチを apply しているような。

と、こんな感じで大体の動きが確認できた。
あとは気になるのが、**衝突したときの挙動** だ。

# 衝突と解決

とても気になるのが、衝突をどう解決するのか。
Pijul のドキュメントを見ていると、様々な場面で

- Pijul はパッチの集合
- パッチは基本前後を入れ替えても問題ない
- 過去に適用したパッチを非適用しても問題ない

みたいな説明を見た。
けど、衝突と解決を行ったら、それらは崩れてしまいそうに思う。

多分、答えは以下等を読むと分かりそうだが、そこそこ難しい。

https://jneem.github.io/merging/
https://jneem.github.io/pijul/
https://arxiv.org/pdf/1311.3903.pdf

今はそっとしておく。

# もっとこうして欲しい

## そっけない態度

レスポンスが結構簡素で、 `pijul add` しても `pijul apply` しても「しました！」みたいな反応をくれない。

## `HEAD` がない

Git の `HEAD` みたいなのがあると、`pijul unrecord HEAD` みたいにできるんだけど。
時系列的な意味合いを含む HEAD (先頭) は Pijul 的には正しくないのかもしれないが。

# あとがき

※ この記事は個人の見解であり、所属する組織を代表するものではありません。