2017-01-30 3 views
5

Мне нужно клонировать git repo в существующий каталог ($HOME, для управления dotfiles). Я делаю голый клон и реконфигурирую его, потому что мне нужно клонировать в существующий рабочий стол unclean. Это работает, однако я обнаружил, что git status пытается запустить фильтры при первом использовании. Почему это так и как я могу предотвратить это?Почему «git status» запускает фильтры?

Попробуйте это:

# create a test repo 
mkdir test && cd test 
git init 
echo hello > hello.txt 
git add . 
git commit -m 1 
echo 'hello.txt filter=foo diff=bar' > .gitattributes 
git add . 
git commit -m 2 

# clone it bare and configure it 
mkdir ../test2 && cd ../test2 
git clone --bare ../test .git 
git config core.bare false 
git config core.logallrefupdates true 
git reset 
git checkout . 
git config filter.foo.clean foo 
git config filter.foo.smudge foo 
git config diff.bar.textconv bar 

Это borks

$ git status 
error: cannot run foo: No such file or directory 
error: cannot fork to run external filter 'foo' 
error: external filter 'foo' failed 
On branch master 
nothing to commit, working tree clean 

Это не

$ git status 
On branch master 
nothing to commit, working tree clean 

Кроме того, первоначально делать git status несколько раз в быстрой последовательности (т.е. git status; git status; git status) может дать многократный Иногда.

Насколько я могу подтвердить, much reading, фильтры должны запускаться только при проверке файлов.

Почему именно git status ими управляют?

+0

что такое 'git -version'? –

+0

git version 2.11.0 – starfry

+0

Кстати, я не буду (и не буду) управлять dot-файлами таким образом. Вместо этого у меня есть каталог Git с именем 'Dotfiles' в моем домашнем каталоге, который является обычным не-голым деревом, а затем я ссылаюсь на' .whatever' на 'Dotfiles/whatever'. – torek

ответ

2

Идея, что фильтры работают только во время регистрации/проверки, является чем-то вроде white lie. Он предназначен для того, чтобы сделать фильтры более объяснимыми.

В самом деле, хотя, фильтры работать при перемещении файлов между индексом и рабочим деревом (а также, в достаточно современных версиях Git, при запросе с --path= вариантов в git show и git cat-file и git hash-object, а также: некоторые из них переходы непосредственно из репозитория в stdout или stdin в репозиторий). Это в основном эквивалент времени проверки/проверки. Но у git status есть специальное разрешение, из-за аспекта кеша индекса.

По соображениям производительности Git хочет знать, может ли какой-либо файл в дереве быть «грязным» относительно версии в индексе. Git предполагает, что значение statst_mtime, который обычно имеет один-вторую резолюцию, может быть использован для этой цели: если st_mtime времени файла -работы дерево начального является старше сохраненной st_mtime в записи индекса, то индексная запись обновляется и является «чистой»: что соответствует индексу, соответствует ли рабочее дерево, после применения чистых фильтров и т. д.

Если метка времени рабочего дерева запись более поздняя, ​​чем сохраненная запись индекса, то файл определенно был изменен: запись индекса может быть устаревшим. Это не гарантировал устаревшим, так как файл дерева работ мог быть изменен таким образом, который в конечном итоге не изменился. Но очевидно, что нужно запустить чистый фильтр (и любой хакерство линии CR/LF).

Если две метки времени: то же самое, запись в дереве не определена. (Гит называет это «расово чистым», хотя «расистски грязный» был бы одинаково точным.)

Во всех этих случаях git status будет запускать чистый фильтр (и любые модификации CR/LF направления ввода-в-Git) по дереву файлов, чтобы вычислить новый хеш. Если новый хеш соответствует хеш-индексу, Git может и будет обновлять запись индекса, чтобы пометить файл как «фактически чистый». Теперь, в следующий раз, когда вы что-то сделаете, Git не придется запускать чистый фильтр.

Если вы не делаете все это в разрешении поля stat st_mtime. В этом случае запись индекса заканчивается «racily clean», и Git должен повторить попытку. Вот что вы здесь наблюдаете.

(Обратите внимание, что, кстати, что git status работает два Diffs: один из HEAD к индексу, и один из индекса работы дерево Это что второй дифф, который приносит пользу огромно с точки зрения кэша проиндексирует.. индекс теперь может также хранить информацию о некэшированные файлы и каталоги, тоже!)


Некоторые stat вызовы дают меньше секунды точность, но по разным причинам, запись индекса/кэш только хранит 1 -секундная временная метка разрешения, в любом случае, n ormally.

Подробнее об этом см. the racy-git.txt file in the technical documentation.

+0

Отличное объяснение! Это также объясняет, почему 'touch hello.txt' заставляет' git status' запускать фильтры. И это объясняет, почему они запускаются снова, если время между изменением временной метки файла и проверка статуса слишком коротки (<1 с). Учитывая это объяснение, я бы предположил, что невозможно предотвратить запуск фильтров (в моем случае фильтры будут терпеть неудачу до тех пор, пока не будет предоставлен криптовый ключ). В этом случае, я работаю вокруг 'sleep 1 && git status &>/dev/null', на что я могу надеяться ...? – starfry

+0

Этот способ работы должен работать. Однако я не знаю, почему вы шифруете эти вещи в первую очередь. – torek

+0

закрытые ключи, ключи API и т. Д. Я только шифрую вещи, которые чувствительны, для каждого файла. – starfry

Смежные вопросы