Scalar とは
大規模リポジトリを対象とした、リポジトリ容量最適化・コマンド高速化のための拡張機能の提供とgit configの自動設定を行うツールです。元々 Microsoft によって開発されていました (https://github.com/microsoft/scalar) が、Git 2.38よりメインストリームに取り込まれたことで同梱されるようになりました。
下記コマンドでScalarを利用することができます。
# 既存リポジトリでScalarを利用する場合 $ cd /path/to/repo $ scalar register # 新規でクローンする場合 $ scalar clone /path/to/repo
実際に、https://github.com/git/git のリポジトリを対象にScalarを利用するとなにが起きるのか今回は調べてみました。
`scalar register` するとどうなる?
既存のリポジトリに対して scalar regsiterをすると、git configに下記が追加されます。
scalar.repo=/Users/xxx/git maintenance.repo=/Users/xxx/git core.multipackindex=true core.preloadindex=true core.untrackedcache=true core.autocrlf=false core.safecrlf=false core.fsmonitor=true am.keepcr=true credential.https://dev.azure.com.usehttppath=true credential.validate=false gc.auto=0 gui.gcwarning=false index.threads=true index.version=4 merge.stat=false merge.renames=true pack.usebitmaps=false pack.usesparse=true receive.autogc=false feature.manyfiles=false feature.experimental=false fetch.unpacklimit=1 fetch.writecommitgraph=false fetch.showforcedupdates=false status.aheadbehind=false commitgraph.generationversion=1 log.excludedecoration=refs/prefetch/* maintenance.auto=false maintenance.strategy=incremental
主に最適化のための設定になりますが、改行コードの扱い、マージの挙動なども含まれていました。開発者によっては設定を戻す必要があるため、変更される項目については確認が必要です。
いくつか特徴的なものを上げると、
core.untrackedcache=true core.fsmonitor=true
では、2.37で追加されたFSMonitor というデーモン型のファイル管理システムを用いたgit statusの高速化が有効化されています。
github.blog
maintenance.repo=/Users/xxx/git maintenance.auto=false maintenance.strategy=incremental gc.auto=0 fetch.writecommitgraph=false
こちらは2.31に追加されたGitリポジトリの最適化をバックグランドで行う設定となっており、1時間毎にprefetch と commit-graphの生成(git statusなどの高速化)、1日毎に容量の最適化が行われるようになります。git gc や fetch でもともと行われていた最適化は止め、バックグラウンドで定期的に行うことにより高速化と最適化を両立しています。
github.blog
git maintenanceで行われるprefetchでは、ローカルのrefs/remoteは書き換えずfetchした最新情報を保持しており、次回fetch時にその情報を用いることで高速化しているようです。
prefetchされているときとされていないときのfech時間を計測してみましたが、最新までprefetchできているときは当たり前ですが待ち時間なくfetchできるようになっています。
# prefetchしない場合 $ time git fetch remote: Enumerating objects: 324817, done. remote: Counting objects: 100% (324817/324817), done. remote: Compressing objects: 100% (77849/77849), done. remote: Total 324817 (delta 244704), reused 324817 (delta 244704), pack-reused 0 Receiving objects: 100% (324817/324817), 194.56 MiB | 84.28 MiB/s, done. Resolving deltas: 100% (244704/244704), done. From /Users/xxx/git-bare * [new branch] master -> origin/master git fetch 12.36s user 1.26s system 142% cpu 9.587 total $ git show-ref 3dcec76d9df911ed8321007b1d197c1a206dc164 refs/remotes/origin/master # prefetchした場合 $ git show-ref 3dcec76d9df911ed8321007b1d197c1a206dc164 refs/prefetch/remotes/origin/master $ time git fetch From /Users/xxx/git-bare * [new branch] master -> origin/master warning: fetch normally indicates which branches had a forced update, but that check has been disabled; to re-enable, use '--show-forced-updates' flag or run 'git config fetch.showForcedUpdates true' git fetch 0.01s user 0.02s system 72% cpu 0.044 total $ git show-ref 3dcec76d9df911ed8321007b1d197c1a206dc164 refs/prefetch/remotes/origin/master 3dcec76d9df911ed8321007b1d197c1a206dc164 refs/remotes/origin/master
`scalar clone` するとどうなる?
通常のgit clone と、scalar cloneを比べてみました。
clone時間は約4分の1、clone後の.gitディレクトリは半分近くの容量で抑えられました。
# git clone % time git clone https://github.com/git/git.git Cloning into 'git'... remote: Enumerating objects: 335027, done. remote: Total 335027 (delta 0), reused 0 (delta 0), pack-reused 335027 Receiving objects: 100% (335027/335027), 200.78 MiB | 18.12 MiB/s, done. Resolving deltas: 100% (250551/250551), done. git clone https://github.com/git/git.git 16.06s user 3.46s system 102% cpu 19.112 total % du -sh git/.git 218M git/.git # scalar clone % time scalar clone https://github.com/git/git.git Initialized empty Git repository in /Users/xxx/git/src/.git/ warning: fetch normally indicates which branches had a forced update, but that check has been disabled; to re-enable, use '--show-forced-updates' flag or run 'git config fetch.showForcedUpdates true' remote: Enumerating objects: 473, done. remote: Counting objects: 100% (411/411), done. remote: Compressing objects: 100% (411/411), done. remote: Total 473 (delta 1), reused 0 (delta 0), pack-reused 62 Receiving objects: 100% (473/473), 1.95 MiB | 3.78 MiB/s, done. Resolving deltas: 100% (1/1), done. warning: fetch normally indicates which branches had a forced update, but that check has been disabled; to re-enable, use '--show-forced-updates' flag or run 'git config fetch.showForcedUpdates true' Updating files: 100% (474/474), done. branch 'master' set up to track 'origin/master'. Already on 'master' Your branch is up to date with 'origin/master'. scalar clone https://github.com/git/git.git 4.47s user 1.39s system 60% cpu 9.715 total % du -sh git/src/.git 92M git/src/.git
scalar cloneのリポジトリのconfigを確認したところブロブレスクローンで行われていました。各ブロブ情報はHEAD以外に必要なタイミングで取得する方式で、容量を抑えつつgit cloneを高速化し、コミットとツリー情報はあるためgit log には影響しないのが特徴なパーシャルクローンとなります。
github.blog
またsparse-checkoutも有効となっており、特定ディレクトリのみをcloneすることができるようになっています。モノリポで管理されているリポジトリにおいて開発者が担当するソースコードだけを手元に置くなどの用途のために使われています。
github.blog
実はscalar cloneするとプロジェクトディレクトリの下にsrcディレクトリが間に挟まるような構成となっています。これまでgitignoreで定義していたビルド結果やパッケージをGitリポジトリ外に置けるようにし、Gitの監視配下から外すことで最適化しているようです。
- repo
- ビルド結果などをここに置く
- src
- リポジトリの中身
- .git/
Scalarの注意点
便利に設定してくれるScalarですが、注意点がいくつかあります。
その一つがScalar推奨の設定がGit推奨でないため、一部コマンド実行時にWarningがでるようになります。Scalarによるものなのか、オペレーションによるものなのかが分かりづらいので、今後のアップデートでScalar利用時は関連するWarningがでなくなるといいなと思いました。
また、Scalar適用前に戻そうと思った場合に scalar unregister を行うのですが、こちらが
- git maintenance の定期実行の解除
- scalar reconfigure でバージョン更新にあわせてconfigの更新ができないようにscalar管理下から外れる
となっており、一度変更のあった git config についてはそのまま書き換わったままとなります。そのため、まずはお試しでと思う方については.git/configのバックアップを取っておくのをおすすめします。
最後に
Gitに新たに追加されたScalarについて、情報が少なく不明な点も多かったため、簡単ではありますがまとめてみました。参考になったら幸いです。今回調べていてGitの新機能や設定で便利なものが追加されていることがわかり、もっと早く知りたかった!と思うものが多々ありました。
開発において誰もが触るツールだからこそ、楽に最適化できるScalarは活用していければと思います。今回は調査だけでしたので、実際に大規模プロジェクトで利用してみての体感やその他Gitの活用・効率化などを今後公開できればと思っています!
ColoplTechについて
コロプラでは、勉強会やブログを通じてエンジニアの方々に役立つ技術や取り組みを幅広く発信していきます。
connpassおよびTwitterで情報発信していますので、是非メンバー登録とフォローをよろしくお願いいたします。
colopl.connpass.com
twitter.com
また、コロプラではゲームや基盤開発のバックエンド・インフラエンジニアを積極採用中です!
興味を持っていただいた方はぜひお気軽にご連絡ください。