Это:
Однако, по-видимому, индекс по-прежнему в ревизия во время операции фильтра, поэтому только те файлы, которые изменены по отношению к ГОЛОВАМ ...
совершенно неверно, но, к сожалению, эта проблема сложна.
Давайте начнем с основным фактом, что git filter-branch
произведения копирования каждый фильтруются совершают (и аннотированный тегом, если с помощью --tag-name-filter
). Если результирующая копия бит-бит-бит идентична исходной фиксации, копия завершается с тем же идентификатором хэша, и, следовательно, является оригиналом, в очень реальном смысле. В противном случае это новый фиксатор и заменяет первоначальную фиксацию.
Индекс Git играет несколько разных ролей, хотя основной из них - «построить следующую фиксацию». Следовательно, индекс действительно изменяется, так как git filter-branch
выполняет итерацию по каждой исходной фиксации для ее копирования. Однако ...
а именно сделать дерево-фильтр который добавляет .gitattributes
, а затем выполняет сброс GIT.
... есть проблема здесь. Если вы посмотрите на the filter-branch code, вы увидите, что он запускает git update-index
в конце запуска фильтра дерева. Он не запускается git add
, поэтому он зависит от результатов команд git diff-index
и git ls-files
.Все это делается во временном каталоге, который переопределяет нормальное рабочее дерево.
Здесь мы сталкиваемся в края моей личной Гит-фу :-) потому git add
и т.п. вызова кода атрибута (в беличьей пути, с помощью функции unpack_trees
, которая вызывается непосредственно из builtin/reset.c
, и косвенно вызывается из diff_cache
как вызванный от run_diff_index
или index_differs_from
для других) таким образом, который соответствует файлу .gitattributes
в дереве. Однако представляется, что git update-index
не (это основано на вашем собственном наблюдении, что ваши атрибуты не применяются).
К счастью, существует вероятное обходное решение. Если вы явно указали git add .gitattributes
(вместо, или, возможно, прежде, если необходимо, запустите git reset
или, возможно, еще один git checkout-index
), который должен получить новый файл в индекс. Затем, если git update-index
использует индексированную версию вместо временного древовидного файла (как представляется, на основе источника), он будет использовать тот, который вы намеревались использовать.
Последний:
Что именно вызывает мерзавца подобрать окончание строки преобразования в этой ситуации?
Это не очень хорошо документировано, и путь кода здесь, если вообще, еще сложнее.
В основном, все фильтры, включая преобразования текста/CRLF, применяются в двух точках: при перемещении файлов «из» из индекса в дерево работы или при перемещении файлов «в» с рабочего дерева на индекс.
Индекс также, однако, имеет ряд stat
данных и флагов, так что Git только даже смотреть на (гораздо меньше копии в или из) файлов, которые, как представляется, скорее всего, будет отличаться в дереве, чем в индексная версия.
В индексе есть отдельный флаг, чтобы пометить файлы «грязные». Этот флаг устанавливается, когда фильтр изменяет файл во время проверки. Так как нет .gitattributes
на начальном checkout, грязный флаг здесь не будет установлен. (Но существование этого флага делает любой файл, который делает фильтруется, гораздо медленнее работать. Таким образом, используя множество атрибутов делает Git гораздо медленнее, победив умный индекс кэширования.)
Мне потребовалось некоторое время, чтобы обработать ваш комментарий :-) Спасибо, что указали мне на источник git! Действительно, 'git update-index' действительно вызывает преобразование атрибута, что происходит в' sha1_file.c': 'index_path()'. Файл атрибутов считывается из дерева работ. Однако 'diff-index' в' git-filter-branch.sh' не получает никаких изменений до тех пор, пока 'git reset' не станет эффективно индексировать все файлы, и в этот момент' update-index' делает преобразование , Выглядит вполне безопасно для меня, но завтра я попробую его в большом хранилище ... – tcernaj