Gitの高速化:パフォーマンス最適化の必須テクニック

クローンコストの削減、Git LFSの賢い活用、古い参照の整理、生成ファイルの無視、スパースチェックアウトの適用によりGitを高速化します。

Gitの高速化:パフォーマンス最適化の必須テクニック

Gitが遅い場合、通常は具体的な原因があります。履歴が多すぎる、追跡されていないファイルが多すぎる、大きなバイナリオブジェクト、高コストなファイルシステムスキャン、またはネットワークレイテンシです。Git自体を責める前に、どの操作が遅く、それが何を読み取りまたはダウンロードしようとしているのかを確認してください。

Gitのパフォーマンス最適化は、修正を症状に合わせると最も効果的です。遅いCIクローンには、巨大なワーキングツリーでの遅いgit statusとは異なる対策が必要です。

Gitのパフォーマンス低下の原因を理解する

一般的な原因から始めましょう:

  • 多くのファイルと参照を含む長い履歴。
  • Gitに直接コミットされた大きなバイナリファイル。
  • ワーキングツリーに無視されずに置かれているビルド出力、依存関係フォルダ、ログ。
  • 多くの古いリモート追跡ブランチとタグ。
  • リモートへの遅いネットワークリンク。
  • 新しいメンテナンスやスパースチェックアウトの改善が欠けている古いGitバージョン。

意図を持って遅いコマンドを実行してください。git cloneが遅い場合は、履歴のサイズとネットワーク転送を確認します。git statusが遅い場合は、ワーキングツリーのサイズ、無視されたファイル、ファイルシステムの動作を確認します。git fetchが遅い場合は、リモート参照、タグ、変更されたオブジェクトを確認します。

クローンとフェッチのコストを削減する

CI、デプロイジョブ、読み取り専用の検査では、完全な履歴は必要ないことがよくあります。

シャロークローンを使用します:

git clone --depth <数値> <リポジトリURL>

例えば、最後の10コミットのみをクローンする場合:

git clone --depth 10 https://github.com/example/repo.git

現在のコミットのみをビルドするCIジョブでは、--depth 1で十分なことがよくあります。開発者の作業では、完全なクローンの方が通常は予期せぬ問題が少ないです。なぜなら、深いgit log、古いタグのチェックアウト、一部のリベースなど、より多くの履歴を必要とするコマンドがあるからです。

すでにシャロークローンがあり、さらに履歴が必要な場合は、深くします:

git fetch --deepen=50 origin

または、完全なクローンに変換します:

git fetch --unshallow origin

部分的なデータが必要な場合、新しいGitバージョンでは、--filter=blob:noneなどの部分クローンフィルターもサポートされていますが、Gitホストとワークフローがそれらを適切にサポートしている場合にのみ使用してください:

git clone --filter=blob:none https://github.com/example/large-repo.git

大きなファイルを通常のGit履歴から除外する

大きなバイナリは、Gitを遅くする最も速い方法の一つです。画像、動画、アーカイブ、デザインファイル、モデルファイルは、圧縮や差分がうまくいかないことがよくあります。

リポジトリに本当に属する大きなアセットにはGit LFSを使用します:

git lfs install
git lfs track "*.psd"
git lfs track "assets/*.mp4"
git add .gitattributes
git commit -m "大きなアセットをGit LFSで追跡"

Git LFSは、追跡ルールが設定された後の将来のコミットに影響します。誰かがすでに大きなファイルを通常のGit履歴にコミットしている場合、現在のツリーから削除するだけでは不十分です。git lfs migrate importgit filter-repoなどのツールを使用した協調的な履歴書き換えが必要になる場合があります。

生成されたビルドアーティファクトについては、通常はLFSではなく、コミットしない方が良い答えです。代わりに.gitignoreに追加します:

node_modules/
dist/
coverage/
*.log

ローカル参照とオブジェクトをクリーンアップする

古いリモート追跡ブランチは乱雑さを増し、参照をリストまたは検査するコマンドを遅くする可能性があります。フェッチ中にそれらを整理します:

git fetch --prune

すでにマージされ、不要になったローカルブランチを削除します:

git branch --merged
git branch -d old-feature-branch

Gitにメンテナンスを実行させます:

git maintenance run

古いワークフローでは、git gcもまだ有用です:

git gc

必要な理由がわからない限り、積極的なクリーンアップコマンドは避けてください。例えば、reflogを期限切れにすると、悪いリセットからの回復が難しくなる可能性があります。

git statusを軽くする

git statusはワーキングツリーを検査する必要があります。プロジェクトディレクトリに数千の生成ファイルや依存ファイルが含まれている場合、ステータスがノイズだらけで遅くなる可能性があります。

Gitが考慮すべきでないファイルには.gitignoreを使用します。ファイルがすでに追跡されている場合、.gitignoreはGitがそれを追跡するのを止めません。最初にインデックスから削除する必要があります:

git rm --cached path/to/generated-file

ツリーの一部だけが必要な非常に大きなリポジトリでは、スパースチェックアウトが役立ちます:

git sparse-checkout init --cone
git sparse-checkout set services/api docs

これにより、選択したパスのみがワーキングツリーに保持されます。モノレポで有用ですが、チームは期待されるスパースパスを文書化して、開発者が必要なファイルを見逃さないようにする必要があります。

フェッチと統合を分離する

git pullはフェッチしてから、設定に応じてマージまたはリベースで変更を統合します。リポジトリが大きい場合やブランチが分岐している場合、最初にフェッチする方が明確なことがよくあります:

git fetch origin
git log --oneline HEAD..origin/main
git merge origin/main

これ自体でネットワーク転送が小さくなるわけではありません。ワーキングブランチを変更する前に制御を与えます。

実践的なポイント

短期間のジョブにはシャロークローン、大きなアセットにはGit LFS、生成ファイルには.gitignore、古い参照には整理、大きなツリーでサブセットのみが必要な場合にはスパースチェックアウトを使用してください。Gitを最新に保ちますが、リポジトリの破損が疑われない限り、git fsckなどの整合性ツールをパフォーマンス修正として使用しないでください。

Gitが遅いと感じたら、正確なコマンドと時間がどこで費やされているか(ネットワーク転送、オブジェクト処理、ワーキングツリースキャン)を書き留めてください。その詳細が通常、適切な最適化を示します。