Что происходит? GIT увидеть изменения без изменений - PullRequest
2 голосов
/ 12 октября 2019

Git видит изменения сразу после чистого клонирования.

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

nick@DESKTOP-NUMBER MINGW64 /d
$ git clone http://nick@host/nick/test.git
Cloning into 'test'...
remote: Enumerating objects: 27, done.
remote: Counting objects: 100% (27/27), done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 27 (delta 8), reused 0 (delta 0)
Unpacking objects: 100% (27/27), done.
error: failed to encode 'Var.not' from UTF-8 to Windows-1251

nick@DESKTOP-NUMBER MINGW64 /d
$ cd test/

nick@DESKTOP-NUMBER MINGW64 /d/test (master)
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   Var.not

no changes added to commit (use "git add" and/or "git commit -a")

error: failed to encode 'Var.not' from UTF-8 to Windows-1251 Файл может быть открыт в VSC в коде UTF-8 с некоторыми нечитаемыми символамиОбычно это Windows-1251. Но в чем проблема? Соседний файл "Var.yes" имеет тот же текст и ту же кодовую страницу - без проблем, без псевдо-изменений.

Как это исправить?

1 Ответ

0 голосов
/ 12 октября 2019

Этот бит информации, который вы добавили в комментарий , имеет решающее значение:

Я просто использую .gitattributes со строкой: *.* text working-tree-encoding=Windows-1251

Директива working-tree-encoding имеет довольно много побочных эффектов. См. документацию по gitattributes для получения более подробной информации, но я сейчас процитирую еще один бит с этой страницы.

Это сообщение об ошибке из вашего вопроса выше:

error: failed to encode 'Var.not' from UTF-8 to Windows-1251

предполагает, что содержимое этого файла фактически не сохраняется как данные UTF-8.

Одна из ловушек, перечисленных в документации по gitattributes:

Например, файлы ресурсов Microsoft Visual Studio (*.rc) или файлы сценариев PowerShell (*.ps1) иногда кодируются в UTF-16.

Возможно, это относится к вашей Var.notфайл.

В любом случае:

Неправильно ли я и работаю ли в кодировке дерева редактировать и как-то заново сохранять мои файлы?

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

Внутренние элементы Git: blob объекты или как файлы заморожены навсегда

Git на самом деле не о файлах , а о коммитах . Каждый сделанный коммит является (в основном) постоянным и (полностью) доступным только для чтения / неизменяемым. В коммите хранятся файлы , хотя, точнее, имеются ссылки на файлы, поэтому, сохраняя коммиты, Git эффективно сохраняет файлы.

Форма файла, находящегося в хранилище, имеет важное значение.

Обычно Git просто обещает, что файл представляет собой пакет байтов. Какие бы байты вы ни хранили в файле, Git вернет их вам. Это относится и к файлам необработанных данных - к файлам, где вы, в .gitattributes, скажете -text. Это относится к всем файлам, если вы не просите Git смешивать их, т. Е. Вы не помечаете их как text и не устанавливаете такие параметры, как окончания строк CRLF или working-tree-encoding. Но если вы сделаете ... ну, во-первых, давайте продолжим с тем, как работают файлы пакета байтов.

Каждый коммит сохраняет копию каждый файл - но с дедупликацией! Предположим, у вас есть тысяча коммитов, а каждый коммит имеет тысячу файлов. Это означает, что у вас есть Git, хранящий миллион версий различных файлов. Но большинство из этих версий файлов одинаковы. Таким образом, в самом первом коммите вы могли создать файл с именем README.md. Вы помещаете некоторый текст в файл и помещаете файл в свой первый коммит.

После этого вы сделали еще 99 коммитов, используя тот же README.md. Затем вы немного изменили его и сделали оставшиеся 900 коммитов со второй версией README.md.

Файлы в коммитах, как и сами коммиты, заморожены на все времена. Поэтому нет необходимости делать 1000 отдельных версий README.md. Нам просто нужны две версии: первая и вторая. Первые 100 фиксируют все share , первые README.md. Все последние 900 коммитов делятся вторым.

Чтобы сделать это быстро и с экономией места, Git делает с файлом мешка байтов следующее: сжатие это(с zlib deflate) и сохраните его в том, что Git называет объект blob . Этот объект BLOB-объекта получает уникальный идентификатор хеша, так же как каждый коммит получает уникальный идентификатор хеш-функции. Идентификатор хэша первого README.md основан на байтах данных в нем. Хеш-идентификатор второго README.md основан на байтах данных в этом втором README.md. Таким образом, есть только два объекта BLOB-объекта, общие для всех 1000 коммитов, причем каждый коммит ссылается на тот объект, который имеет право замороженного, сжатого README.md содержимого.

ThРезультатом всего этого является то, что файловое хранилище для каждого коммита состоит из этих замороженных, сжатых blob объектов. Мне нравится называть файлы в этой форме «лиофилизированными»: они похожи на лиофилизированный кофе, в который нужно добавить воду. Регидратация сублимированных файлов возвращает вам оригинальное содержимое - оригинальный пакет байтов - обратно.

Следовательно, чтобы проверить коммит, Git должен повторно смачивать все свои сублимированныефайлы. В коммите хранятся лиофилизированные (и не изменяемые!) Копии. Рабочее дерево содержит файлы обычного формата. Мы вернемся к этому чуть позже.

Внутренние элементы Git: индекс, область подготовки AKA

Когда вы делаете новый коммит, Git должен упаковатьвсе ваши файлы как новые или повторно использованные замороженные объекты BLOB-объектов. Другие системы контроля версий сделали это, например, повторно заморозив каждый файл. Это довольно медленно! Вместо этого Git делает что-то умное.

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

Другими словами, в индексе перечислены все идентификаторы хэша BLOB-объекта, которые были использованы для извлечения этого коммита в рабочее дерево.

Когда вы изменяете вещи в рабочем дереве, с индексом ничего не происходит. Вы должны запустить git add <file> для каждого из ваших измененных файлов. Этот git add шаг копирует файл из рабочего дерева. Это повторно сжимает байты во внутреннюю лиофилизированную форму. При необходимости это создает новый объект BLOB-объекта на месте. Теперь у Git есть хэш-идентификатор файла в формате замороженного формата, готового к фиксации в индексе.

Другими словами, индекс всегда содержит следующий коммит, готовыйидти. Если вы хотите, чтобы обновленный файл обновлялся в при следующем коммите, вы должны запустить на нем git add. Это копирует файл в индекс путем поиска или создания внутреннего объекта BLOB-объекта, и еще раз, индекс содержит следующий коммит, готовый к работе.

Это также почему вы должны продолжать работать git add. Обновление файла рабочего дерева не влияет на индекс , а git commit делает новые коммиты из того, что находится в индексе . Если его нет в индексе, его нет в новом коммите. Что бы не было в индексе, это , что в новом коммите.

Обратите внимание, что git status работает:

  1. Сравнение фиксации HEAD с индексом. Какие бы файлы ни были разные , Git говорит подготовлено для коммита . Когда два файла одинаковы - когда они являются одним и тем же объектом BLOB-объекта - Git ничего не говорит.

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

Таким образом, индекс или промежуточная область - это то, что фиксируется. Ваше рабочее дерево существует только для того, чтобы вы могли работать с вашими файлами. Эти файлы на самом деле никогда не передаются: то, что передается, - это сублимированный материал в индексе.

.gitattributes влияет на процесс сублимационной сушки и регидратации

НетТо есть каждый раз, когда файл выходит из Git, он должен быть повторно обработан. Обратите внимание, что каждый раз, когда файл попадает в область индекса / промежуточной области, он должен подвергаться сушке вымораживанием. Эти процессы всегда возбуждаются с файлами bag-of-bytes, сжимая их с помощью zlib deflate или, при необходимости, заново производя их с помощью zlib inflate. Операция zlib deflate / inflate является операцией сохранения данных: она никогда не изменяет ни одного байта, в конце концов, после циклического обхода (deflate + inflate).

Но потому что Gitуже обрабатывает каждый байт каждого файла, это идеальное место для изменения байтов. Например, предположим, что мы хотим, чтобы в высушенных сублимацией файлах всегда использовались окончания перевода строки, а в файлах рабочего дерева в Windows использовались окончания строки CRLF. Мы можем сказать Git:

  • При регидратации файла измените \n на \r\n (только LF только на CRLF).
  • При сушке сублимацией файла измените *От 1210 * до \n (только от CRLF до LF).

Поскольку Git выполняет коммит из индекса (лиофилизированный), а не из рабочего дерева (регидратированный), это дает нам только то, чтомы хотим. Для этого все, что мы делаем, это пишем:

*.txt  text eol=crlf

Но мы можем сделать это больше, чем просто переводы LF / CRLF. Фактически, используя то, что Git называет clean и smudge filters, мы можем вставить наши собственные произвольные операции. (Вот как работает Git-LFS.) Или, как в данном конкретном случае, мы можем установить working-tree-encoding.

Кодирование рабочего дерева влияет на сушку вымораживанием и регидратацию

Рабочийнастройка древовидной кодировки говорит Git:

  • При повторной гидратации, предположите, что исходный файл - UTF-8, и перекодируйте в кодировку рабочего дерева.
  • При лиофилизации,предположим, что исходный файл находится в кодировке рабочего дерева, и перед обычным делением zlib конвертируйте в UTF-8.

Чтобы это работало, объекты BLOB должны на самом деле be UTF-8. Более того, эта операция - от UTF-8 к чему угодно, к чему бы то ни было - к UTF-8 - должна быть согласованной: в противном случае каждый коммит может иметь некоторую случайную перекодировку в UTF8. Это та же самая идея кругового обхода, что и для раздувания / раздувания. Но не все кодировки дают здесь хорошие гарантии.

(гораздо) о подводных камнях - больше, чем упоминания в документации по gitattributes - см. Джоэл о программном обеспечении: абсолютный минимум Каждый разработчик программного обеспечения Абсолютно, позитивно должен знатьО Unicode и наборах символов (без оправданий!) , а затем, например, эта статья о Unicode, объединяющей символы и нормализацию , которая показывает, что две строки выглядят одинаковыми ("Zoë ") может быть написано с разными байтовыми последовательностями (объединяющими умлаут и букву E или использующими символ Unicode в нижнем регистре-E-with-umlaut).

В вашем случае наиболее вероятной проблемой является то, чтоисходный файл не UTF-8 для начала (но это может быть какая-то ошибка перекодирования).

...