Що робить git status:
- порівнює індекс з
HEAD- швидко, працює з хешами; - порівнює робочий каталог з індексом - для кожного відстежуваного файлу перевіряє метадані (
stat: розмір, час зміни, inode); - шукає невідстежувані файли - обходить усі каталоги й застосовує правила
.gitignore.
У репозиторії зі 300 тисячами файлів кроки 2 і 3 - сотні тисяч системних викликів на кожен status. А IDE й промпт оболонки викликають status постійно.
Прискорення:
1. fsmonitor - Git питає не файлову систему, а демон, що стежить за змінами:
git config core.fsmonitor true
Вбудований демон (macOS і Windows) підписується на події файлової системи, і status перевіряє лише файли, змінені з минулого разу. На Linux - через hook з Watchman.
2. Кеш невідстежуваних файлів:
git config core.untrackedCache true
Git запам'ятовує, які каталоги не змінювалися, і не обходить їх повторно. У поєднанні з fsmonitor ефект найбільший.
3. Менше файлів у робочому каталозі:
- sparse-checkout - найдієвіше для монорепозиторію;
- sparse index (
git sparse-checkout init --cone --sparse-index) - індекс зберігає цілі каталоги поза набором одним записом.
4. Версія індексу й багатопотоковість:
git config feature.manyFiles true # index.version=4, untrackedCache
git config index.threads true
5. scalar - утиліта, що постачається з Git і вмикає всі рекомендовані налаштування для великих репозиторіїв разом:
scalar clone https://github.com/acme/monorepo.git
scalar register # для існуючого клону
Вмикає частковий клон, sparse-checkout у режимі cone, fsmonitor, фонове обслуговування й низку налаштувань продуктивності.
Діагностика:
GIT_TRACE2_PERF=1 git status # де витрачається час
git status --untracked-files=no # чи справа в пошуку невідстежуваних
Типові причини поза Git:
- величезні ігноровані каталоги (
node_modules,vendor) - кеш невідстежуваних і fsmonitor допомагають; - антивірус на Windows, що сканує кожне звернення до файлу;
- мережеві файлові системи й bind mount у Docker на macOS.