git checkout branch заканчивает тем, что изменяет файлы - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть Mac, на котором я клонирую репо.Когда я извлекаю какую-либо ветку, файлы .json, которые у меня появляются, отображаются как «измененные».

Вот список вещей, которые я пробовал.

  1. git clone <blah>.git
  2. git checkout release
  3. git checkout -- $(git ls-files -m)

Файлы по-прежнему отображаются как измененные:

me@box> cat ~/.gitattributes
text=auto
-crlf

me@box> cat .gitconfig
[core]
    autocrlf = true

Я пробовал autocrlf с auto и false тоже.

Есть ли способ это исправить?

1 Ответ

0 голосов
/ 21 ноября 2018

TL; DR

Вы можете хотите, чтобы .gitattributes (не ~/.gitattributes) содержало строку * -text или *.json -text.Вы можете хотите удалить любую настройку autocrlf = true из .git/config, или $XDG_CONFIG_HOME/git/config, или $HOME/.config/git/config, или $HOME/.gitconfig.Вам может потребоваться более точный контроль над дополнительными файлами, в зависимости от того, как вы и другие используете эти репозитории, в каких системах.

Long

С одной стороны, эти строки неверны:

text=auto
-crlf

Записи в .gitattributes должны иметь форму имени файла или шаблона, за которым следует пробел (обычно это вкладка, но с пробелами тоже все в порядке), за которым следует один или несколько атрибутов.Здесь часть имени файла / шаблона отсутствует, хотя Git не видит этого таким образом: Git должен применить атрибуты no ко всем файлам с именем text=auto и применить атрибут отсутствует для всех файлов с именем -crlf.Поскольку, вероятно, нет файлов с этими смешными именами, это не применяет атрибуты ни к каким файлам - поэтому это не имеет никакого эффекта.

(Вы, вероятно, хотели * text=auto и / или * -crlf, но см. Ниже.)

Точно так же (но, возможно, не проблема), это может быть неправильным местом:

cat ~/.gitattributes

Git ищет файлы атрибутов в несколькихмест.Наиболее важным является .gitattributes на верхнем уровне рабочего дерева хранилища, то есть .gitattributes, а не ~/.gitattributes.Вы можете иметь Git consult core.attributesFile, для которого вы можете установить ~/.gitattributes.Modern Git ищет $XDG_CONFIG_HOME/git/attributes или $HOME/.config/git/attributes, если core.attributesFile не установлен, поэтому, если вы не настроили глобальную настройку core.attributesFile, он не будет искать в $HOME/.gitattributes.

Мнение: core.autocrlf не очень хорошая идея

cat .gitconfig
[core]
    autocrlf = true

Если это из вашего домашнего каталога, это может быть источником проблемы.

Установка core.autocrlf вtrue действует так, как описано в документации git config :

Установка этой переменной в значение "true" аналогична установке атрибута text в "auto "для всех файлов и core.eol для" crlf ".Установите значение true, если вы хотите, чтобы в вашем рабочем каталоге были окончания строк CRLF, а в репозитории - окончания строк LF.Эта переменная может быть установлена ​​на input , в этом случае преобразование вывода не выполняется.

В общем, мне не нравится text=auto, потому что это означает, что Git должен угадайте , является ли ваш файл текстовым.Git будет угадывать неправильно?Иногда да, так и будет.Если вы работаете в Linux, где по умолчанию в конце строки ничего не делает , это безвредно, но в Windows и MacOS это не так безобидно.Здесь .gitattributes файл с указанием того, какие окончания строк и в каких файлах используются.

Стоит также посмотреть описание core.eol, поскольку вы упомянули установку core.autocrlf в false:

Устанавливает тип окончания строки для использования в рабочем каталоге для файлов, у которых свойство text установлено, когда core.autocrlf имеет значение false.Альтернативы: lf , crlf и native , которые используют окончание собственной строки платформы.Значение по умолчанию является родным.См. gitattributes (5) для получения дополнительной информации о преобразовании конца строки.

Я пробовал autocrlf с auto и false тоже.

Единственными допустимыми настройками являются true, false и input.Ну, технически, установка его на 1, 0 и -1 соответственно также работает, поскольку Git попытается преобразовать его в целое число, если оно не соответствует ни одному из этих слов.Установка его в буквальную строку auto заставляет Git рассматривать его как целое число, которое преобразуется в значение 0 и, следовательно, означает false.Это значение по умолчанию, и в этом случае core.eol входит в игру при условии , что в файлах .gitattributes нет переопределений.

Большая часть оставшихся вещей, которые нужно знать, похоронена в , чтоgitattributes документация , за исключением нескольких ключевых пунктов, которые нигде не описаны должным образом.Это требует четкого определения Git's index и work-tree .

Commits, index и work-tree

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

Если зафиксированный файл имеет строку, заканчивающуюся CR-then-LF, за которой следует вторая строка, заканчивающаяся CR-без-LF, и третья строкакоторый заканчивается LF-без-CR, эта подтвержденная версия этого файла всегда имеет эту форму.С этим никто ничего не может поделать.Если у вас есть этот коммит, у вас есть этот файл с этими тремя окончаниями строк в указанном порядке.Вы можете проверить это или нет;но что бы вы ни делали или не делали, этот файл существует в этой форме в этом коммите.

Но подождите!Акт проверки какого-либо файла - или коммит, полный файлов, в этом отношении - не означает, что помещает этот файл в рабочее дерево как есть .Давайте рассмотрим файл, такой как x.json.Сначала файл должен пройти через ваш index .Индекс Git представляет собой особую структуру данных (обычно хранящуюся в одном большом плоском файле, хотя есть некоторые оптимизации, в которых иногда используется более одного файла: плоский файл имеет различные слоты индекса, частично обнаруживаемые по именам, таким как x.json, наряду со связямик внутренним данным, которые действительно хранятся в другом месте: индексная копия на самом деле просто указатель на реальные данные).У индекса есть еще два имени, отражающие, возможно, его важность в Git, или, что имя index оставляет желать лучшего: его также называют staging area , или иногда кеш , в зависимости от того, кто / какая часть Git выполняет вызов.

В любом случае x.json внутри коммита замораживается, как мы только что упомянули, но также находится вспециальный сжатый (иногда сильно сжатый) Git-only формат.Git сначала копирует это x.json в ваш индекс, размораживая файл, но сохраняя его в специальном формате Git-only.Поскольку копия в вашем индексе в настоящее время совпадает с копией в коммите, она имеет те же окончания строк.Но так как он не заморожен, вы можете изменить окончания строк, если хотите.Прежде чем мы доберемся до этого, давайте посмотрим на последний шаг проверки x.json.

Файл Git-only бесполезен ни для чего, кроме Git.Итак, Git копирует незамерзающий файл Git-only из индекса в ваше рабочее дерево , создавая фактический файл x.json обычного формата.Это последний шаг, который выполняет первый проход в конце строки, основываясь на:

  • , был ли файл обнаружен как «текст» - нетекстовый файл никогда не обрабатывается таким образом—И
  • параметр eol, если таковой имеется, из файла .gitattributes или подразумеваемый core.eol или core.autocrlf, более или менее в этом порядке.

Можно, конечно, также скопировать из рабочего дерева в указатель.В в это время Git снова выполнит манипуляцию конца строки, основываясь на тех же двух элементах, плюс настройку input, которая говорит Git выполнять преобразования конца строки, даже если output pass not.

Преобразования

На самом деле возможны два преобразования.Первое и наиболее распространенное относится к возврату каретки и переводу строки.Второй, новый с тех пор, как commit 107642fe2661 (впервые появившийся в Git 2.18.0), связан с кодировками Unicode.

CRLF-преобразования

При копировании из индексадля работы с деревом, Git заменит окончания строк только для LF на окончания строк CRLF, если вы сказали это сделать.Он не заменит CR-LF на LF;здесь только LF-to-CRLF.

Покакопируя из рабочего дерева в индекс, Git заменит окончания строк CRLF на окончания строк только для LF, если вы сказали это сделать.Он не заменит LF на CRLF;он делает CRLF-to-LF здесь.В современном Git есть некоторая дополнительная магия: если копия файла index имеет возврат каретки (\r или ^M символов), Git запрещает преобразование, если он не выполняет операцию «перенормировки» (git add --renormalize, плюс слияние или вишня с включенным флагом перенормировки).

Преобразования в Unicode

Как я уже говорил, они были новыми в Git 2.18 (и до сих пор для меня новы).Git теперь перекодирует файлы UTF-16 в UTF-8, и наоборот, если вы скажете это, через запись .gitattributes.Как и в случае с преобразованиями в конце строки, они являются направленными: git add, который копирует из рабочего дерева в индекс, подготавливает файл для хранения в Git и преобразует в UTF-8, тогда как git checkoutили git checkout-index (или различные дополнительные случаи, например git reset --hard), которые копируют из индекса в рабочее дерево, преобразуют из UTF-8.

Могут быть доступны дополнительные перекодировкина основе печати iconv --list.Это также описано в документации по gitattributes .

Изменение text= и проблемы с обходом конверсии

По умолчанию для Git думаю является ли какой-либо файл текстовым или нет.Если файл является текстом, он конвертируется;если нет, Git рассматривает это как священный: все, что находится в индексе, попадает в рабочее дерево, а все, что в рабочем дереве, попадает в индекс.Так что * -text говорит Git: никогда не трогает файл , и проблем нет.Но что, если Git ранее думал * text=auto?

Ответ на этот вопрос: это не работает хорошо.Плохие вещи случаются!За исключением git add --renormalize, Git будет полагать , что индекс и рабочее дерево совпадают, и, следовательно, не потрудится копировать так или иначе, если файл был недавно извлечен или добавлен.

То есть, в частности, следите за этим:

$ git checkout branch
$ echo '* -text' > .gitattributes   # avoid conversions
$ git add file.ext                  # use whatever's in the work-tree

и это:

$ git checkout branch
$ echo '* -text' > .gitattributes   # avoid conversions
$ git checkout -- file.ext          # see what's actually in the commit

Шаг git add или git checkout здесь может ничего не делать при условии, что рабочее дерево и индекс уже совпадают, даже если для сопоставления использовались только , основанные на предыдущей настройке .gitattributes (или ее отсутствии).Вы можете форсировать извлечение или добавление, изменив (или даже удалив, если вы собираетесь повторно извлечь) файл, так что копия рабочего дерева теперь явно отличается.Но, в общем, раздражающе и сложно получить изменение .gitattributes, чтобы оно вступило в силу, потому что Git не осознает, что изменение .gitattributes может изменить преобразования, которые выполнит Git .

В этом отношении то же самое верно для core.eol и core.autocrlf: изменение этих элементов конфигурации изменяет преобразование, которое может выполнять Git, однако Git не знает, что индекс и рабочее дерево теперь могут быть не синхронизированы друг с другом.Аспект индекса cache работает здесь против вас.

Наконец, обратите внимание, что Git скажет вам, что какой-то файл изменен или будет изменен, если Git увидит, что git add -ing файл будет изменять окончания строк.Иногда Git ошибается, особенно после изменения записей .gitattributes, чтобы файлы, которые были классифицированы как текст, теперь классифицировались как двоичные или наоборот.В этих случаях вы все равно должны git add файл, чтобы Git обновлял копию индекса, после чего Git понимает, что обновленная индексная копия по-прежнему соответствует фиксации HEAD и что файл все равно не изменен.

Другими словами, иногда исправления файла .gitattributes недостаточно, , даже если файл не изменится. Обратите внимание, что иногда зафиксированная версия файл имеет неправильные окончания строки , если запись .gitattributes отсутствует или неверна.Копия рабочего дерева вполне может быть правильной, но пока вы не сделаете новый коммит, в котором замороженная копия будет построена из правильной index копии, Git будет - на этот раз правильно - сообщать вамчто файл изменен!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...