2023/01/09

Saplingを試してみる

Metaで開発されているSaplingが公開されましたので、使ってみます。

  1. インストール
  2. 初期設定
  3. リポジトリの作成
  4. ファイルを追加
  5. 編集してコミット
  6. コミットログの表示
  7. headの表示
  8. 分岐の作成
  9. 分岐で次に進む
  10. ブランチのマージ
  11. マージを元に戻す
  12. rebaseにてブランチをマージ
  13. コミット間の移動
  14. 操作の取り消しと再実行
  15. コマンド一覧

今回はWindowsで試してみます。

インストール


インストールは、
https://github.com/facebook/sapling/releases/tag/0.2.20221222-152408-ha6a66d09
からダウンロードしてきたzipを展開してPATHを通すだけです。

頻繁に更新されているようなので、新規にインストールするなら最新のものを利用するのがよさそうです。

初期設定


まずは使用者名の設定をします。
$ sl config --user ui.username "yourname <yourname@mail.address.com>"
今回は、メールアドレスを省略して、
$ sl config --user ui.username "yourname"
としています。

リポジトリの作成


新しいリポジトリを作っていきます。
https://sapling-scm.com/docs/introduction/getting-started
ではGithubからリポジトリを取得するように書かれていますが、ここでは実験的な機能として入っているgitのリポジトリを1から作成する方法を使ってみます。
$ sl init --git
これは実験的な機能であるためか、sl helpでも今回試しているバージョンではコマンドが出てきません。

何もファイルをコミットしていない状態だと、logもなにも表示されないので、sl showを実行してみたところ、

$ sl show
changeset:   0000000000000000000000000000000000000000  (@)
user:
date:        木, 01 1 1970 09:00:00 +0900
といった表示がされました。

ファイルを追加


お試し用のファイルを
$ echo aaa > a.txt
のように作成します。

次にSaplingに登録します。

$ sl add a.txt
最後にコミットします。
$ sl commit
Windowsでは、デフォルトではメモ帳が開くので、コミットメッセージを書いて保存し、メモ帳を終了します。 すると、コミットが完了します。

ログを見ると、

$ sl log
changeset:   5bbaee36d524dc4b97c9ee5740cf6440a37ddfb5  (@)
user:        yourname <>
date:        木, 05 1 2023 15:31:25 +0900
summary:     Initial commit
と表示されます。

単にslを実行すると、

$ sl
@  5bbaee36d  2 minutes ago  >
   Initial commit
となります。コミット時間が相対時間で表示されるので、時刻表示のほうが良い場合はlogのほうがよさそうです。
$ sl head
changeset:   5bbaee36d524dc4b97c9ee5740cf6440a37ddfb5  (@)
user:        yourname <>
date:        木, 05 1 2023 15:31:25 +0900
summary:     Initial commit
とすると、logと同じ内容が表示されます。

編集してコミット


次に、
$ echo "bbb" >> a.txt
で、コミットしているファイルを編集してみます。diffをとると、
$ sl diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,1 +1,2 @@
 aaa
+"bbb" <0D>
と表示されてbbbが追加されていることがわかります。Windowsなので、改行記号が\r\nになっており、0Dが追加で表示されているようです。

statusを表示してみると、

$ sl status
M a.txt
となり、変更されていると表示されます。

今回はsl commit -iにて、対話的なコミット画面を表示してみます。

$ sl commit -i
starting interactive selection
実行すると、
Select hunks to record - [x]=selected **=collapsed  c: confirm  q: abort  arrow keys: move/expand/collapse  space: deselect  ?: help
[x]    diff --git a/a.txt b/a.txt                                                                                                   
       1 hunks, 1 lines changed                                                                                                     

   [x]     @@ -1,1 +1,2 @@                                                                                                          
            aaa ^M                                                                                                                  
      [x]  +"bbb" ^M                                                                                                                
と表示されます(色は省略)。Mercurialのhg com -iや、git crecordと同じ操作感の画面です。部分コミットを簡単にできます。 今回は1箇所しか変更していないので、そのままcを押して、コミットします。

コミットログの表示


単にログを表示します。
$ sl log
changeset:   f4adbb569e88ed2127b9b79c0a88d22d396532aa  (@)
user:        yourname <>
date:        木, 05 1 2023 15:45:49 +0900
summary:     Update

changeset:   5bbaee36d524dc4b97c9ee5740cf6440a37ddfb5
user:        yourname <>
date:        木, 05 1 2023 15:31:25 +0900
summary:     Initial commit
のようになり、履歴がわかります。

--graphにてグラフ表示もできるようです。

$ sl log --graph
@  changeset:   f4adbb569e88ed2127b9b79c0a88d22d396532aa  (@)
│  user:        yourname <>
│  date:        木, 05 1 2023 15:45:49 +0900
│  summary:     Update
│
o  changeset:   5bbaee36d524dc4b97c9ee5740cf6440a37ddfb5
   user:        yourname <>
   date:        木, 05 1 2023 15:31:25 +0900
   summary:     Initial commit
単にslを実行すると、
$ sl
@  f4adbb569  100 seconds ago  >
│  Update
│
o  5bbaee36d  16 minutes ago  >
   Initial commit
と表示されます。

headの表示


headを表示してみます。分岐の先頭の一覧が表示されますが、今の時点では分岐がないので、
$ sl head
changeset:   f4adbb569e88ed2127b9b79c0a88d22d396532aa  (@)
user:        yourname <>
date:        木, 05 1 2023 15:45:49 +0900
summary:     Update
のように1つだけ表示されます。

prevコマンドで最初のコミットに戻ってみます。

$ sl prev
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[5bbaee] Initial commit

$ sl head
changeset:   f4adbb569e88ed2127b9b79c0a88d22d396532aa
user:        yourname <>
date:        木, 05 1 2023 15:45:49 +0900
summary:     Update
headは変わりません。slコマンドでは
$ sl
o  f4adbb569  13 minutes ago  >
│  Update
│
@  5bbaee36d  27 minutes ago  >
   Initial commit
@の場所が変化します。

分岐の作成


最初にa.txtに文字を追加します。
$ echo "ccc" >> a.txt
を実行し、
$ sl commit
にてコミットします。
$ sl head
changeset:   1cae689a8bab379edcc7e1c63c305f78d37d608a  (@)
user:        yourname <>
date:        木, 05 1 2023 16:00:24 +0900
summary:     Add ccc

changeset:   f4adbb569e88ed2127b9b79c0a88d22d396532aa
user:        yourname <>
date:        木, 05 1 2023 15:45:49 +0900
summary:     Update
となり、headが複数できていることがわかります。この表示はMercurialと同様です。

slを実行すると、

$ sl
@  1cae689a8  67 seconds ago  >
│  Add ccc
│
│ o  f4adbb569  15 minutes ago  >
├─╯  Update
│
o  5bbaee36d  30 minutes ago  >
   Initial commit
となります。罫線の幅を半角表示にするときれいに位置がそろうのですが、CSSでうまく書けなかったため、ずれたままで。

また、─╯ は2文字ですが、コマンドプロンプトウィンドウでは、重ねて表示されており、分岐した線のように見えます。 一方、WSL Terminalで当該文字列を表示すると重ならないです。

話はそれますが、 ╯ はUnicodeで256F、UTF-8でE2 95 AFです。

分岐で次に進む


まず、今の状態でsl prevを実行すると、
$ sl
o  1cae689a8  4 minutes ago  >
│  Add ccc
│
│ o  f4adbb569  18 minutes ago  >
├─╯  Update
│
@  5bbaee36d  33 minutes ago  >
   Initial commit
となり、最初のコミットに戻ってきます。

この位置では分岐があるのでnextを実行するとどうなるかというと、

$ sl next
commit 5bbaee36d524 has multiple children, namely:
(1) [f4adbb] Update
(2) [1cae68] Add ccc
which commit to move to [1-2/(c)ancel]?
というメッセージが出力され、どちらに進むか選ぶようになっています。

(1)側に進んでみると、

which commit to move to [1-2/(c)ancel]?  1
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[f4adbb] Update
と表示され、(1)側に移動できます。
$ sl
o  1cae689a8  6 minutes ago  >
│  Add ccc
│
│ @  f4adbb569  20 minutes ago  >
├─╯  Update
│
o  5bbaee36d  35 minutes ago  >
   Initial commit
となり、たしかに、f4adbb569 に移動できていることが確認できます。

隣の分岐に移動するには、

$ sl goto 1cae
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
でよさそうです。
$ sl
@  1cae689a8  9 minutes ago  >
│  Add ccc
│
│ o  f4adbb569  24 minutes ago  >
├─╯  Update
│
o  5bbaee36d  38 minutes ago  >
   Initial commit
となっており、移動できていることが確認できます。

ブランチのマージ


さきほど作成したブランチをマージします。Saplingではマージよりrebaseを使うように設計されているようですが (https://sapling-scm.com/docs/introduction/のCaveatsより)、 mergeコマンドはあるのでそれでマージしてみます。
$ sl merge
を実行すると、kdiff3をインストールしているためか、kdiff3が立ち上がって、コンフリクトを解消するよう指示が出ます。

手動でマージすると、

$ sl merge
merging a.txt
running merge tool kdiff3 for file a.txt
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
と表示され、マージができました。この段階ではコミットされておらず、
$ sl
@  1cae689a8  25 minutes ago  >
│  Add ccc
│
│ @  f4adbb569  39 minutes ago  >
├─╯  Update
│
o  5bbaee36d  54 minutes ago  >
   Initial commit
のように表示されます。@が2箇所に表示されます。
$ sl commit
でコミットすると、
$ sl
@    b84d24eda  15 seconds ago  >
├─╯  Merge
│ │
o │  f4adbb569  41 minutes ago  >
│ │  Update
│ │
│ o  1cae689a8  26 minutes ago  >
├─╯  Add ccc
│
o  5bbaee36d  55 minutes ago  >
   Initial commit
と表示され、めでたくマージできたことが確認できます。

マージを元に戻す


rebaseが推奨であるようなので、一旦これを元に戻してみます。

インタラクティブにできそうなので、-i付きで実行してみましたが、

$ sl undo -i
abort: interactive ui is not supported on Windows
となり残念ながら実行できません。-iなしで試してみると、
$ sl undo
undone to 木 1 05 16:09:49 2023 +0900, before commit
hint[undo-uncommit-unamend]: undoing commits discards their changes.
to restore the changes to the working copy, run 'sl revert -r b84d24eda1a8 --all'
in the future, you can use 'sl uncommit' instead of 'sl undo' to keep changes
hint[hint-ack]: use 'sl hint --ack undo-uncommit-unamend' to silence these hints

$ sl
@  1cae689a8  30 minutes ago  >
│  Add ccc
│
│ o  f4adbb569  44 minutes ago  >
├─╯  Update
│
o  5bbaee36d  59 minutes ago  >
   Initial commit
と表示され、マージ処理を元に戻せています。マージしたファイルを取得する方法もメッセージに書かれており、 消えていてもリビジョン(=コミットのハッシュ値)さえわかっていればrevertで戻せるようです。

試して見ると、

$ sl revert -r b84d24eda1a8 --all
reverting a.txt

$ sl diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,2 +1,3 @@
 aaa
+"bbb" <0D>
 "ccc"
となり、たしかにマージ処理したa.txtが戻ってきます。

さらにundoできるか試してみると、

$ sl undo
abort: uncommitted changes
となります。revertで戻したファイルが未コミットのファイルとなっており、この状態ではundoはできないようです。

rebaseにてブランチをマージ


先程はブランチのコミットを維持したままマージしましたが、今度はrebaseでマージしてみます。 枝を別の場所に継ぎ変えるということです。

今の状態は

$ sl
@  1cae689a8  38 minutes ago  >
│  Add ccc
│
│ o  f4adbb569  52 minutes ago  >
├─╯  Update
│
o  5bbaee36d  67 minutes ago  >
   Initial commit
となっています。ここで
$ sl rebase f4ad
abort: you must specify a destination (-d) for the rebase

$ sl rebase -r f4ad
abort: you must specify a destination (-d) for the rebase

$ sl rebase -r 1cae
abort: you must specify a destination (-d) for the rebase

$ sl rebase
abort: you must specify a destination (-d) for the rebase
としてみると、すべてエラーとなります。

ヘルプを見ると

sl rebase [-s REV | -b REV] [-d REV] [OPTION][-i]
と表示されるので、エラーメッセージの通りrebase先を-dで指定する必要があるようです。
sl rebase -r f4adbb569 -d 1cae689a8
rebasing f4adbb569e88 "Update"
merging a.txt
abort: must use on-disk merge for this rebase (hit merge conflicts in a.txt), but you have working copy changes
(commit, revert, or shelve them)
さきほどローカルのa.txtをマージ後のものに戻していたので、エラーとなってしまっています。
$ sl revert a.txt
で元に戻します(マージ後のローカルのa.txtの内容を破棄します)。

再度rebaseしてみます。

$ sl rebase -r f4adbb569 -d 1cae689a8
rebasing f4adbb569e88 "Update"
merging a.txt
hit merge conflicts (in a.txt); switching to on-disk merge
rebasing f4adbb569e88 "Update"
merging a.txt
running merge tool kdiff3 for file a.txt
f4adbb569e88 -> f292f8d2ac45 "Update"
今回もkdiff3が立ち上がるので、手動でマージすると、rebaseが完了します。
$ sl
o  f292f8d2a  88 seconds ago  >
│  Update
│
@  1cae689a8  49 minutes ago  >
│  Add ccc
│
o  5bbaee36d  78 minutes ago  >
   Initial commit
となり、一直線になりました。 ヘルプを読むとrebaseしたコミットを適用先にコピーし、さらにrebaseしたブランチを隠すという処理が行われているようです。
$ sl head
changeset:   f292f8d2ac45f92a9737cf4d2dd38be2e1a6fb11
user:        yourname <>
date:        木, 05 1 2023 16:47:58 +0900
summary:     Update
のように、headも1つになりました。コミット履歴が読みやすいので、マージよりもコミット履歴の管理としてはこの方が良いのかもしれません。 一方で、リビジョン番号は変わってしまうので、リビジョン番号を維持しておきたい場合はmergeのほうがよいかもしれません。 rebaseでも元のコミットは隠されているだけで残ってはいますが、コピーができてしまってどれとどれが同じコミットなのかを後から追いにくくなりそうですので、リビジョン番号が重要な場合はmergeでしょうか。 状況に合わせて適切な方法を利用することになりそうです。

コミット間の移動


これまでの説明で既に使用していますが、コミット間の移動は近くのコミットであればnextとprevで移動するのが簡単です。
$ sl next
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[f292f8] Update

$ sl
@  f292f8d2a  15 minutes ago  >
│  Update
│
o  1cae689a8  62 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit

$ echo ddd >> a.txt
$ sl commit

$ sl
@  da3ea5b13  22 seconds ago  >
│  Add ddd
│
o  f292f8d2a  15 minutes ago  >
│  Update
│
o  1cae689a8  63 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit

$ sl prev
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[f292f8] Update

$ sl
o  da3ea5b13  50 seconds ago  >
│  Add ddd
│
@  f292f8d2a  16 minutes ago  >
│  Update
│
o  1cae689a8  64 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit

操作の取り消しと再実行


なんらかの制限はあるようですが、操作の取り消し(undo)と再実行(redo)も簡単にできます。

先程の操作を元に戻していきます。

$ sl undo
undone to 木 1 05 17:03:41 2023 +0900, before prev

$ sl
@  da3ea5b13  81 seconds ago  >
│  Add ddd
│
o  f292f8d2a  16 minutes ago  >
│  Update
│
o  1cae689a8  64 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit
確かにprevコマンドを実行する前の状態に戻りました。さらに取り消すと、
$ sl undo
undone to 木 1 05 17:02:45 2023 +0900, before commit

$ sl
@  f292f8d2a  17 minutes ago  >
│  Update
│
o  1cae689a8  65 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit
dddを追加したコミットが消えました。もう一度実行すると、
$ sl undo
undone to 木 1 05 16:48:26 2023 +0900, before next

$ sl
o  f292f8d2a  18 minutes ago  >
│  Update
│
@  1cae689a8  65 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit
となり、参照している場所も戻りました。

今度はredoで一挙にundoをundoしてみます。

$ sl redo 10
undone to 木 1 05 17:05:19 2023 +0900, before undo

$ sl
@  f292f8d2a  19 minutes ago  >
│  Update
│
o  1cae689a8  67 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit
再実行はできましたが、残念ながら一括ではundo操作を戻せませんでした。
$ sl redo 2
undone to 木 1 05 17:04:52 2023 +0900, before undo

$ sl
@  da3ea5b13  5 minutes ago  >
│  Add ddd
│
o  f292f8d2a  21 minutes ago  >
│  Update
│
o  1cae689a8  69 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit
残りのundoした回数である2を指定しても1回再実行できるだけで引数の値には効果がないようです。再度redoすると、
$ sl redo
undone to 木 1 05 17:04:19 2023 +0900, before undo

$ sl redo
abort: nothing to redo

$ sl
o  da3ea5b13  6 minutes ago  >
│  Add ddd
│
@  f292f8d2a  21 minutes ago  >
│  Update
│
o  1cae689a8  69 minutes ago  >
│  Add ccc
│
o  5bbaee36d  Today at 15:31  >
   Initial commit
となり、undoする前に戻ってくることはできました。
You can run 'sl redo' multiple times to undo a series of 'sl undo' commands. Alternatively, you can explicitly specify the number of 'sl undo' commands to undo by providing a number as a positional argument.
とヘルプには書いてありましたが、できないようです。

コマンド一覧


slコマンドのヘルプ表示では表示されないコマンドを含めたコマンド一覧が
https://sapling-scm.com/docs/category/commands/
に載っています。