Git говорит, что есть изменения, но их нет - PullRequest
0 голосов
/ 14 мая 2018

Во-первых, мне не удалось отменить изменения в файле, я бы использовал git reset --hard, ошибок не было, но изменения остались. Я попробовал несколько предложений из других статей StackOverflow.

git rm .gitattributes
git add -A
git reset --hard

git rm --cached [fileName]

Я даже сдул репо, и сразу же после клонирования репо он снова изменил файл. Если я вручную внесу изменения в файл (удалите то, что в GIT отличается, используя редактор), я могу теперь увидеть его в измененном списке дважды (например, когда я запускаю git status, я вижу тот же файл с тем же путем в списке дважды под неподготовленными файлами). Наконец, нашел тот, который фактически сбросил файл и удалил его из измененного списка.

git ls-files -m | xargs -i git update-index --assume-unchanged "{}"

Теперь я попытался переключить ветви, и он говорит, что изменения будут перезаписаны, я должен зафиксировать или спрятать свои изменения, но когда я запускаю git stash, он говорит, что никаких изменений нет. Я попробовал несколько предложений, включая попытку обновить окончание строки , и ничто не позволяет мне проверить ветку. В ветке есть "/", может ли это вызывать проблемы?

C: \ git \ azureWebApps \ CRM-WebAPI (qa -> origin) λ git status
На ветке qa
Ваша ветка обновлена ​​с помощью origin / qa.

нечего коммитить, рабочее дерево чистое

C: \ git \ azureWebApps \ CRM-WebAPI (qa -> origin) λ git diff

C: \ git \ azureWebApps \ CRM-WebAPI (qa -> origin) λ функция проверки git / PEN-146-CreateUpdatePerson
ошибка: ваши локальные изменения в следующих файлах будут перезаписаны> checkout: CRM-RestAPI / web.config
Пожалуйста, передайте изменения или спрячьте их, прежде чем переключать ветки.
Отмена

C: \ git \ azureWebApps \ RM-WebAPI (qa -> origin) λ git stash
Нет локальных изменений для сохранения

1 Ответ

0 голосов
/ 14 мая 2018

[ Примечание: это, в конце концов, проблема с именем файла; см. «изменить» ниже.]

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

Это означает, что происходит одно из двух:

  • файл является изменяющимся, или
  • Идея Git о том, какой файл не соответствует реальности на вашем компьютере.

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

Это имеет меньше смысла. Было бы полезно, если бы вы включили вырезку и вставку того, что вы имеете в виду.

[ Edit: в комментариях, это было что-то вроде - я бы использовал реальный текст, но я должен воссоздать его, так как у меня нет проблемы самостоятельно - следующее:

(boilerplate snipped)
    modified:   CRM-RestAPI/Web.config
    modified:   CRM-RestAPI/web.config

Хотя Git обрабатывает их как два отдельных файла (как они будут в файловой системе, чувствительной к регистру), если ваша ОС делает регистр- сворачивание (и Windows или MacOS делают это по умолчанию), будет только один файл, который будет иметь заглавные или строчные буквы W, а не оба, с обеими буквами в обоих случаях. Это конкретный пример общей проблемы, которую я опишу ниже, где Git хранит имена файлов в виде почти произвольных байтовых строк, но не все ОС делают это.]

Фон, который вам нужно будет найти и решить проблему

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

Каждый файл существует в трех версиях

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

В любом случае, у вас есть текущий коммит , чей ID хеша вы можете найти с помощью:

git rev-parse HEAD

Идентификатор хэша текущих изменений коммитов, когда вы проверяете различные коммиты или делаете новые коммиты, но всегда есть некоторый текущий коммит (с исключением, которое здесь не происходит).

Каждый коммит содержит список файлов, которые должны быть извлечены, если вы git checkout этот конкретный коммит. Вы можете просмотреть эти файлы, если хотите, используя:

git ls-tree -r <commit-hash>

, который показывает вам детально каждый файл, который идет с этим коммитом.

Каждый коммит доступен только для чтения - файлы, хранящиеся в этом коммите под этим хэш-идентификатором, постоянно хранятся там 1 , и они никогда не могут измениться.

вторая копия каждого файла хранится в Git's index . Это то, чем вы манипулируете с git update-index --assume-unchanged. Индекс является центральной структурой данных, которую Git использует для многих вещей, но, возможно, его лучше всего описать как , где вы (и Git) создаете следующий коммит, который вы сделаете. Таким образом, индекс обычно начинается точно соответствует текущий коммит. Каждый файл в текущем коммите имеет и в индексе в том же специальном сжатом формате Git, который используется Git. (Технически индекс просто разделяет копию коммита файла.) Важное различие между копией индекса и копией коммита состоит в том, что индексная копия может быть перезаписана, после чего индекс больше не разделяет коммит версия файла. Индексная копия все еще находится в специальном сжатом формате Git, но в отличие от подтвержденной копии, вы можете перезаписать индексную копию.

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


1 Так или иначе, так же, как и сам коммитЕсли вы заставите Git забыть о коммите, сами файлы уйдут, если какой-то другой коммит (ы) не поделится ими.


HEAD, index и work-tree

Мы можем проиллюстрировать три копии, пометив их немного:

  HEAD        index     work-tree
---------   ---------   ---------
README.md   README.md   README.md
somefile    somefile    somefile

и так далее.Git копирует файлы между этими различными версиями, за исключением того, что HEAD (подтвержденная) версия всегда доступна только для чтения, поэтому для «изменения» подтвержденной версии Git создает новый коммит из того, что находится вindex прямо сейчас .

Команда git status сообщает вам об этом, сравнивая, во-первых, версию HEAD каждого файла с индексной версией каждого файла.Если здесь что-то не так, git status напечатает имя файла и сообщит вам, что это изменение готово к фиксации.Затем он сравнивает индексную версию каждого файла с версией рабочего дерева каждого файла.Если здесь что-то не так, git status печатает имя файла и сообщает, что это изменение еще не подготовлено для фиксации.

Команда git checkout копирует файлы из фиксации в индекс и работает-дерево или от индекса к рабочему дереву.(Это должны быть отдельные команды - и они были в одной точке.) Команда git reset копирует файлы из коммита в индекс, но не в рабочее дерево.Команда git add копирует файлы из рабочего дерева в индекс.Команда git commit делает новый коммит из того, что находится в индексе, а затем упорядочивает вещи так, чтобы HEAD теперь ссылался на новый коммит.

Интересующие вещи, или, Что искать

Теперь, когда вы знаете, что находится в разных частях, вот где что-то может пойти не так.

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

имена файлов, хранящихся в коммитах и ​​в индексе, являются просто байтовыми строками в Git.Git, как правило, «кодирует agnositc», за исключением того, что использует косую черту для отделения имен каталогов от подкаталогов и файлов, а также NUL-байт ASCII для завершения этих байтовых строк.Это позволяет Git использовать UTF-8 для кодирования имен файлов, поскольку кодировка UTF-8 никогда не кодирует любой символ, кроме косой черты / (ASCII 0x2f), в качестве байтового кода 0x2f.Если вы работаете в системе, в которой вместо косой черты используется обратная косая черта, либо она разрешает внутреннюю косую черту, либо Git переводит косые черты по мере необходимости, так что все это работает.

Это также означает, что GitИмена файлов чувствительны к регистру: файл README полностью отличается от файла readme, который отличается от двух разных файлов Readme и ReadMe.То же самое относится и к именам каталогов.

Между тем, на вашем собственном компьютере может быть регистр в чувствительной файловой системе: здесь только один файл, имя которого является первым из тех, которые вывыбрал.Если у вас есть файл с именем ReadMe и вы открываете README, вы получите ReadMe, а не новый файл с именем README.(Это имеет место в Windows и MacOS по умолчанию.)

Точно так же, если ваш компьютер нормализует имена, такие как schön, для этого имени есть два различных варианта написания UTF-8, иGit будет рассматривать их как два разных имени файла, но ваш компьютер будет обрабатывать их как ссылки на один файл.(Это относится к MacOS; я не уверен насчет Windows.)

Если это проблема, то она достаточно распространена и с ней трудно разобраться.Лучше всего запустить систему Unix или Linux, которая не не выполняет свертывание и нормализацию, и работает с хранилищем для устранения проблемных имен файлов.Затем вы можете проверить любые зафиксированные коммиты, так как эти коммиты больше не предоставляют имена, которые приводят в действие вашу ОС.

Концы строк и другие фильтры

Помимо имен файлов, вы также видели, что Git может возиться с окончаниями строк.В репозиториях, созданных в Linux или Unix-подобных системах, обычно используются окончания строк только для новой строки (только LF), в то время как для файлов, редактируемых в системе Windows, могут потребоваться последовательности возврата каретки-новой строки (окончания CR-LF или CRLF).Чтобы разрешить межсистемную работу, Git предлагает возможность, но не обязательное выполнение некоторых хитрых изменений в конце строки.

В общем случае это работает так, что Git ссылается на некоторые файлы как clean и некоторые как нечеткое .То, что хранится в коммитах и ​​в индексе, т. Е. В сжатом формате Git-only, всегда считается clean .Всякий раз, когда Git копирует файл из индекса в рабочее дерево, он размазывает файл и всякий раз, когда он копирует этот же файл из рабочего дерева обратно в индекс, он очищает файл.

Если вы включите окончания строк CRLF, процесс смазывания включает в себя изменение только LF на CRLF, а процесс очистки включает в себя изменение CRLF только на LF. 2 Это означает, что приПока все файлы в хранилище действительно чистые, они должным образом загрязняются в вашей системе Windows и повторно очищаются, когда вы git add делаете их перед git commit очищенными файлами.

Но - этоключевой момент здесь - весь этот процесс является необязательным. Пользователи Linux не платят ни за что из этого, потому что они отключают все это, и хранилище Git на стороне Linux затем сохраняет все, что находится врабочее дерево в индексную версию, , даже если файл рабочего дерева имеет окончания строк CRLF. Затем они могут быть зафиксированы, так что содержимое коммитов включает окончания CRLF.

Если вы извлекаете такой файл на компьютер с Windows и включаете очистку CRLF, преобразование index-> ​​work-tree оставляет CRLF в покое.Но теперь у всех файлов рабочего дерева свои CRLF будут изменены только на LF, поэтому они больше не совпадают!Все они мгновенно изменены (но еще не готовы к фиксации).

Эта ситуация также очень сложная, потому что Git пытается различными способами узнать, когда файлы рабочего дерева пачкаются или очищаются без запускаих через все процессы размазывания и очистки.(Это довольно медленно - очень медленно, в некоторых случаях - так что это обычно важно.) Но это означает, что "измененность" файлов несколько непредсказуема и ее трудно диагностировать.Хитрость заключается в проверке содержимого необработанного файла, что проще всего, если вы снова клонируете репозиторий в системе Linux, где нет никаких манипуляций со всеми окончаниями строк.Затем вы можете использовать инспектор с учетом конца строки, чтобы увидеть, что находится в файле.

(Вы можете сделать это в других системах, используя git cat-file -p, чтобы извлечь определенные файлы без каких-либо пятен или других фильтров или преобразований текста,и исследовать полученный поток байтов с помощью инспектора, осведомленного о конце строки. Как это сделать в Windows, я понятия не имею - я, как правило, избегаю систем Windows. MacOS имеет cat -v и hexdump.)


2 Здесь мы говорим «включает», а не «состоит из», потому что вы можете написать свои собственные пятна и чистые фильтры, которые применяются в дополнение к настройка CRLF.

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