Почему «git status» игнорирует фильтр очистки .gitattributes?

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

$ cat .git/config
[filter "cleancomments"]
    clean = "grep -v '^#'"

$ cat .gitattributes
*   filter=cleancomments

И у меня есть файл «тест» со следующим содержимым (зафиксирован в репозитории):

This is a file with random content

Теперь я вношу изменения в «тест» и добавляю комментарии:

This is a file with random content
# and some comments
# like this

git status теперь говорит мне:

modified:   test

но git diff пусто (как и должно быть).

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

Что действительно загадочно для меня, так это следующее:

Если я сделаю это:

git add test

Затем внезапно файл «тест» больше не помечается как измененный и не отображается в индексе git. Почему это?


person Omar Kohl    schedule 06.11.2013    source источник
comment
Почему именно вы хотите удалить все комментарии из файла? Просто любопытно, у вас, очевидно, есть свои причины, но есть несколько сценариев, в которых это действительно разумно.   -  person Sietse van der Molen    schedule 06.11.2013
comment
Это всего лишь очень упрощенный пример того, что я действительно делаю :-) Я протестировал свой пример, и он работает так, как описано. Реальный сценарий предполагает удаление комментариев из файлов .po, потому что они почти никогда не бывают полезными, всегда могут быть автоматически сгенерированы повторно и вызывают много конфликтов, когда несколько разработчиков редактируют один и тот же файл.   -  person Omar Kohl    schedule 06.11.2013


Ответы (1)


git add добавляет файл в индекс1, но сначала пропускает его через все необходимые фильтры.

Индекс содержит имя файла на диске и «истинное имя» (его git-хеш как «большой двоичный объект») вместе со значениями каталога stat и парой git-хеш-значений (исходное и отфильтрованное), а также некоторые другие биты и бобы по мере необходимости. . После add-ed git status может узнать из данных индекса, что файл теперь "актуален" в индексе, а сам индекс актуален в репозитории, поскольку хэш большого двоичного объекта совпадает с хэшем фиксации HEAD.

Однако если вы еще немного измените файл, некоторые ключевые stat данные изменятся, и git решит, что индекс устарел, и git status снова решит, что его нужно git add редактировать.2

Общая идея здесь заключается в том, что git status ничего не записывает (даже индекс). Было бы неплохо, если бы git update-index --refresh обновил пару work-dir/cleaned-entry, но, похоже, этого не происходит.


1Точнее, git add вычисляет хеш — и, следовательно, «истинное имя» в репозитории — а затем добавляет объект в репозиторий тогда и только тогда, когда его еще нет. Хэш-значение теперь известно и может быть сохранено в индексе по мере необходимости. Хэш-значение неизвестно до тех пор, пока не будут выполнены фильтрация и хеширование, т. е. git status не знает его.

2Здесь есть больше тонкостей, если вы используете такие вещи, как --assume-unchanged и/или core.ignorestat.

person torek    schedule 06.11.2013
comment
Есть ли способ заставить «git status» занять больше времени и учесть фильтр/очистку? Или есть другой способ избежать пометки файла как «измененный» без необходимости «git add»? - person Omar Kohl; 06.11.2013
comment
Не похоже. Тем не менее, git add -u . добавит все необходимое для очистки измененных статусов (если они действительно изменились, он, конечно, также их добавит). Между прочим, я проверил это, и простое изменение даты не приводит к тому, что она появляется снова, т. Е. Я ошибался, просто используя touch test, поэтому теперь я гораздо менее уверен, какую статистическую информацию проверяет git status. (Некоторое время назад я просмотрел код, я знаю, что он интенсивно использует lstat()...) - person torek; 06.11.2013