ロゴ画像

Git2.43リリース: repackに--filter(-to)が追加された

Git2.43リリース

機能・特徴に関する公式ハイライトはこちら

git repackの新しい特徴

repackの新しい特徴を知るためには、「そもそもrepackって?」から始まり、さらにrepackを知るためには「シャロークローン」、「パーシャルクローン」、さらにさらに「 blobtree 」を知る必要があり、もろもろ掘り下げる必要があるので、ひとつづつ紹介して何が新しくなったのかまとめようと思う。

git repackとは??

サイズを小さく取得するという手段として、git clone時にシャロークローン、パーシャルクローンを使うことで小さく取得することが可能

git repackを使うことで、git clone(フルクローン)後でもシャロークローンやパーシャルクローンと同じ状態に持っていける

フルクローンについて

シャロークローン

パーシャルクローン

blobtree を事前に理解する必要がある

こちらの記事「コミットはスナップショットであり差分ではない」を読めばいいのですが、必要な箇所のみを、かいつまんで再紹介します。

要約してしまうと

となります。 例として、このシステムのREADMEを見てみます。

``


% git rev-parse HEAD:README.md                                         
225b6d3cd5af3aa15113dc3c2f87a377fed2a931

% git cat-file -t 225b6d3cd5af3aa15113dc3c2f87a377fed2a931
blob

% git cat-file -p 225b6d3cd5af3aa15113dc3c2f87a377fed2a931 | head -n 10
## Getting Started

```bash
npm install
npm run dev

上記は、 git rev-parse HEAD:README.md により、「HEADのREADME.md」の最新commit hashを取得してます。 取得されたcommmit hash OID(ObjectID)である 225b6d3cd5af3aa15113dc3c2f87a377fed2a931git cat-file -t 225b6d3cd5af3aa15113dc3c2f87a377fed2a931 によって blob だと判明しました。

blobはファイルの内容を表現するので、 git cat-file -p 225b6d3cd5af3aa15113dc3c2f87a377fed2a931 によって中身を確認しますが、表示が多すぎるので | head -n 10 で10行に制限してます。 最終的に最新commit hashのREADMEの中身冒頭10行が表示されました。


次に tree についても追ってみます。

% git rev-parse HEAD^{tree}
22ca9eb1546b28612dafb97100fd2c87464fe830

% git cat-file -p 22ca9eb1546b28612dafb97100fd2c87464fe830 
100644 blob a8cdd12f5d52f695f7acc1f06a9c10e24bbe0038	.eslintrc.json
100644 blob d13d6afc4794ee444a1ba2bb3a54a8d029f48a45	.gitignore
100644 blob 225b6d3cd5af3aa15113dc3c2f87a377fed2a931	README.md
040000 tree 9f3452fcd101334fcebd089e430eb3a082b662ac	app
040000 tree 69e5504765955f548d679fee1dd9a55729fa091a	components
040000 tree 1408e6b21febdd96bc1e6f0680c31644a93137e5	interfaces
040000 tree 064be88dc384cbdbf60929023998325daf4f4e2f	lib
040000 tree b6d1d25b3c2abd1b97fb3462ea1dc6fea88aa5a3	md_template
100644 blob 767719fc4fba59345ae29e29159c9aff270f5819	next.config.js
100644 blob b7724524df7b8c9c155d403356bd02415eaf89cf	package-lock.json
100644 blob dbe767dc2e8fbbf3fc1443335da06ab39e7f9a84	package.json
040000 tree 5797d987fbc582ae5e5c6241e39d1b11b7354f16	prisma
040000 tree e1f989786432ba20b6ba5e9b95cc33e6c312f202	public
100644 blob eb0b41d94d58fc5fb1e745951191c9e79b12e2d0	tsconfig.json
040000 tree 27860a5b8e5308e39c5393a1504d6bccd5a42dfc	types

上記は、 git rev-parse HEAD^{tree} により、このシステムのHEAD^treeでOIDである 22ca9eb1546b28612dafb97100fd2c87464fe830 を取得してます。

次に取得されたOIDを git cat-file -p 22ca9eb1546b28612dafb97100fd2c87464fe830 にかけることで、この tree が持つObjectの一覧が表示されました。

上記の中には、先ほど blob の説明にも使った 225b6d3cd5af3aa15113dc3c2f87a377fed2a931 が表示されてます。blobはファイルの中身です。

git cat-file -p 225b6d3cd5af3aa15113dc3c2f87a377fed2a931 することでREADMEの中身が確認できます。

このように tree はディレクトリ(tree)とファイル(blob)の一覧とそのOIDが確認できます。


blob はファイル内容、 tree はディレクトリと理解した上で、元の話「パーシャルクローン」に戻ります。

パーシャルクローンは git clone のoption --filter を使うことで実現できます。 例えば git clone --filter=blob:none <git url> とすることで、ブロブレスクローンとなり、コミットとツリーのみをダウンロードし、 git checkout を行ったコミットのブロブだけをダウンロードすることができます。 Head以外のblobは取得しないので、最新でbuildしたいだけといった用途に向いている。

git clone --filter=tree:0 とすることで、HEADの全データは取得されるが、履歴のtreeとblobは取得されません。履歴の長いrepositoryに有効です。 git logなど実行するとtreeが取得される。開発には非推奨で、一度buildして履歴だけ参照したい用途に有効。

リポジトリの履歴が多く、大きなブロブがたくさんあるような場合は、パーシャルクローンを使うことで git clone の時間を大幅に短縮することができます。

git repack使ってみる

もろもろ理解した上で、改めて、git repackしてみる。

ただし、以下のように状況によって .git/objects/pack の中身が異なります。

ケース1の人が積み上げてpushした履歴やら歴代オブジェクトがpackの中に圧縮されて詰まってます。

% git verify-pack -v .git/objects/pack/pack-xxx.pack
fdbccb2cec890853f54ae13e5f4175d26d8d4b11 commit 212 144 12
5a30c05bf4924cd7ca793216fdac371ec52638f7 tree   555 497 156
a8665a11ae22a9b3a091761688f13f68e77fb3c4 tree   31 44 653 1 5a30c05bf4924cd7ca793216fdac371ec52638f7
34f7b27c5a542950c9f4984d7f48d93f7a059dff tree   298 273 697
3d8f2fc1c3068e6d6197a8ab9b8b6033e370a71f tree   55 70 970 1 34f7b27c5a542950c9f4984d7f48d93f7a059dff
9a478a11aee2b07751d2fb1555eb07df4e1d33fc blob   384 282 1040
・・・

git verify-pack -v .git/objects/pack/pack-xxx.pack でpackファイルの中を確認できます。

要は、ケース2の人はもう圧縮されているのですが、履歴を積み上げてきたケース1の人はオブジェクトが羅列され、packが空っぽなので、 git repack で圧縮して軽くしよう!ということです。

現状、ケース1の人のobjectsはこうなってます。

% ls -ltr .git/objects 
pack <-空っぽ
info <-空っぽ
9d <-オブジェクトハッシュが入ってる
71 <-オブジェクトハッシュが入ってる
9b <-オブジェクトハッシュが入ってる
73 <-オブジェクトハッシュが入ってる
82 <-オブジェクトハッシュが入ってる
2e <-オブジェクトハッシュが入ってる
15 <-オブジェクトハッシュが入ってる
0b <-オブジェクトハッシュが入ってる
・・・

git repack してみる

% git repack -Ad
Enumerating objects: 718, done.
Counting objects: 100% (718/718), done.
Delta compression using up to 8 threads
Compressing objects: 100% (613/613), done.
Writing objects: 100% (718/718), done.
Total 718 (delta 337), reused 0 (delta 0), pack-reused 0

-A オプションを使用すると、パックされていないすべてのオブジェクトが1つのパックにまとめられます。-d オプションを使用すると、新しく作成されたパックファイルが既存のパックファイルを置き換える場合、既存のパックファイルが削除されます。

コマンド結果見てみる

 % ls .git/objects 
d8
pack
d7
info

% ls .git/objects/pack
pack-7f2c42314cebbe7a4e2dbe63ba766c61617e8154.pack
pack-7f2c42314cebbe7a4e2dbe63ba766c61617e8154.idx

packファイルが作られ、大半のオブジェクトdirは消えた。 (残ったdirはなんだろ???)

とりあえず、.gitは

% du -sh .git
3.5M	.git

↓

% du -sh .git
456K	.git

ここまで減った ケース2の途中からクローンした人と大体同じになった。

% du -sh .git
404K	.git

新しい特徴とは??

前置き長かったが、2.43の新特徴とは?

--filter--filter-to のoptionが使えるようになったみたいです。

git repack -ad --filter='blob:limit=1m' \
 --filter-to=../backup.git/objects/pack/pack

つまり、 cit clone --filter=blob:none--filter=tree:0 がフルクローン後でもrepackで可能になったということみたいです。

ちな --filter-to はpack結果ファイルの格納場所の指定です。

また、シャロークローンの --depth はもともと使えました。今回はパーシャルクローンと同等の --filter が追加されましたということでした。

まとめ

実際に手で検証しながら把握しているつもりですが。Gitに精通しているわけではないため、間違っていたら申し訳ないです。

参考文献

戻る