Возможная причина № 1 - Нормализация конца строки
Одна из ситуаций, в которой это может произойти, - когда рассматриваемый файл был зарегистрирован в хранилище без правильной конфигурации для концов строк (1), в результате чего в хранилище был файл с неправильными окончаниями строк или смешанными окончаниями строк. Для подтверждения убедитесь, что git diff
отображаются только изменения в окончаниях строк (по умолчанию они могут быть не видны, попробуйте git diff | cat -v
увидеть возврат каретки как буквенные ^M
символы).
Впоследствии кто-то, вероятно, добавил .gitattributes
или изменил core.autocrlf
настройку, чтобы нормализовать окончания строк (2). На основе .gitattributes
или глобальной конфигурации Git применил локальные изменения к вашей рабочей копии, которые применяют запрошенную нормализацию конца строки. К сожалению, почему-то git reset --hard
не отменяются эти изменения нормализации линии.
Решение
Обходные пути, в которых обнуляются локальные окончания строк, не решат проблему. Каждый раз, когда git «видит» файл, он пытается применить нормализацию, что приводит к той же проблеме.
Наилучший вариант - позволить git применить требуемую нормализацию путем нормализации всех концов строк в репо, чтобы они соответствовали .gitattributes
, и фиксации этих изменений - см. Попытка исправить окончания строк с помощью git filter-branch, но безуспешно .
Если вы действительно хотите попытаться отменить изменения в файле вручную, то, кажется, самое простое решение - стереть измененные файлы, а затем указать git восстановить их, хотя я отмечаю, что это решение не работает согласованно на 100%. время ( ВНИМАНИЕ: НЕ запускайте это, если ваши измененные файлы имеют изменения, отличные от окончаний строки !!):
git status --porcelain | grep "^ M" | cut -c4- | xargs rm
git checkout -- .
Обратите внимание, что если вы не нормализуете окончание строк в репозитории в какой-то момент, вы продолжите сталкиваться с этой проблемой.
Возможная причина № 2 - нечувствительность к регистру
Вторая возможная причина - нечувствительность к регистру в Windows или Mac OS / X. Например, допустим, что в хранилище существует следующий путь:
/foo/bar
Теперь кто-то в Linux фиксирует файлы в /foo/Bar
(возможно, из-за инструмента сборки или чего-то, что создало этот каталог) и отправляет. В Linux это фактически две отдельные директории:
/foo/bar/fileA
/foo/Bar/fileA
Проверка этого репо в Windows или Mac может привести к изменению, fileA
которое не может быть сброшено, потому что при каждом сбросе git в Windows проверяется /foo/bar/fileA
, а затем, поскольку Windows не учитывает регистр, перезаписывает содержимое fileA
with /foo/Bar/fileA
, в результате чего они «модифицируются».
Другим случаем может быть отдельный файл (ы), который существует в репо, который при извлечении в нечувствительной к регистру файловой системе будет перекрываться. Например:
/foo/bar/fileA
/foo/bar/filea
Могут быть и другие подобные ситуации, которые могут вызвать такие проблемы.
git на нечувствительных к регистру файловых системах должен действительно обнаруживать эту ситуацию и показывать полезное предупреждающее сообщение, но в настоящее время это не так (это может измениться в будущем - см. это обсуждение и соответствующие предлагаемые исправления в списке рассылки git.git).
Решение
Решение состоит в том, чтобы привести в соответствие регистр файлов в индексе git и регистр в файловой системе Windows. Это можно сделать либо в Linux, который покажет истинное положение вещей, либо в Windows с очень полезной утилитой с открытым исходным кодом Git-Unite . Git-Unite применяет необходимые изменения регистра к индексу git, который затем может быть зафиксирован в репо.
(1) Это было, скорее всего, кем-то, кто использовал Windows, без какого-либо .gitattributes
определения для рассматриваемого файла, и использовал глобальную настройку по умолчанию, для core.autocrlf
которой false
(см. (2)).
(2) http://adaptivepatchwork.com/2012/03/01/mind-the-end-of-your-line/
.
обозначает текущий каталог, а не корневой каталог