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

80

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

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

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

Сентил А Кумар
источник
2
Узким местом здесь в значительной степени является NFS. lstat - довольно синхронная операция.
user611775
1
Возможный дубликат Git Status требует много времени для завершения
Сет Баттин

Ответы:

45

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

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

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

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

Джош Ли
источник
31
То, что вы пропустили: патч Линуса действительно был объединен, и его можно включить, установив core.preloadindexзначение true - см. git-configДокументацию для получения небольшого описания. (На моем рабочем месте используется NFS, и я столкнулся именно с этой проблемой, но никогда не замечал настройки preloadindex. Спасибо, что указали мне правильный путь!)
Cascabel
1
Здесь к принятому ответу следует добавить 'git config core.preloadindex true'. возможно с флагом -uno от user1077329
ostler.c 01
2
core.preloadindexflag установлен в true по умолчанию, начиная с
Петр Газаров
38

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

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

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

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

user1077329
источник
Как упоминается в git-status (1), его можно установить по умолчанию, установив status.showUntrackedFilesconfig.
johankj 02
33

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

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

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

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

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

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

Джабари
источник
5
Я тоже не понимаю, как проголосовали против; это действительно полезно. git gcсократить время git logзапуска с 15 секунд до 0 на одном из моих репозиториев.
GreenRaccoon23
@NicolasC А! Не знаю, как я это пропустил, но я бы тоже проголосовал против своего ответа. : - /
Jabari
1
git cg хорош, git clean, может быть, удалит какой-то ненужный файл?
Лука Регеллин 08
18

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

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

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

бено
источник
7

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

См. Commit 950a234 (14 апреля 2017 г.) Джеффа Хостетлера ( jeffhostetler) .
(Объединено Junio ​​C Hamano - 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 (второй квартал 2018 г.) представит новую трассировку для измерения времени, затрачиваемого на операции с интенсивным индексированием.

См. Commit ca54d9b (27 января 2018 г.) Нгуен Тай Нгук Дуй ( pclouds) .
(Объединено Junio ​​C Hamano - gitster- в фиксации 090dbea , 15 февраля 2018 г.)

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

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

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 (второй квартал 2018 г.) улучшается за счет git status:

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

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

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

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

На копии репозитория Linux с локальным экземпляром «master» за удаленной ветвью « origin/master» на ~ 60 000 коммитов мы обнаруживаем, что производительность « git status» повысилась с 1,42 секунды до 1,32 секунды, с относительной разницей -7,0%.


Git 2.24 (3 квартал 2019 г.) предлагает еще одну настройку для повышения git statusпроизводительности:

См. Коммит aaf633c , фиксацию c6cc4c5 , фиксацию ad0fb65 , фиксацию 31b1de6 , фиксацию b068d9a , фиксацию 7211b9e (13 августа 2019 г.) от Деррика Столи ( derrickstolee) .
(Слияние Junio ​​C Hamano - gitster- in коммите f4f8dfe , 09 сентября 2019 г.)

repo-settings: создать настройку feature.manyFiles

feature.manyFilesУстановка подходит для сделок РЕПО с большим количеством файлов в рабочем каталоге.
Установив index.version=4и core.untrackedCache=true, такие команды, как 'git status ', должны улучшиться.

Но:

В Git 2.24 (4 квартал 2019 г.) кодовый путь, читающий index.version конфигурацию, был нарушен в последнем обновлении, которое было исправлено.

См. Коммит c11e996 (23 октября 2019 г.) Деррик Столи ( derrickstolee) .
(Объединено Junio ​​C Hamano - gitster- в коммите 4d6fb2b , 24 октября 2019 г.)

repo-settings: читать int для index.version

Подписано: Деррик Столи

Несколько параметров конфигурации были объединены в repo_settingsструктуру в ds / feature-macros, включая перемещение параметра конфигурации index.version в 7211b9e (" repo-settings: объединить некоторые параметры конфигурации", 2019-08-13, Git v2.24.0-rc1 - слияние указано в партии № 0 ).

К сожалению, этот файл выглядел как много шаблонного, и, что явно является фактором перегрузки копирования и вставки, параметр конфигурации анализируется repo_config_ge_bool()вместоrepo_config_get_int() . Это означает, что параметр index.version = 4 не будет правильно зарегистрирован и вернется к версии 3 по умолчанию.

Я поймал это при включении v2.24.0-rc0 в кодовую базу VFS для Git, где нам действительно важно, чтобы индекс был в версии 4.

Это не было обнаружено кодовой базой, потому что проведенные проверки версии t1600-index.shнедостаточно протестировали "базовый" сценарий. Здесь мы модифицируем тест, чтобы включить эти обычные настройки, которые не могут быть отменены features.manyFilesили GIT_INDEX_VERSION.
В то время как "по умолчанию" версия - 3, она понижена до версии 2 вdo_write_index() когда в этом нет необходимости.

VonC
источник
См. Также stackoverflow.com/a/43667992/6309 и новую index.threadsнастройку конфигурации
VonC
GIT_TRACE = true git log Вот как вы запускаете трассировку и находите узкое место
dhavale
@dhavale На самом деле, начиная с Git .22, у вас также есть trace2: stackoverflow.com/a/56094711/6309
VonC
4

git config --global core.preloadIndex true

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

климат
источник
Какую версию Git вы используете?
VonC
2.7.4. Я использую подсистему Linux для Windows, и даже при обновлении, apt-getпохоже, есть ссылки на довольно старые пакеты.
klimat
1
Хорошо, имеет смысл. Я не думаю, что это нужно для более свежей версии.
VonC
Это даже помогло мне с git версии 2.17.1
Маркус Зеллер
1

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

город
источник
1

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

git config core.fscache true


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

git config core.ignoreStat true

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

источник

dCSeven
источник
Это помогло мне в Windows 10, хотя у меня была довольно свежая версия Git для Windows. Спасибо. Мое репо было ~ 100 Гб в папке .git (git lfs)
Алекс Сороколетов
0

Оставшиеся 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этим git, прочитал там все мои большие файлы с 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и удалите остатки.

нh2
источник
0

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

Вы упомянули, что ваш репозиторий 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 не повторно принял файл.

РС_
источник