🗃️
git cloneを早くしたいんだよなぁ
モチベーション
デプロイメントパイプラインの中で、結構大きめのMonorepoをcloneしている。それが遅いのでどうにかしたい。
どうやら対象のリポジトリは33Gくらいあるっぽい。(通常のclone後)
環境
$ git -v
git version 2.42.0
$ scalar version
git version 2.42.0
対応
gitにはいろいろなcloneの仕方があり、軽くすることができる。詳細は参考に載せているリンクだったり、helpを見て欲しい。
$ git clone -h
usage: git clone [<options>] [--] <repo> [<dir>]
-v, --verbose be more verbose
-q, --quiet be more quiet
--progress force progress reporting
--reject-shallow don't clone shallow repository
-n, --no-checkout don't create a checkout
--bare create a bare repository
--mirror create a mirror repository (implies bare)
-l, --local to clone from a local repository
--no-hardlinks don't use local hardlinks, always copy
-s, --shared setup as shared repository
--recurse-submodules[=<pathspec>]
initialize submodules in the clone
--recursive[=<pathspec>]
alias of --recurse-submodules
-j, --jobs <n> number of submodules cloned in parallel
--template <template-directory>
directory from which templates will be used
--reference <repo> reference repository
--reference-if-able <repo>
reference repository
--dissociate use --reference only while cloning
-o, --origin <name> use <name> instead of 'origin' to track upstream
-b, --branch <branch> checkout <branch> instead of the remote's HEAD
-u, --upload-pack <path>
path to git-upload-pack on the remote
--depth <depth> create a shallow clone of that depth
--shallow-since <time>
create a shallow clone since a specific time
--shallow-exclude <revision>
deepen history of shallow clone, excluding rev
--single-branch clone only one branch, HEAD or --branch
--no-tags don't clone any tags, and make later fetches not to follow them
--shallow-submodules any cloned submodules will be shallow
--separate-git-dir <gitdir>
separate git dir from working tree
-c, --config <key=value>
set config inside the new repository
--server-option <server-specific>
option to transmit
-4, --ipv4 use IPv4 addresses only
-6, --ipv6 use IPv6 addresses only
--filter <args> object filtering
--also-filter-submodules
apply partial clone filters to submodules
--remote-submodules any cloned submodules will use their remote-tracking branch
--sparse initialize sparse-checkout file to include only files at root
--bundle-uri <uri> a URI for downloading bundles before fetching from origin remote
で、使うのが --filter=blob:none
と --no-checkout
オプション。
scalarという大規模リポジトリ向けのコマンドでcloneするときと同じclone方式になる。
実践
IntelliJだったらリポジトリでかいだろとういことで試していく。
$ time git clone git@github.com:JetBrains/intellij-community.git
Cloning into 'intellij-community'...
remote: Enumerating objects: 8641478, done.
remote: Counting objects: 100% (23050/23050), done.
remote: Compressing objects: 100% (8602/8602), done.
remote: Total 8641478 (delta 10917), reused 21922 (delta 9869), pack-reused 8618428
Receiving objects: 100% (8641478/8641478), 4.36 GiB | 8.64 MiB/s, done.
Resolving deltas: 100% (5147491/5147491), done.
Updating files: 100% (212804/212804), done.
git clone git@github.com:JetBrains/intellij-community.git 334.45s user 143.63s system 74% cpu 10:45.88 total
$ du -h -d 0 intellij-community/
6.0G intellij-community/
我が家のネットワークの問題もあると思うが、10分以上かかっている…
$ time git clone --filter=blob:none --no-checkout git@github.com:JetBrains/intellij-community.git
Cloning into 'intellij-community'...
remote: Enumerating objects: 6863068, done.
remote: Counting objects: 100% (18691/18691), done.
remote: Compressing objects: 100% (5920/5920), done.
remote: Total 6863068 (delta 9107), reused 17717 (delta 8203), pack-reused 6844377
Receiving objects: 100% (6863068/6863068), 733.09 MiB | 9.50 MiB/s, done.
Resolving deltas: 100% (3693568/3693568), done.
git clone --filter=blob:none --no-checkout 87.21s user 76.39s system 128% cpu 2:07.74 total
--filter=blob:none
--no-checkout
だと2分ちょい。
du -h -d 0 intellij-community/
954M intellij-community/
そりゃ軽いよねー。
ls -la intellij-community/
total 0
drwxr-xr-x@ 3 tenten0213 staff 96 10 19 19:19 .
drwxr-xr-x@ 3 tenten0213 staff 96 10 19 19:19 ..
drwxr-xr-x@ 11 tenten0213 staff 352 10 19 19:21 .git
--filter=blob:none
はHEADより過去のBlobを取得しないし、 --no-checkout
でHEADのBlobも取得しない。
じゃあどうやってデプロイメントパイプラインを流していくのかというと、必要となるディレクトリだけチェックアウトしていく。
本来はこんな感じでいっぱいディレクトリがあるわけなんだけど、絞ってjavaディレクトリだけチェックアウトしてみる。
$ ls intellij-community/
CODE_OF_CONDUCT.md getPlugins.sh notebooks
CONTRIBUTING.md idea platform
Dockerfile images plugins
LICENSE.txt installers.cmd python
NOTICE.txt intellij.idea.community.main.android.iml qodana.yaml
README.md intellij.idea.community.main.iml resources
RegExpSupport intellij.yaml resources-en
aether-dependency-resolver java spellchecker
bin jps test-log.properties
build json tests.cmd
build.txt jupyter tools
build.xml jvm uast
community-resources lib updater
docs license xml
getPlugins.bat native
一部のディレクトリだけチェックアウトするには git sparse-checkout
コマンドを使う。
こんな感じで初期化&欲しいディレクトリを追加してー
$ cd intellij-community
$ git sparse-checkout init --cone
$ git sparse-checkout add java
$ git sparse-checkout list
java
部分的なチェックアウトになるので、サイズも小さいし、21秒でチェックアウトできた。
$ time git checkout master
remote: Enumerating objects: 46218, done.
remote: Counting objects: 100% (19640/19640), done.
remote: Compressing objects: 100% (13979/13979), done.
remote: Total 46218 (delta 7823), reused 5873 (delta 5658), pack-reused 26578
Receiving objects: 100% (46218/46218), 29.14 MiB | 6.88 MiB/s, done.
Resolving deltas: 100% (14452/14452), done.
Updating files: 100% (49454/49454), done.
Already on 'master'
Your branch is up to date with 'origin/master'.
git checkout master 5.14s user 7.63s system 59% cpu 21.399 total
$ ls java
compiler java-analysis-api java-frontback-tests java-psi-api jsp-base-openapi mockJDK-1.8 structuralsearch-java
debugger java-analysis-impl java-impl java-psi-impl jsp-openapi mockJDK-1.9 testFramework
execution java-features-trainer java-impl-inspections java-runtime jsp-spi openapi typeMigration
ide-customization java-frontback-impl java-impl-refactorings java-structure-view manifest performancePlugin
ide-resources java-frontback-psi-api java-indexing-api java-tests mockJDK-1.4 plugin
idea-ui java-frontback-psi-impl java-indexing-impl jdkAnnotations mockJDK-1.7 remote-servers
こんな感じで、欲しいディレクトリだけチェックアウトしていけば巨大なmonorepo全体をチェックアウトするより早くすむ、はず。
参考
-
https://git-scm.com/docs/scalar
- 大規模なリポジトリ用のコマンドなんかも用意されている
- gitコマンドでclone部分は再現できるので、利用しなかった
- 大規模なリポジトリ用のコマンドなんかも用意されている
- https://speakerdeck.com/yuukiyo/trends-in-development-methodology-from-the-latest-git-updates
- https://qiita.com/taquaki-satwo/items/bf8393dc9707639bea4f
Discussion