いつのまにかGitのshallow cloneが”Push”も"Pull"もできるように超進化していたよ! すごーい!

流行りに乗ってフレンズ用語を活用しようと思って、タイトルで力尽きたブログはこちらです。

はじめに

不向きと言われながらもgitでGBを超える巨大リポジトリを取り扱うことはあります。 そんなときの強い味方が Shallow Clone

これは任意の世代だけを持ってくるので、どうせ滅多に参照しない1年以上前の履歴とか持ってくる必要がない便利な機能です。

なんですが、最近まで私の中では「shallow clone(笑)」な印象でした。

というのも、Gitのshallow cloneには制約が多く、fetchが出来ないのでputもpushも使えずせいぜいがCIサーバでのビルド時くらいだろうと思ってました。

実際、昔は出来なかったし今でもブログとかでも何だかんだで古いものがヒットするから、同じ印象だった人もそれなりにいるんじゃないかな? と思います。

Facebookが改造したというMercurialのshallow cloneはfetchが出来るので、うらやましく思ったものです。

www.infoq.com

でも、実は、Git 1.9から変わってた!。下記のAtlassianの記事でもさりげなく言及されてました。さりげなさすぎるよ!

japan.blogs.atlassian.com

blogs.atlassian.com

1.9が出た当時だから2014年以降のgitはshallow clone後もfetchが出来ますが、その結果どうなるかはあまり明言された記事も見つからなかったので確認してみました。

基本的なpushとpull

元になるリポジトリの作成

まずは検証用のリポジトリを作ります。

$ echo "# sandbox-git_shallow-clone" >> README.md
$ git init
$ git add README.md
$ git commit -m "first commit"
$ git remote add origin https://github.com/koduki/sandbox-git_shallow-clone.git
$ git push -u origin master

以降の作業が分かりやすいように全履歴をもつ通常のリポジトリfull-repoとしてcloneします。

$ git clone git@github.com:koduki/sandbox-git_shallow-clone.git full-repo
$ cd full-repo/

full-repoにいくつかcommitをしてみます。

$ touch history.txt
$ git add history.txt
$ echo "history1" >> history.txt
$ git commit -m "history commit 1 from full-repo" -a
$ echo "history2" >> history.txt
$ git commit -m "history commit 2 from full-repo" -a
$ echo "history3" >> history.txt
$ git commit -m "history commit 3 from full-repo" -a
$ git push

当たり前ですが下記のように履歴が出ています。

$ git log --pretty=oneline
7539bfe549690c037c172aec11c1b764424ee101 history commit 3 from full-repo
886bbd29a664c388473494af38689b362a7adf34 history commit 2 from full-repo
f8024e169867ca6c2ce3731ede8c2f87de8841da history commit 1 from full-repo
17404e2207096399f2e15a7176665dd62f5f4821 first commit

shallow cloneリポジトリの作成とPush

続いて検証のためにshallow cloneをdepth=2くらいで、shallo-repoとして作成します。

$ git clone --depth 2 git@github.com:koduki/sandbox-git_shallow-clone.git shallow-repo
$ cd shallow-repo
$ git log --pretty=oneline
7539bfe549690c037c172aec11c1b764424ee101 history commit 3 from full-repo
886bbd29a664c388473494af38689b362a7adf34 history commit 2 from full-repo

ちゃんと2世代分だけがとれたことが確認できました。ではshallow cloneした側でも同様に適当なcommitをしてみます。

$ echo "history4" >> history.txt
$ git commit -m "history commit 4 from shallow-repo" -a
$ echo "history5" >> history.txt
$ git commit -m "history commit 5 from shallow-repo" -a
$ git log --pretty=oneline
3f1dcc459ab3e105d0e10fba007e1beb693ab277 history commit 5 from shallow-repo
4a034d35a5893150308a9bd73d07370cd5dc971b history commit 4 from shallow-repo
7539bfe549690c037c172aec11c1b764424ee101 history commit 3 from full-repo
886bbd29a664c388473494af38689b362a7adf34 history commit 2 from full-repo
$ git push

とりあえず、エラーもなくPushもできました。

full-repoとshallow-repoでの相互のpull & push

では元の全履歴を持ったfull-repoでpullできるかを確認します。

$ cd ../full-repo/
$ git log --pretty=oneline -n1
7539bfe549690c037c172aec11c1b764424ee101 history commit 3 from full-repo
$ git pull
$ git log --pretty=oneline
3f1dcc459ab3e105d0e10fba007e1beb693ab277 history commit 5 from shallow-repo
4a034d35a5893150308a9bd73d07370cd5dc971b history commit 4 from shallow-repo
7539bfe549690c037c172aec11c1b764424ee101 history commit 3 from full-repo
886bbd29a664c388473494af38689b362a7adf34 history commit 2 from full-repo
f8024e169867ca6c2ce3731ede8c2f87de8841da history commit 1 from full-repo
17404e2207096399f2e15a7176665dd62f5f4821 first commit

pullする事で、ちゃんとshallow cloneした側のコミット内容が取り込まれましたね?

当たり前ですがshallow cloneした側の履歴で上書きされたりせず、元の履歴もきちんと保持しています。

念のため、全履歴を持つfull-repoからshallow-repoへの反映も確認します。

$ echo "history6" >> history.txt
$ git commit -m "history commit 6 from full-repo" -a
$ git push
$ cd ../shallow-repo
$ git pull
$ git log --pretty=oneline
e94867ec121d779cc234441cd9045fa03494d2e1 history commit 6 from full-repo
3f1dcc459ab3e105d0e10fba007e1beb693ab277 history commit 5 from shallow-repo
4a034d35a5893150308a9bd73d07370cd5dc971b history commit 4 from shallow-repo
7539bfe549690c037c172aec11c1b764424ee101 history commit 3 from full-repo
886bbd29a664c388473494af38689b362a7adf34 history commit 2 from full-repo

問題なくcommitが反映されてますね。相互にcommitしあっても何の問題も無さそうですね。これなら他のブランチの修正もmasterマージ後に取り込める

まとめ

今回はgitのshallow cloneについて検証をしました。

正直「これが出来たらなぁ」と思ってた機能が3年近く前から実装されてたのは衝撃ですが、これは中々に便利がよさそうなので活用していきたいです。

ちなみに私の手元の環境では数十分cloneにかかってたのがshallowだと数分になりました。たのしー

しかし「git 巨大リポジトリ 対処」とかで調べても昔の情報ばかり出てくるのは残念。

それではHappy Hacking!