Как принудительно конвертировать файлы worktree после изменения core.autocrlf? - PullRequest
0 голосов
/ 02 декабря 2018

Я нахожусь в Windows и имею общесистемную core.autocrlf=true.

Для определенного хранилища я переопределил его локально на false.

Но это не преобразовало строкуокончания в проверенных файлах.Как мне это сделать?

  • Если я преобразую файлы вручную, например, dos2unix, они будут отображаться как измененные.
  • Также пробовал git checkout --force HEAD, это не имело никакого эффекта.

Единственный найденный мной способ работы - это удалить все файлы, затем git reset --hard, что довольно неудобно (= для этого нет простой и надежной команды, и она выполняет много ненужной работы -- все воссоздается с нуля, а не просто перезаписывается файлы, которые необходимо преобразовать).

1 Ответ

0 голосов
/ 02 декабря 2018

TL; DR

Это три возможных решения (не обязательно только * три).

  1. Использование:

    git add --renormalize .
    

    (делается на верхнем уровне хранилища, один раз).Это требует более нового Git, но это самый простой метод.

    Примечание: мне совершенно не ясно, влияет ли это на версии work-tree ;вам все еще может потребоваться git checkout -- . для повторного копирования из индекса в рабочее дерево.

  2. Для каждого файла, к которому git status предъявляет претензии: rm <em>file</em>; git checkout -- <em>file</em>.rm удаляет копию рабочего дерева, поэтому git checkout должен на самом деле повторно извлечь файл в соответствии с новыми правилами окончания строки.

    Вы можете несколько упростить это с помощью git rm -r .; git checkout HEAD -- . (всего две команды) но это имеет побочный эффект касания всех файлов в рабочем дереве, даже любых файлов без изменений (файлы, в которых нет возврата каретки).

  3. Использованиеdos2unix как было, затем запустите git add для файлов (или .).Несмотря на видимость, это должно оставить индекс без изменений.

Во всех случаях, впоследствии, git status должен сказать nothing to commit, working tree clean.

Long

Это не вполне дубликат Git: как перенормировать окончания строк во всех файлах во всех ревизиях? , так как вы не хотите повторно копировать кучу существующих коммитов.Тем не менее, ответ git add --renormalize там должен работать.

Если это не удастся, вы можете попробовать Комментарий комментария PetSerAl .

Или, если это не удастся или ваш Git слишкомстарый вариант с параметром --renormalize:

Если я преобразую файлы вручную, например, dos2unix, они будут отображаться как измененные.

Вы можете конвертировать файлы вручнуюзатем git add . или удалите копии рабочего дерева и git checkout снова.git checkout --force HEAD потерпел неудачу, потому что Git был слишком умен для своего блага: он видел (неправильно), что копия рабочего дерева уже была правильной, и избегал делать с ней работу.

Что здесь происходит

Всегда есть три активных копии каждого файла.Допустим, у вас есть README.txt и prog.cc, оба из которых имеют CRLF-окончания в вашем рабочем дереве, но только LF-окончания строк в репозитории.

   HEAD          index       work-tree
----------    ----------    ----------
README.txt    README.txt    README.txt
prog.cc       prog.cc       prog.cc

Копия в коммитеявляется священным, неприкосновенным, замороженным навсегда (или до тех пор, пока существует этот коммит) в любой его форме.(Я предполагаю, что каждый из этих файлов имеет окончания строк в стиле LF.) Он тоже сжат.

Копия в index доступна для записи, но изначально соответствует копиив коммите.Так что он также будет иметь LF-only окончания строки.Он тоже сжат (на самом деле это просто ссылка на зафиксированную копию).

Копия в рабочем дереве не сжата и содержит окончания строк, которые вы указали Git использоватьчерез ваш .gitattributes файл (нет) и ваши core.autocrlf и core.eol и так далее.У вас было , чтобы они сменили LF на CRLF, поэтому у копий в вашем рабочем дереве на данный момент есть окончания CRLF.

Сейчас - после проверки - вы измените ваши настройки, так что файлы, которые будут извлечены, будут иметь только строки LF или будут сохранять то, что находится в индексе.К сожалению, одна из записей в каждой индексной копии файла - это информация о копии рабочего дерева.Это заставляет Git предполагать , что копия рабочего дерева совпадает с копией индекса.

Очевидно, что копия рабочего дерева имеет окончания CRLF, а копия индекса имеет окончания только для LF, два разные.Но если вы не изменили свои настройки конца строки, git status - это , требуется , чтобы сказать иначе, поэтому он должен сделать это предположение.

Если бы вы не изменили настройки EOL, git status ничего бы не сказал, и это никого не побеспокоило бы, потому что, если вы запустили git add, скажем, README.txt, это скопировало бы копию рабочего дерева обратно виндекс.Попутно это превратит окончания строк CRLF в окончания строк только для LF и повторно сжимает файл.Полученный файл будет соответствовать копии HEAD, а git status ничего не скажет.

Но вы действительно изменили настройки EOL, поэтому, если вы запустили git add сейчас,Git должен скопировать окончание CRLF в индекс.По сути, git status был обманут: индекс говорит - специально! - что копия рабочего дерева совпадает (даже если это не так), и запуск git add, в то время как копия рабочего дерева имеет CRLF, окончания строк изменятсякопия индекса.

Если вы используете dos2unix в файле для изменения копии рабочего дерева, Git теперь видит, что статистика копии рабочего дерева не совпадает с сохраненной индексом "этот файл чистый"статистика.То есть git status остается одураченным , но теперь говорит, что копия рабочего дерева отличается!Если вы git add файл сейчас , Git будет сохранять окончания строк только для LF при обновлении индексной копии.Конечным результатом будет то, что копия индекса в конце концов будет соответствовать копии HEAD, и , что Git обновляет кэшированную статистику рабочего дерева о файле, чтобы он знал, что индексcopy совпадает с копией рабочего дерева.

По сути, после изменения настроек окончания строки - в переменных .gitattributes и / или core.* - необходимо, чтобы Git исправил данные кеша индекса "чистый / грязный" индекса.До git add --renormalize единственным способом сделать это было заставить Git копировать из индекса в рабочее дерево:

rm worktreefile
git checkout -- worktreefile

или заставить Git копировать из рабочего дерева в индекс:

git add worktreefile

и то, и другое исправляет данные кэша индекса, но, очевидно, вносит дополнительный вклад в процесс.

Обратите внимание, что если подтвержденная копия HEAD имеет окончания CRLF, все меняется

Предположим, что подтвержденная копия README.txt имеет окончания CRLF.Затем первоначально:

  • индексная копия соответствует копии HEAD как обычно, поэтому она имеет окончания CRLF;
  • с окончаниями CRLF в рабочем дереве, все три копии совпадают;
  • но если в рабочем дереве выбрать окончания LF-only и сделать это, копия рабочего дерева отличается от HEAD и индекса.

Этоимеет значение true независимо от того, является ли git status одураченным.

После того, как вы скопируете окончания строк только для LF рабочего дерева в индекс, так что индекс также имеет окончания строк только для LF, теперь индексная копия («подготовленная для фиксации») отличается от HEAD копии.На этом этапе, если вы сделаете новый коммит, этот коммит будет иметь окончания строки только для LF, и вы будете в состоянии, которое мы описали ранее.

...