git で特定の branch / tag だけを clone してイライラを減らす
はじめに
git
を使ってると、特定の branch や tag だけを clone
したくなることが稀によくある。たとえば docker コマンドを使っていてちょっと挙動が不可思議だったりするとソースを見に行くと思うが、そんな時にソースを根こそぎ clone
すると結構時間がかかってイライラする。イライラどころか何ならリポジトリがデカすぎて clone
に失敗する事すらある。(我が家のようにネットワーク環境が貧弱な場合
と言う訳で、そんな時にイライラを減らすために有用なコマンドやオプションをまとめてみた。(イライラしなくなるとは言ってない
まずは普通に clone してみる
比較のため、まずは普通に clone
してみる。
$ time git clone https://github.com/docker/cli.git
Cloning into 'cli'...
remote: Enumerating objects: 423695, done.
remote: Counting objects: 100% (8959/8959), done.
remote: Compressing objects: 100% (1596/1596), done.
remote: Total 423695 (delta 8086), reused 7714 (delta 7346), pack-reused 414736
Receiving objects: 100% (423695/423695), 181.86 MiB | 17.60 MiB/s, done.
Resolving deltas: 100% (219767/219767), done.
real 0m21.476s
user 0m30.640s
sys 0m4.145s
なかなかに遅い。
いや、実はこれでも我が家の環境よりは断然速い。
最初はくっそ遅い我が家の環境で比較して差を強調しようと思ったのだがのだが、ネットワークがあまりにもダメ過ぎて結果が安定しないので仕方なく EC2 上で試している関係で、それなりの速度は出ているんだと思う。
話が逸れた。以降これを改善していこうと思う。
branch を指定する
git clone
には -b
オプションがあるのでこれを使えば良さそうだ。
今回は手元の環境にインストールされている docker cli のバージョンが 24.0.7
だったので、それに合わせて 24.0
branch を取ってくる。
$ time git clone -b 24.0 https://github.com/docker/cli.git
Cloning into 'cli'...
remote: Enumerating objects: 423695, done.
remote: Counting objects: 100% (8959/8959), done.
remote: Compressing objects: 100% (1596/1596), done.
remote: Total 423695 (delta 8086), reused 7714 (delta 7346), pack-reused 414736
Receiving objects: 100% (423695/423695), 181.86 MiB | 15.34 MiB/s, done.
Resolving deltas: 100% (219767/219767), done.
real 0m23.687s
user 0m29.470s
sys 0m4.030s
ぜんぜん良さそうじゃなかった…
よくよくマニュアルを読むと、-b
では clone
そのものの挙動は変わらなくて、最後に checkout
する branch が変わるだけだった。そりゃあ速くはならんわな…
他の branch を clone しない
--single-branch
と言うオプションがある。これなら特定の branch のみを clone してくれるので、-b
と併用してみる。
$ time git clone -b 24.0 --single-branch https://github.com/docker/cli.git
Cloning into 'cli'...
remote: Enumerating objects: 82325, done.
remote: Counting objects: 100% (7856/7856), done.
remote: Compressing objects: 100% (1091/1091), done.
remote: Total 82325 (delta 7340), reused 6797 (delta 6765), pack-reused 74469
Receiving objects: 100% (82325/82325), 45.84 MiB | 19.02 MiB/s, done.
Resolving deltas: 100% (49599/49599), done.
real 0m6.311s
user 0m7.370s
sys 0m1.011s
それなりに速くなった。
履歴を持ってこない
--single-branch
だと、特定の branch の全ての過去履歴を持ってくる。過去の経緯とかまで調べたい時には役立つのだが、場合によってはそこまで必要ない。たとえば、手元の 24.0.7 に対応するソースだけ見られれば良い、といったような場合もあるだろう。
-b
には tag も指定できるんだがそれでもそこまでの履歴を持ってこようとするので、そんな時には --depth
オプションが役に立つ。
$ time git clone -b v24.0.7 --depth=1 https://github.com/docker/cli.git
Cloning into 'cli'...
remote: Enumerating objects: 3845, done.
remote: Counting objects: 100% (3845/3845), done.
remote: Compressing objects: 100% (3183/3183), done.
remote: Total 3845 (delta 584), reused 1926 (delta 361), pack-reused 0
Receiving objects: 100% (3845/3845), 6.29 MiB | 12.42 MiB/s, done.
Resolving deltas: 100% (584/584), done.
Note: switching to 'afdd53b4e341be38d2056a42113b938559bb1d94'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
real 0m2.273s
user 0m0.796s
sys 0m0.301s
めちゃめちゃ速い。履歴を一切持ってきてないのだから当たり前かもしれないが、とにかく速い。
見れば分かると思うが、履歴がちょっとだけ欲しい場合には --depth=10
とか指定すれば履歴を 10 件だけ持ってきてくれる。
また、上記では tag を指定したがもちろん branch の時に --depth=1
とか指定しても良い。
ちなみに、--depth
を指定すると --single-branch
がデフォルトになるので、わざわざ --single-branch
を指定する必要は無い。
出力がウザいんだが?
先程めっさ速かったのだが、出力がウザいと思った方も多いだろう。
tag を指定して clone
したので親切にも「branch が無いから detached HEAD だよ、危ないよ」と教えてくれているのだが、「そんなん分かっとるがな、大きなお世話や」と言う方もいるかもしれない。
あるいは、このコマンドはシェルスクリプトや Dockerfile
の中から実行されていて、ビルドし終わったらリポジトリ自体要らない、なんて場合もあるかもしれない。(割と見かける
そんな場合には advice.detachedHead
オプションを false
にすると良い。(実はさっきのログにも出ているが…
$ time git -c advice.detachedHead=false clone -b v24.0.7 --depth=1 https://github.com/docker/cli.git
Cloning into 'cli'...
remote: Enumerating objects: 3845, done.
remote: Counting objects: 100% (3845/3845), done.
remote: Compressing objects: 100% (3183/3183), done.
remote: Total 3845 (delta 584), reused 1926 (delta 361), pack-reused 0
Receiving objects: 100% (3845/3845), 6.29 MiB | 12.10 MiB/s, done.
Resolving deltas: 100% (584/584), done.
real 0m2.427s
user 0m0.979s
sys 0m0.328s
速さはそのままに、ウザさが軽減された。
あのウザい出力は常に要らない
オレ自身はあの出力はありがたいと思っているのだが(ウザいことによって detached HEAD であることを忘れずに済む)、あれは常に要らんと思っている方もいるかもしれない。
そんな方は config を変えてしまおう。(お勧めはしないが
$ git config --global advice.detachedHead false
$ time git clone -b v24.0.7 --depth=1 https://github.com/docker/cli.git
Cloning into 'cli'...
remote: Enumerating objects: 3845, done.
remote: Counting objects: 100% (3845/3845), done.
remote: Compressing objects: 100% (3183/3183), done.
remote: Total 3845 (delta 584), reused 1926 (delta 361), pack-reused 0
Receiving objects: 100% (3845/3845), 6.29 MiB | 10.31 MiB/s, done.
Resolving deltas: 100% (584/584), done.
real 0m2.469s
user 0m0.859s
sys 0m0.315s
これで毎回オプションを指定しなくてもウザくない。
ところで、git config
のマニュアルには advice.detachedHead
は git switch
と git checkout
に効くぜ的な事が書いてあるが、git switch
で例のメッセージを出力させるのは無理なんじゃないかと思う。知らんけど…
追加の branch が欲しくなった
最初 --single-branch
で持ってきたけど、他の branch も欲しくなる場合はあるだろう。たとえば、今使ってるのは 24.0 系列だから 24.0
branch だけ取ってきたけど最新の 27.0 系列だったらどうなってるか知りたいとか。
そんな時は remote set-branches
コマンドを実行すればよい。
$ git remote set-branches --add origin 27.0
--add
オプションに注意しよう。これで指定した branch も「追加で」認識されるので、これ以降普通に fetch
すると 27.0
branch も一緒に落ちてくる。
$ time git fetch
remote: Enumerating objects: 10586, done.
remote: Counting objects: 100% (5893/5893), done.
remote: Compressing objects: 100% (800/800), done.
remote: Total 10586 (delta 5467), reused 5208 (delta 5093), pack-reused 4693
Receiving objects: 100% (10586/10586), 6.09 MiB | 8.04 MiB/s, done.
Resolving deltas: 100% (7238/7238), completed with 1365 local objects.
From https://github.com/docker/cli
* [new branch] 27.0 -> origin/27.0
* [new tag] v25.0.0 -> v25.0.0
...量が多いので略...
* [new tag] v27.0.2 -> v27.0.2
* [new tag] v27.0.3 -> v27.0.3
real 0m3.009s
user 0m1.532s
sys 0m0.209s
あとはいつも通り git switch
して作業すればよい。
$ git switch 27.0
branch '27.0' set up to track 'origin/27.0'.
Switched to a new branch '27.0'
追加の tag が欲しくなった。
追加で欲しいのが tag であれば、fetch
で直接取ってこれる。
$ time git fetch --depth=1 origin tag v27.0.3
remote: Enumerating objects: 4023, done.
remote: Counting objects: 100% (4023/4023), done.
remote: Compressing objects: 100% (1669/1669), done.
remote: Total 2464 (delta 1453), reused 1319 (delta 645), pack-reused 0
Receiving objects: 100% (2464/2464), 2.66 MiB | 15.28 MiB/s, done.
Resolving deltas: 100% (1453/1453), completed with 1066 local objects.
From https://github.com/docker/cli
* [new tag] v27.0.3 -> v27.0.3
real 0m2.228s
user 0m0.893s
sys 0m0.118s
見ての通り、fetch
コマンドに origin tag v27.0.3
と言う引数を付けることで当該 tag のみ取ってこれる。
ちなみに、--depth=1
を忘れると指定した tag に関連する履歴を根こそぎ拾ってこようとして時間がかかるので注意が必要だ。
やっぱり全部の branch が欲しくなった
最初 --single-branch
で clone
したけどやっぱり全 branch 欲しくなる、なんてこともあるだろう。
そんな時も remote set-branches
コマンドを実行すればよい。
$ git remote set-branches origin "*"
今度は --add
オプションは指定していないが、branch の名前としてワイルドカード "*"
を指定したので全ての branch が根こそぎ認識される。
これ以降普通に fetch
すると全ての branch が落ちてくる。
$ time git fetch
remote: Enumerating objects: 18089, done.
remote: Counting objects: 100% (10022/10022), done.
remote: Compressing objects: 100% (1220/1220), done.
remote: Total 18089 (delta 9234), reused 9260 (delta 8785), pack-reused 8067
Receiving objects: 100% (18089/18089), 8.83 MiB | 22.44 MiB/s, done.
Resolving deltas: 100% (12382/12382), completed with 2265 local objects.
From https://github.com/docker/cli
* [new branch] 18.06 -> origin/18.06
* [new branch] 18.09 -> origin/18.09
...ものっそい量なので略...
* [new tag] v27.0.2 -> v27.0.2
* [new tag] v27.0.3 -> v27.0.3
real 0m4.012s
user 0m2.619s
sys 0m0.398s
やっぱり全部の履歴が欲しくなった
最初 --depth=1
で clone
したけどやっぱり全履歴欲しくなる、なんてこともあるだろう。
そんな時は fetch --unshallow
コマンドを実行すればよい。
$ time git fetch --unshallow
remote: Enumerating objects: 80591, done.
remote: Counting objects: 100% (80589/80589), done.
remote: Compressing objects: 100% (27277/27277), done.
remote: Total 78155 (delta 49881), reused 74743 (delta 46555), pack-reused 0
Receiving objects: 100% (78155/78155), 38.09 MiB | 20.45 MiB/s, done.
Resolving deltas: 100% (49881/49881), completed with 1734 local objects.
remote: Enumerating objects: 33, done.
remote: Total 33 (delta 0), reused 0 (delta 0), pack-reused 33
Unpacking objects: 100% (33/33), 4.08 KiB | 2.04 MiB/s, done.
From https://github.com/docker/cli
* [new tag] v18.06.0-ce-rc1 -> v18.06.0-ce-rc1
* [new tag] v18.09.0-ce-tp0 -> v18.09.0-ce-tp0
...量が結構多いので略...
* [new tag] v24.0.5 -> v24.0.5
* [new tag] v24.0.6 -> v24.0.6
real 0m9.216s
user 0m7.064s
sys 0m0.870s
これで、元々持ってきていた branch や tag に関する全ての履歴が取ってこられる。
おわりに
イライラ軽減コマンド/オプションについてまとめてみた。これが皆さんのイライラ軽減に役立てば幸いである。
それでは、よい git ライフを。
Discussion