Способы улучшения производительности git status

У меня есть репо 10 ГБ на машине с Linux, которая находится на NFS. Первый раз git status занимает 36 минут и последующие git status занимает 8 минут. Кажется, Git зависит от ОС для кэширования файлов. Только первый git такие команды, как commit, status это включает в себя упаковку / переупаковку всего репо, очень большое время занимает огромное репо. Я не уверен, что вы использовали git status на таком большом репо, но кто-нибудь сталкивался с этой проблемой?

я пытался git gc, git clean, git repack но время все равно / почти то же самое.

Помогут ли субмодули или какие-либо другие концепции, такие как разбиение репо на более мелкие? Если это так, что лучше для разделения большого репо. Есть ли другой способ улучшить время, затрачиваемое на команды git в большом репо?

15 ответов

Решение

Чтобы быть более точным, git зависит от эффективности lstat(2) системный вызов, так что настройка таймаута кэша атрибутов вашего клиента может помочь.

Руководство по git-update-index - по сути, ручной режим для git-status - описывает, что вы можете сделать, чтобы облегчить это, используя --assume-unchanged флаг, чтобы подавить его нормальное поведение и вручную обновить пути, которые вы изменили. Вы даже можете запрограммировать свой редактор на сброс этого флага каждый раз, когда вы сохраняете файл.

Альтернатива, как вы предлагаете, состоит в том, чтобы уменьшить размер вашей проверки (размер упаковочных файлов здесь не вступает в игру). Возможные варианты: редкая проверка, субмодули или инструмент репо Google.

(Есть ветка списка рассылки об использовании Git с NFS, но она не отвечает на многие вопросы.)

Я также вижу эту проблему в большом проекте, совместно используемом через NFS.

Мне потребовалось некоторое время, чтобы обнаружить флаг -uno, который можно присвоить как git commit, так и git status.

Этот флаг отключает поиск неотслеживаемых файлов. Это значительно уменьшает количество операций NFS. Причина в том, что для того, чтобы git обнаружил неотслеживаемые файлы, он должен искать во всех подкаталогах, поэтому, если у вас много подкаталогов, это повредит вам. Отключая git от поиска неотслеживаемых файлов, вы исключаете все эти операции NFS.

Объедините это с флагом core.preloadindex, и вы сможете получить разумную производительность даже на NFS.

Попробуй git gc. Также может помочь git clean.

ОБНОВЛЕНИЕ - Не уверен, откуда пришло отрицательное голосование, но руководство git определенно заявляет:

Запускает ряд служебных задач в текущем репозитории, таких как сжатие версий файлов (для уменьшения места на диске и увеличения производительности) и удаление недоступных объектов, которые могли быть созданы из предыдущих вызовов git add.

Пользователям рекомендуется запускать эту задачу на регулярной основе в каждом хранилище, чтобы поддерживать хорошее использование дискового пространства и хорошую производительность.

Я всегда замечаю разницу после запуска git gc, когда состояние git медленное!

ОБНОВЛЕНИЕ II - Не уверен, как я пропустил это, но OP уже попробовал git gc и git clean. Клянусь, этого изначально не было, но я не вижу никаких изменений в правках. Простите за это!

Если в вашем git repo интенсивно используются подмодули, вы можете значительно повысить производительность git status, отредактировав файл конфигурации в каталоге.git и установив ignore = dirty на любых особенно больших / тяжелых подмодулях. Например:

[submodule "mysubmodule"]
url = ssh://mysubmoduleURL
ignore = dirty

Вы потеряете удобство напоминания о том, что в любом из подмодулей есть незакрепленные изменения, о которых вы, возможно, забыли, но вы все равно сохраните основное удобство - знать, когда подмодули не синхронизированы с основным репо. Кроме того, вы все равно можете изменить свой рабочий каталог на сам подмодуль и использовать в нем статус git, как обычно, чтобы увидеть больше информации. Смотрите этот вопрос для более подробной информации о том, что означает "грязный".

Производительность статуса git должна улучшиться с Git 2.13 (2 квартал 2017 года).

Смотрите коммит 950a234 (14 апреля 2017 г.) Джеффа Хостетлера ( jeffhostetler )
(Объединено Юнио С Хамано - gitster - в коммите 8b6bba6, 24 апреля 2017 г.)

> string-list: использовать ALLOC_GROW макрос при перехвате string_list

использование ALLOC_GROW() макрос при восстановлении string_list массив, а не просто увеличить его на 32.
Это оптимизация производительности.

Во время статуса на очень большом репо, и есть много изменений, значительный процент от общего времени выполнения тратится на перераспределение wt_status.changes массив.

Это изменение уменьшает время в wt_status_collect_changes_worktree() от 125 до 45 секунд в моем очень большом хранилище.


Кроме того, Git 2.17 (Q2 2018) представит новую трассировку для измерения времени, потраченного на операции с индексами.

См. Коммит ca54d9b (27 января 2018 г.) Нгуен Тай Нгук Дуй ( pclouds)
(Объединено Юнио С Хамано - gitster - в коммите 090dbea, 15 февраля 2018 г.)

trace: измерить, где время тратится в индексных операциях

Все известные блоки тяжелого кода измеряются (кроме доступа к объектной базе данных). Это должно помочь определить, эффективна ли оптимизация или нет.
Неоптимизированный git-статус даст что-то вроде ниже:

0.001791141 s: read cache ...
0.004011363 s: preload index
0.000516161 s: refresh index
0.003139257 s: git command: ... 'status' '--porcelain=2'
0.006788129 s: diff-files
0.002090267 s: diff-index
0.001885735 s: initialize name hash
0.032013138 s: read directory
0.051781209 s: git command: './git' 'status'

Тот же Git 2.17 (Q2 2018) улучшается git status с:

revision.c: уменьшить количество запросов к объектной базе данных

В mark_parents_uninteresting() мы проверяем наличие объектного файла, чтобы увидеть, следует ли нам рассматривать коммит как проанализированный. В результате устанавливается бит "parsed" в коммите.

Изменить условие только для проверки has_object_file() если результат изменит разобранный бит.

Когда локальная ветвь отличается от своей вышестоящей ссылки, " git status "будет вычислять счет вперед / назад.
Это использует paint_down_to_common() и хиты mark_parents_uninteresting(),

На копии репозитория Linux с локальным экземпляром "master" за удаленной веткой " origin/master "~60000 коммитов, мы находим производительность" git status "с 1,42 секунды до 1,32 секунды, при относительной разнице -7,0%.

git config --global core.preloadIndex true

Сделал работу за меня. Проверьте официальную документацию здесь.

В нашей кодовой базе, где мы имеем где-то в диапазоне 20 - 30 подмодулей,
git status --ignore-submodules
ускорил дело ради меня. Обратите внимание, что это не будет сообщать о статусе субмодулей.

Что-то, что еще не было упомянуто, - это активировать кэш файловой системы на компьютерах с Windows (файловые системы linux совершенно разные, и git был оптимизирован для них, поэтому, вероятно, это помогает только для Windows).

git config core.fscache true


В крайнем случае, если git все еще работает медленно, можно отключить проверку времени модификации, так что git должен выяснить, какие файлы изменились.

git config core.ignoreStat true

НО: измененные файлы должны быть добавлены самим разработчиком git add, Git не находит изменений сам.

источник

В Git 2.40 (1 квартал 2023 г.) сообщение с советом, данное "" ( manman ) , когда перечисление неотслеживаемых путей занимает много времени, было обновлено.

Он лучше иллюстрирует все параметры конфигурации, которые вы можете применить, чтобы получить более быстрый/быстрый .

См. коммит ecbc23estatus (30 ноября 2022 г.) Руди Ригота ( rudyrigot).
(Объединено Junio ​​C Hamano -- gitster-- в коммите f3d9bc8, 19 декабря 2022 г.)

: модернизируйте совет git-status "медленные неотслеживаемые файлы"

Подписал: Руди Риго

( ) может быть медленным при наличии большого количества неотслеживаемых файлов и каталогов, поскольку Git должен выполнять поиск по всему рабочему дереву, чтобы перечислить их.
Когда он слишком медленный, Git печатает совет с истекшим временем поиска и предложением отключить поиск с помощью параметра.
Это предложение также содержит предупреждение, которое может отпугнуть некоторых пользователей.

Однако в эти дни,-unoне единственный вариант.
Git может сократить время, затрачиваемое на перечисление неотслеживаемых файлов, кэшируя результаты предыдущих вызовов, когдаcore.untrackedCacheиcore.fsmonitorфункции включены.

Обновите справочную страницу, чтобы объяснить эти параметры конфигурации, и обновите рекомендации, чтобы предоставить более подробную информацию о текущей конфигурации и обратиться к обновленной документации.

теперь включает в свою справочную страницу :

НЕОТСЛЕЖИВАЕМЫЕ ФАЙЛЫ И ПРОИЗВОДИТЕЛЬНОСТЬ

может быть очень медленным в больших рабочих деревьях, если/когда ему нужно искать неотслеживаемые файлы и каталоги.

Существует множество параметров конфигурации, позволяющих ускорить это, либо избегая работы, либо используя кешированные результаты предыдущих команд Git.
Не существует единого оптимального набора настроек, подходящего для всех.

Мы перечислим сводку соответствующих параметров, чтобы помочь вам, но прежде чем перейти к списку, вы можете запустить снова, потому что ваша конфигурация может уже кэшировать результаты, поэтому последующие запуски могут быть быстрее.

  • The --untracked-files=noфлаг илиstatus.showUntrackedfiles=falseconfig (оба варианта см. выше): укажите, что не следует сообщать о неотслеживаемых файлах. Это самый быстрый вариант. не будет перечислять неотслеживаемые файлы, поэтому вам нужно помнить, создаете ли вы какие-либо новые файлы и вручнуюgit addих.

  • advice.statusUoption=false(видетьgit config): установка этой переменной вfalseотключает предупреждающее сообщение, когда перечисление неотслеживаемых файлов занимает более 2 секунд. В большом проекте это может занять больше времени, и пользователь может уже принять компромисс (например, использование «-uno» может быть неприемлемым вариантом для пользователя), и в этом случае нет смысла выдавать предупреждающее сообщение, и в таком случае лучше отключить предупреждение.

  • (видеть): включить функцию неотслеживаемого кеша и искать только те каталоги, которые были изменены с момента предыдущей команды.
    Git запоминает набор неотслеживаемых файлов в каждом каталоге и предполагает, что если каталог не был изменен, то и набор неотслеживаемых файлов внутри не изменился.

    Это намного быстрее, чем перечисление содержимого каждого каталога, но все же не без затрат, потому что Git все еще должен искать набор измененных каталогов. Неотслеживаемый кеш хранится в.git/indexфайл. Сокращение затрат на поиск неотслеживаемых файлов немного компенсируется увеличением размера индекса и стоимостью его обновления. Это сокращение времени поиска обычно стоит дополнительного размера.

  • core.untrackedCache=trueиcore.fsmonitor=trueилиcore.fsmonitor=<hook_command_pathname>(видетьgit update-index): включить функции неотслеживаемого кеша и FSMonitor и выполнять поиск только в тех каталогах, которые были изменены с момента выполнения предыдущей команды.

    Это быстрее, чем использовать только неотслеживаемый кеш, потому что Git также может избежать поиска измененных каталогов.
    Git должен только перечислить точный набор каталогов, которые недавно изменились. Хотя функцию FSMonitor можно включить без неотслеживаемого кеша, в этом случае преимущества значительно уменьшаются.

Обратите внимание, что после включения функций неотслеживаемого кеша и/или FSMonitor может пройти некоторое время.git statusкоманды для разогрева различных кешей, прежде чем вы увидите улучшенное время команд.
Это нормально.

Хорошо, в это довольно трудно поверить, если бы я не видел своими глазами ... У меня была очень ПЛОХАЯ производительность на моем новом рабочем ноутбуке, git statusзанимает от 5 до 10 секунд даже для самого глупого репозитория. Я попробовал все советы в этой теме, потом заметил, что git logбыл медленным, поэтому я расширил свой поиск общей медлительности новой установки git и нашел это https://github.com/gitextensions/gitextensions/issues/5314#issuecomment-416081823

в отчаянии я попытался обновить графический драйвер своего ноутбука и ...

Святой Санта-Клаус дерьмо ... это сделало свое дело!

...для меня тоже!

Таким образом, очевидно, что драйвер видеокарты здесь имеет какое-то отношение ... трудно понять, почему, но теперь производительность "такая, как ожидалось"!

Остатки index.lock файлы

git status может быть патологически медленным, когда у вас есть остатки index.lock файлы.

Особенно это случается, когда у вас git submodules, потому что тогда вы часто не замечаете такие оставшиеся файлы.

Резюме: Бегиfind .git/ -name index.lock, и удалите оставшиеся файлы, убедившись, что они действительно не используются какой-либо запущенной программой.


Детали

Я обнаружил, что мой статус оболочки git был очень медленным в моем репо, с git 2.19 на Ubuntu 16.04.

Закопался и обнаружил, что /usr/bin/time git status в моем assets Подмодуль git занял 1,7 секунды.

Найдено с strace этот мерзавец читает все мои большие файлы с помощью mmap. Обычно этого не происходит, обычноstat достаточно.

Я погуглил проблему и обнаружил проблему с использованием индекса и Racy Git.

Пытался git update-index somefile (в моем случае gitignoreв проверке подмодуля) показано здесь, но это не удалось с

fatal: Unable to create '/home/niklas/src/myproject/.git/modules/assets/index.lock': File exists.

Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.

Это классическая ошибка. Обычно вы замечаете это при любой операции git, но для подмодулей, которые вы нечасто используете, вы можете не замечать этого месяцами, потому что он появляется только при добавлении чего-либо в индекс; предупреждение не появляется только для чтенияgit status.

Удаление index.lock файл, git status сразу стало быстро, mmaps исчез, и теперь он более чем в 1000 раз быстрее.

Итак, если ваш статус git неестественно медленный, проверьте find .git/ -name index.lock и удалите остатки.

Частой причиной медлительности больших репозиториев являетсяstatusпроверка актуальности команды с удаленной веткой — установите эту конфигурацию уровня репо, чтобы отключить ее:

      git config status.aheadBehind false

Я не знаю, какой в ​​этом смысл, но для меня статус занимал 30 минут, я перепробовал все, что мог найти в Интернете, наконец, я сделал git reset У меня были сотни изменений, которые я применил из stash, где stash был создан из другой ветви, но применен к этой ветви, все они были подготовлены, но не зафиксированы (просто объясняя, что я сделал по-другому, прежде чем столкнуться с этой проблемой), git reset заняло 15 минут, но после этого все стало работать быстро, менее чем за секунду для статуса. Я не эксперт по git, просто рассказываю, что решило мою проблему, надеюсь, это поможет другим, кто попадет на эту страницу.

В качестве теста попробуйте временно отключить защиту в реальном времени для антивирусного программного обеспечения. Если это проблема, поменяйте антивирус.

Показательный пример: у меня был запущен Webroot , и на выполнение каких-либо действий с Git уходило от 30 до 60 секунд. Приостановил защиту в реальном времени, и внезапно моя первоначальная производительность вернулась с обновлениями за доли секунды и быстрой, быстрой системой.

Я выбрал Webroot, так как он славится минимальным влиянием на производительность системы, но в данном случае он метафорически заливал мой процессор патокой.

Это довольно старый вопрос. Хотя я удивлен, что никто не прокомментировал двоичный файл, учитывая размер репозитория.

Вы упомянули, что ваш репозиторий git составляет ~10 ГБ. Похоже, что помимо проблемы с NFS и других проблем с git (решаемыхgit gcи изменение конфигурации git, как указано в других ответах), команды git (git status, git diff, git add) могут быть медленными из-за большого количества двоичных файлов в репозитории. git плохо справляется с обработкой двоичного файла. Вы можете удалить ненужный двоичный файл, используя следующую команду (пример приведен для файла NetCDF; предварительно сделайте резервную копию репозитория git):

git filter-branch --force --index-filter \  
'git rm --cached --ignore-unmatch *.nc' \   
--prune-empty --tag-name-filter cat -- --all

Не забудьте поместить '*.nc' в файл gitignore, чтобы git не повторно принял файл.

Другие вопросы по тегам