git-replay を最低限の使い方で触ってみた

git-replay というコマンドが追加されたみたいなので触ってみた。とは言っても、自分はあんまり凝ったことはやらないので、細かいところまでは踏み込まずに最低限の使い方ができたらいいなってくらいの気持ちで触った。

github.blog

この記事には、こんな風に書いてある↓

git replay exists to address these challenges. It offers an alternative to git rebase that, in addition to being far more performant:

  • Can operate in bare repositories.
  • Can rebase branches other than the currently checked-out one (in non-bare repositories).
  • Can operate over multiple branches simultaneously. and much more.
  • git rebase よりもずっとパフォーマンスがいい
  • ベアリポジトリに対しても実行できる
  • 今チェックアウトしているブランチ以外のブランチをリベースできる
  • 複数のブランチを同時にリベースできる

ベアリポジトリ?

ベアリポジトリってなんだろう?と思って調べた。

実際のファイル(作業ディレクトリ)を持たずに .git の中身だけを持ってるリポジトリのことをベアリポジトリって呼ぶのか。へー。

普段の開発中に使ってるやつは作業ディレクトリを持ったノンベアリポジトリ。ベアリポジトリは、GitHubとかサーバーみたいに作業ディレクトリが必要ないところで使う用っぽい。

じゃ「ベアリポジトリに対しても実行できる」は僕は気にしなくて良さそう。

自分が git replay を使うときの目的

「複数のブランチを同時にリベースできる」ってのも、僕はあんまり使わなさそう。だから「replayだとそういうのもできるんだな」って頭に入れておくくらいでいいか。

「パフォーマンスがいい」も、これまで git rebase 使っててパフォーマンスが気になったことないし。「今チェックアウトしているブランチ以外のブランチをリベースできる」もあんまりやりたいと思ったことないな・・・。

なので、自分が git replay を使うときの目的は、・・・「ちょっと違う使い方をできる git rebase」くらいだな。

使ってみる

気が楽になったところで公式のドキュメントを眺めながら使ってみる。まだ、Experimentalなんだね。ふむふむ。

Git - git-replay Documentation

適当なツリーを準備してみよう。

準備

❯ mkdir try-replay
❯ cd try-replay

❯ git init
Initialized empty Git repository in (...)/try-replay/.git/

❯ git commit --allow-empty -m "A"
[main (root-commit) 2221dba] A

❯ git commit --allow-empty -m "B"
[main 3db0749] B

❯ git commit --allow-empty -m "C"
[main 967b63d] C

❯ git commit --allow-empty -m "D"
[main cadb435] D

❯ git switch -c hello 3db0749
Switched to a new branch 'hello'

❯ git commit --allow-empty -m "E"
[hello 996c85c] E

❯ git commit --allow-empty -m "F"
[hello 12fc98d] F

❯ git ls
* 12fc98d (HEAD -> hello) F
* 996c85c E
| * cadb435 (main) D
| * 967b63d C
|/
* 3db0749 B
* 2221dba A

こんな感じでいいか。ちなみに git lslog simple みたいな気持ちで、この記事を書くためにエイリアス登録しておいた。

❯ git config --list | grep alias.ls
alias.ls=log --graph --all --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s'

使ってみる

--onto でターゲットのブランチやコミットを指定して、その後ろにリプレイしたいレンジを指定するのか。いま、コミットツリーはこうなってるから

❯ git ls
* 12fc98d (HEAD -> hello) F
* 996c85c E
| * cadb435 (main) D
| * 967b63d C
|/
* 3db0749 B
* 2221dba A

mainをターゲットにして、helloをそこにつけかえてみよう。

❯ git replay --onto main main..hello
update refs/heads/hello 3de3e36e676090cca31a8ef1852f70c7584b8491 12fc98d2fc133b4cf40f1d0c525ee74a535dce17

ツリーは更新されずに、結果だけがアウトプットに出てくるってドキュメントに書いてあったので納得。いちおうツリーを確認しておこう。

❯ git ls
* 12fc98d (HEAD -> hello) F
* 996c85c E
| * cadb435 (main) D
| * 967b63d C
|/
* 3db0749 B
* 2221dba A

変わってない。でさっきのアウトプットを見たところ 3de3e3 のコミットが作成されているはずだから、確認してみようか。

❯ git branch sample 3de3e3

❯ git ls
* 3de3e36 (sample) F
* 1758427 E
* cadb435 (main) D
* 967b63d C
| * 12fc98d (HEAD -> hello) F
| * 996c85c E
|/
* 3db0749 B
* 2221dba A

想像してたとおりになった。

git update-ref --stdin とつなげてみようか

アウトプットは git update-ref --stdin に渡せるよって書いてあるのでやってみよう

❯ git replay --onto main main..hello | git update-ref --stdin

❯ git ls
* d6bd066 (HEAD -> hello) F
* eedec2f E
| * 3de3e36 (sample) F
| * 1758427 E
|/
* cadb435 (main) D
* 967b63d C
* 3db0749 B
* 2221dba A

ふむふむ。そうなるよね。

どう使うかなぁ?

Experimentalってこともあるけど、今のところは git rebase を使いそう。ただ、git rebaseHEAD を移動しちゃうから、それが嫌だなってときは git replay もいいのかな。

僕は使わないだろうなと思ったから触れなかったけど --onto の代わりに --advance ってオプションもあって、そっちでターゲットを指定すると、アウトプットではターゲットブランチが移動する出力になるみたい。さっきの例でいくと hello じゃなくて main ブランチが移動する感じ。

おもしろかった

Gitは、ちょこちょこ新しいコマンドがでてくるから、40歳を過ぎて「新しいものわざわざ覚えなくても、自分がいちど覚えて手に馴染んでいるものがあるからそれでなんとかなるやん」って状態をちょこっと手放そうとしてみる頭の体操にちょうどいいな。