2022年8月15日月曜日

Git で今のブランチ名を取得するコマンドの違いを確認してみた

Git で今いるブランチ名を確認する方法はいくつかあります。
そういう情報は検索すればいっぱい出てきますが、今回は以下の 4 つを比較しました。
git コマンドの出力を加工する方法も検索すると出てきますが、加工なんかしなくても取れるのでそういう系は今回は除外。

* git branch --show-current
* git rev-parse --abbrev-ref HEAD
* git symbolic-ref --short HEAD
* git name-rev --name-only HEAD

とりあえず、試すとこうです。
ただ単にコマンドを実行しただけではどれも同じに見えます。
以下で細かく確認をしていきます。
(本記事執筆時の筆者環境の git version は 2.37.1)
内部処理
まずは、GIT_TRACE で内部的に何をしているのかの違いを確認してみます。
GIT_TRACE は git コマンドのデバッグ用変数です。git コマンドが遅いとか挙動調べるのに使えるので覚えておくと便利です。
こちらもどれも built-in の呼び出しのみで差分なし。
ちなみにこれだと GIT_TRACE の挙動が分かりづらいので git fetch のトレースを貼っておきます。(実は git fetch が中どんな処理をしているのかが伺えます)
パフォーマンス
次は、パフォーマンスの比較をします。GIT_TRACE_PERFORMANCE で内部処理の各処理のパフォーマンスを出力できますが、今回はコマンド自体のパフォーマンスを比較したいのでベンチマーク用のツールを使用します。
今回は hyperfine を使いました。また計測環境は alpine コンテナ内にコピーしたリポジトリで行いました。(コンテナ内の git version は 2.36.2)
結果はこちら
name-rev を使ったものだけ少し遅い結果となりました。他は大体同じくらい。
バージョン
最後に各コマンドが使える Git のバージョンを確認しておきます。
比較的新しいサブコマンドやオプションだと古い環境では使えない可能性もあるので、選択する際の参考になると思います。

commandversion
git branch --show-current2.20
git rev-parse --abbrev-ref HEAD1.6.3
git symbolic-ref --short HEAD1.7.10
git name-rev --name-only HEAD1.5.3

--show-current が比較的新しめの機能でした。
他は今の最新バージョンが 2.37 なのを考えると誤差と言えると思います。
Detached
もう1個だけ確認して置きたいことがありました。 CI などでは Detached 状態で checkout されることがあるので、その場合の挙動を確認しておきましょう。


ここで大きな違いがでてきましたね。
表にまとめるとこうです。
command出力exit code
git branch --show-current0
git rev-parse --abbrev-ref HEADHEAD0
git symbolic-ref --short HEADfatal: ref HEAD is not a symbolic ref128
git name-rev --name-only HEADブランチ名0

symbolic-ref だとコマンドが失敗します。他はそれぞれ出力結果が違いますが、ブランチ名が取れるのは name-rev のみでした。name-rev がちょっと他より遅い理由がなんとなくわかりますね。
CI とかでも fetch はされてるはずなので name-rev ならブランチ名を取得できそうです。
(pull_request の場合は merge ブランチになってるので注意)

また、例えば1つ前のコミットを指してた場合は以下のように ~ 使った表現で出力される模様。
あと、Detached 状態からコミットしてどこのブランチにもいないような場合は「undefined」が出力されます。
まとめ
Detached 状態のときにどうするかで使うコマンドを選ぶと良さそうです。
ブランチ名を必ず取りたいなら name-rev を使うことになります。
Detached が稀で速度を気にするのであれば↓のように symbolic-ref を最初に試みるのがいいかもしれません。

git symbolic-ref --short HEAD 2>/dev/null || git name-rev --name-only HEAD

なんらかの文字列が入っていればよいのであれば rev-parse 、逆に空文字が良ければ branch --show-current ですね。--show-current が git version 2.20 以降でしか使えないのでそこは注意してください。(あとは --show-current の Detached 状態の挙動はバグの可能性もあるので、今後挙動が変わるかもしれません)

調べ始めたときは、対して違いはありませんでしたーってオチを予想してたのですが、割と調べてみてよかったなと思いました。
では。


0 件のコメント:

コメントを投稿