Самый быстрый способ получить статус git в bash

Некоторое время я использовал функцию __git_ps1 в своем приглашении bash PS1 (с PS1='\w$(__git_ps1)'). Теперь я хочу покрасить его в зависимости от ветки положение дел.

Я написал функцию bash, которая проверяет, изменена ли текущая ветка, и цвета красного или белого цвета в зависимости от состояния. Проблема в том, что он использует git status для проверки состояния (это единственный способ, которым я знаю), и что несколько раза медленнее, чем __git_ps1, что достаточно, чтобы вызвать раздражающую задержку, когда Я использую подсказку (у меня очень слабый нетбук).

Итак, я спрашиваю: есть ли более быстрый способ проверить состояние текущей папки git? __git_ps1 намного быстрее, чем ручная разборка git branch, поэтому я думаю может быть какая-то другая скрытая функция git.

Ответ 1

Не совсем ваш ответ, но bash -completion имеет этот встроенный модуль.

Если вы установите значение bash ENV GIT_PS1_SHOWDIRTYSTATE на непустое значение, рядом с именем ветки будут показаны неустановленные (*) и поэтапные (+) изменения. Вы можете настроить этот репозиторий с переменной bash.showDirtyState, которая по умолчанию имеет значение true, когда включена функция GIT_PS1_SHOWDIRTYSTATE.

Вы также можете увидеть, если в настоящее время что-то спрятано, установив GIT_PS1_SHOWSTASHSTATE на непустое значение. Если что-то спрятано, то рядом с именем ветки будет отображаться "$".

Если вы хотите посмотреть, есть ли файлы без следа, вы можете установить GIT_PS1_SHOWUNTRACKEDFILES на непустое значение. Если есть необработанные файлы, тогда рядом с именем ветки будет показано "%".

Не уверен, что скорость ухудшится, если вы включите это. Если вы хотите сделать раскраску:

Поэтажные файлы:

if git rev-parse --quiet --verify HEAD >/dev/null; then
 git diff-index --cached --quiet HEAD -- || color for staged changes
else
  color unstaged changes
fi

Спрятанные файлы

git rev-parse --verify refs/stash >/dev/null 2>&1 && color for stashed files

Отслеживаемые файлы

if [ -n "$(git ls-files --others --exclude-standard)" ]; then
  Color untrack files
fi

Вышеприведенные фрагменты взяты из bash -completion script.

Ответ 2

git diff --quiet возвращает 1, если в рабочий каталог есть изменения, а git diff --quiet --cached делает то же самое для индекса.

Вы можете использовать его:

git diff --quiet
    || echo "There be changes!"

Ответ 3

Примечание: Git 2.6+ (Q3 2015) должен ускорить этот статус __git_ps1:

См. commit dd160d7, совершить 6bfab99 (19 июля 2015) SZEDER Gábor (szeder).
(слияние Junio ​​C Hamano - gitster - в совершить 461c119, 03 августа 2015 г.)

bash prompt: быстрый индикатор отсутствия слежения с неподготовленными каталогами

Если индикатор состояния без следа включен, __git_ps1() ищет ненужные файлы, запустив 'git ls-files'.
Это может быть заметно медленным в случае отсутствия следящей директории, содержащей много файлов, потому что в ней перечислены все файлы, найденные в нетрезвом каталоге, только для прямого перенаправления на /dev/null.
Это фактическая команда, выполняемая __git_ps1():

$ ls untracked-dir/ |wc -l
100000
$ time git ls-files --others --exclude-standard --error-unmatch \
  -- ':/*' >/dev/null 2>/dev/null

real    0m0.955s
user    0m0.936s
sys 0m0.016s

Устранить эту задержку, добавив опцию '--directory --no-empty-directory' в 'git ls-files', чтобы отображать только имя непустых неподготовленных каталогов вместо всего их содержимого:

$ time git ls-files --others --exclude-standard --directory \
  --no-empty-directory --error-unmatch -- ':/*' >/dev/null 2>/dev/null

real    0m0.010s
user    0m0.008s
sys 0m0.000s

Это следует за выражением ea95c7b (завершение: улучшить невоспроизводимый каталог фильтрация для завершения имени файла, 2013-09-18, Git 1.8.5).

Ответ 4

! git diff-index --cached --quiet HEAD      # fastest staged-changes test
! git diff-files --quiet                    # fastest unstaged-changes test
! git diff-index --quiet          HEAD      # fastest any-changes test
stdbuf -oL git ls-files -o | grep -qs .     # fastest untracked-files test
git rev-parse -q --verify refs/stash >&-    # fastest any-stash test

Если игнорируемое состояние имеет значение для неотслеживаемых файлов, используйте --exclude-standard -oi для неотслеживаемого игнорируемого и --exclude-standard -o для неотслеживаемого и игнорируемого.

Самый быстрый способ, которым я знаю, чтобы получить заголовок HEAD (название ветки или ша)

{ git symbolic-ref -q --short HEAD || git rev-parse -q --short --verify HEAD; } 2>&-

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

if HEAD='{ git symbolic-ref -q --short HEAD || git rev-parse -q --verify HEAD;  } 2>&-'
then
        : in a git repo, $HEAD is the branch name or sha
fi

ЗАМЕТЬТЕ, что тест с неотслеживаемыми файлами зависит от запуска с shopt -s lastpipe для bash. zsh и ksh работают таким образом по умолчанию.

Ответ 5

Я использую Ksh и у меня та же проблема. В довершение ко всему, мои репозитории Git находятся на монтируемых NFS, что делает время отклика еще медленнее.

Чтобы напрямую ответить на вопрос о скорости, попробуйте использовать:

git ls-files -m

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

Ответ 6

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

Я написал очень быстрый git-статус в C++ с максимальной оптимизацией. Он даже имеет параметр --refresh-sec который позволит избежать дополнительных вызовов git если предыдущий вызов был меньше, чем --refresh-sec несколько секунд назад. Я думаю, что это самый быстрый способ сделать это.

Это для Zsh, но вы можете адаптировать его для Bash. И это очень быстро: https://gitlab.com/cosurgi/zsh-git-cal-status-cpp