Git说有变化,但是没有变化 [英] Git says there are changes but there are none

查看:352
本文介绍了Git说有变化,但是没有变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我无法放弃对文件的更改,我会使用git reset --hard,没有错误,但更改仍然存在.我尝试了其他StackOverflow文章中的一些建议.

First, I was unable to discard changes to a file, I'd use git reset --hard, no errors, but the changes remained. I tried several suggestions from other StackOverflow articles.

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


git rm --cached [fileName]

我什至销毁了我的存储库,并在克隆新的存储库后立即拥有相同的修改文件.如果我手动更改文件(使用编辑器删除GIT的不同之处),则现在可以在修改后的列表中看到两次(例如,当我运行git status时,我看到的文件具有相同的路径)在未暂存的文件下两次).最终找到了一个实际上可以重设文件并将其从修改后的列表中删除的文件.

I even blew away my repo, and immediately upon cloning the repo fresh it had the same modified file. If I manually make changes to the file(remove what GIT things is different using an editor) , I can see it in the modified list twice now (as in, when I run git status I see the same file with the same path listed twice under unstaged files). Finally finding this one that actually reset the file and removed it from the modified list.

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

现在,我试图切换分支,它说更改将被覆盖,我必须提交或存储我的更改,但是,当我运行git stash时,它告诉我没有更改.我尝试了一些建议,包括尝试更新行尾,但是没有什么可以让我结帐分支.分支中确实有一个"/",可能会引起问题吗?

Now, I tried to switch branches and it says changes will be overwritten, I must commit or stash my changes, yet, when I run git stash it tells me there are no changes. I've tried several suggestions, including trying to update line endings and nothing is letting me checkout a branch. The branch does have a "/" in it, could that be causing issues?

C:\ git \ azureWebApps \ CRM-WebAPI(qa-> origin)λgit status
在分支机构Qa
您的分支机构最新信息为"origin/qa".

C:\git\azureWebApps\CRM-WebAPI (qa -> origin)λ git status
On branch qa
Your branch is up to date with 'origin/qa'.

什么也没提交,工作树很干净

nothing to commit, working tree clean

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

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

C:\ git \ azureWebApps \ CRM-WebAPI(qa-> origin)λgit checkout功能/PEN-146-CreateUpdatePerson
错误:您对以下文件的本地更改将被> checkout覆盖: CRM-RestAPI/web.config
在切换分支之前,请先提交更改或存储更改.
中止

C:\git\azureWebApps\CRM-WebAPI (qa -> origin)λ git checkout feature/PEN-146-CreateUpdatePerson
error: Your local changes to the following files would be overwritten by > checkout: CRM-RestAPI/web.config
Please commit your changes or stash them before you switch branches.
Aborting

C:\ git \ azureWebApps \ RM-WebAPI(qa-> origin)λgit stash
没有要保存的本地更改

C:\git\azureWebApps\RM-WebAPI (qa -> origin)λ git stash
No local changes to save

推荐答案

[注意:这毕竟是文件名大小写的问题;参见下面的编辑".]

[Note: this turned out to be a file name case issue after all; see "edit" below.]

...刚克隆回购协议后,它具有相同的修改文件

... immediately upon cloning the repo fresh it had the same modified file

这意味着正在发生以下两种情况之一:

This means one of two things is going on:

  • 文件正在更改,或者
  • Git的想法是哪个文件与您的计算机上的实际情况不符.
  • the file is getting changed, or
  • Git's idea of which file is which does not correspond to reality on your machine.

如果我手动更改文件,现在可以在修改后的列表中看到两次.

If I manually make changes to the file, I can see it in the modified list twice now.

这没有意义.如果您剪切并粘贴了您的意思,将会有所帮助.

This makes less sense. It would help if you included a cut-and-paste of what you mean.

["每个注释都类似于-我将使用实际文本,但由于我自己没有问题,因此必须重新创建该文本-

[ per comments, this was something like—I would use the actual text but I have to recreate it since I don't have the issue myself—the following:

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

Git 将它们视为两个单独的文件(因为它们在区分大小写的文件系统中),如果您的 OS 区分大小写-折叠(默认情况下Windows或MacOS会执行此操作),只有一个文件以大写或小写W命名,而不是两个都用两个字母命名.这是我在下面描述的一个一般性问题的特定示例,其中Git将文件名存储为几乎任意的字节字符串,但并非所有OS都这样做.]

While Git treats these as two separate files (as they will be on a file system that is case-sensitive), if your OS does case-folding (and Windows or MacOS do this by default), there will be only one file, named with either uppercase or lowercase W, rather than both, with both letters in both cases. This is a specific example of a general issue I describe below, where Git stores file names as nearly-arbitrary byte strings, but not all OSes do so.]

由于目前尚不清楚问题到底是什么,因此尚无法解决.这可能是行尾问题,也可能是其他问题.您需要以下信息.

Since it's not clear what the problem actually is yet, it's impossible to solve it yet. It might be line-ending issues, or it might be something else. You'll need the following information.

在大多数情况下(始终包括任何新克隆),每个可见的文件都存在三个版本.通常,所有三个 都应该相同,但是它们可以 不同(有意还是无意).

In most cases—which always includes any fresh clone—each file that you can see exists in three versions. All three should normally be the same, but they can be different (on purpose or not).

无论如何,您都有一个当前提交,您可以使用以下命令找到其哈希ID:

In any case, you have a current commit, whose hash ID you can find with:

git rev-parse HEAD

当您签出不同的提交或进行新的提交时,当前提交的哈希ID会发生变化,但是总是存在一些当前提交(这里没有发生异常).

The hash ID of the current commit changes as you check out different commits or make new commits, but there's always some current commit (with an exception that doesn't occur here).

每个提交列出一堆文件,如果您git checkout那个特定提交,则应将其检出.您可以使用以下方法查看这些文件:

Each commit lists a bunch of files that should be checked out if you git checkout that particular commit. You can see those files, if you want, using:

git ls-tree -r <commit-hash>

详细显示与提交相关的每个文件.

which shows you in gory detail every file that goes with that commit.

每个提交都是只读的-存储在此提交中的文件(在此哈希ID下)被永久存储在 1 那里,并且它们永远不会更改.

Every commit is read-only—the files stored in this commit, under this hash ID, are stored permanently1 there, and they can never change.

每个文件的第二副本保存在Git的 index 中.这是您要使用git update-index --assume-unchanged进行操作的东西.索引是Git用于许多事情的中央数据结构,但最好将其描述为在其中(和Git)构建将要进行的下一次提交.因此,索引通常从完全匹配当前提交.当前提交中的每个文件在索引中也是 ,采用与Git相同的特殊,仅Git的压缩格式. (从技术上讲,索引只是共享文件的提交副本.)索引副本和提交副本之间的重要区别是可以覆盖索引副本 ,此后索引将不再共享提交文件的版本.索引副本仍采用特殊的仅Git压缩格式,但是与已提交副本不同,您可以覆盖索引副本.

The second copy of every file is kept in Git's index. This is the thing you are manipulating with git update-index --assume-unchanged. The index is a central data structure that Git uses for many things, but it's perhaps best described as where you (and Git) build the next commit you will make. As such, the index normally starts out exactly matching the current commit. Every file that is in the current commit is also in the index, in the same special, Git-only, compressed format that Git uses. (Technically the index simply shares the commit's copy of the file.) The important difference between the index copy and the commit copy is that the index copy can be overwritten, after which the index is no longer sharing the commit's version of the file. The index copy is still in the special Git-only compressed format, but unlike the committed copy, you can overwrite the index copy.

每个文件的最后一个副本是您实际使用的副本.该文件在计算机上以其日常的日常形式出现,而不是特殊的仅Git格式.因为的正常形式,所以它受您的系统施加的所有限制,因此我们可以进入有趣的部分.

The last copy of every file is the one you actually work with. This file is in its normal everyday form on the computer, not in a special Git-only format. Because it is in the normal form, it's subject to whatever limitations your system imposes, and that's where we get into the interesting parts.

1 无论如何,与提交本身一样永久.如果您让Git忘记了提交,除非其他一些提交正在共享它们,否则文件本身将消失.

1As permanent as the commit itself, anyway. If you get Git to forget about the commit, the files themselves will go away unless some other commit(S) is/are sharing them.

我们可以通过标记三个副本来说明它们:

We can illustrate the three copies by labeling them a bit:

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

,依此类推. Git在这些不同版本之间复制文件,但HEAD(提交)版本始终是只读的,因此要更改"提交的版本,Git会根据其中的内容构建一个 new 提交.索引立即.

and so on. Git copies the files between these various versions, except that the HEAD (committed) version is always read-only, so to "change" the committed version, Git builds a new commit from whatever is in the index right now.

git status命令通过首先将每个文件的HEAD版本与每个文件的索引版本进行比较来告诉您这些信息.如果此处有所不同,则git status打印文件的名称,并告诉您这是准备提交的更改.然后,它将每个文件的索引版本与每个文件的工作树版本进行比较.如果此处有所不同,git status会打印文件的名称,并告诉您这是尚未准备提交的更改.

The git status command tells you about these by comparing, first, the HEAD version of every file to the index version of every file. If something is different here, git status prints the file's name and tells you that this is a change that is ready to be committed. Then, it compares the index version of every file to the work-tree version of every file. If something is different here, git status prints the file's name and tells you that this is a change that is not yet staged for commit.

git checkout命令将文件从提交复制到索引和工作树,或从索引复制到工作树. (这些命令应该是单独的命令,并且应该是同一时刻.)git reset命令将文件从提交复制到索引,而不是复制到工作树. git add命令将文件从工作树复制到索引. git commit命令根据索引中的内容进行 new 提交,然后进行排列,以使HEAD现在引用新的提交.

The git checkout command copies files from a commit to the index and work-tree, or from the index to the work-tree. (These should be separate commands—and were at one point.) The git reset command copies files from the commit to the index, but not to the work-tree. The git add command copies files from the work-tree to the index. The git commit command makes a new commit from whatever is in the index, and then arranges things so that HEAD now refers to the new commit.

现在您知道各个部分中的内容,这就是可能出问题的地方.

Now that you know what's in the various parts, here's where things can go wrong.

提交和索引中存储的文件的名称只是Git中的字节字符串.正如该短语所说,Git通常是编码agnositc",只是它使用斜杠将目录名与子目录和文件分开,并使用ASCII NUL字节终止这些字节字符串.这允许Git使用UTF-8编码文件名,因为UTF-8编码绝不会将除斜杠/(ASCII 0x2f)以外的任何字符编码为字节码0x2f.如果您使用的是使用反斜杠而不是斜杠的系统,则它也可以在内部允许正斜杠,或者Git根据需要转换斜杠,以便一切正常.

The names of files stored in commits and in the index are just byte-strings in Git. Git is generally "encoding agnositc", as the phrase goes, except that it uses slashes to separate directory names from sub-directories and files, and an ASCII NUL byte to terminate these byte-strings. This allows Git to use UTF-8 to encode file names, since UTF-8 encoding never encodes any character other than the slash / (ASCII 0x2f) as byte code 0x2f. If you're on a system that uses backslash instead of slash, either it also allows forward slash internally, or Git translates the slashes as necessary, so that this all works.

这也意味着 Git 的文件名区分大小写:文件README与文件readme完全不同,文件readme与两个不同的文件Readme不同和ReadMe.目录名称也是如此.

This also means that Git's file names are case-sensitive: the file README is entirely different from the file readme, which is different from the two different files Readme and ReadMe. The same holds for directory names.

同时,您自己的计算机上可能有区分大小写的文件系统:这里只有一个文件,文件名以您选择的第一个为准.如果您有一个名为ReadMe的文件并打开README,则将得到ReadMe,而不是一个名为README的新文件. (默认情况下,在Windows和MacOS上就是这种情况.)

Meanwhile, your own computer may have a case-insensitive file system: there's only one file here, whose name is whichever is the first of those you chose. If you have a file named ReadMe and you open README, you get ReadMe, not a new file named README. (This is the case on Windows and MacOS by default.)

类似地,如果您的计算机像schön这样的名称对进行标准化,则此名称会有两种不同的UTF-8拼写,Git会将它们视为两个不同的文件名,但是您的计算机将将它们视为引用一个文件. (在MacOS上就是这种情况;我不确定Windows.)

Similarly, if your computer normalizes names like schön, there are two different UTF-8 spellings for this name, and Git will treat them as two different file names, but your computer will both treat them as referring to one file. (This is the case on MacOS; I am not sure about Windows.)

如果这是问题所在,则相当普遍且难以处理.最好的选择是建立一个Unix或Linux系统,该系统进行大小写折叠和规范化,并与存储库一起使用以消除有问题的文件名.然后,您可以签出所有已修复的提交,因为这些提交不再提供可在您的操作系统上运行的名称.

If this is the problem, it's rather pervasive and difficult to deal with. Your best bet is to bring up a Unix or Linux system, which doesn't do case-folding and normalization, and work with the repository to eliminate the problematic file names. You can then check out any of the commits that has been fixed, since those commits no longer provide names that trip up your OS.

除了文件名之外,您还已经看到Git可以摆弄行尾.在Linux或类似Unix的系统上创建的存储库通常将使用仅换行符(仅LF)的行尾,而在Windows系统上进行编辑的文件可能需要回车换行符序列(CR-LF或CRLF结尾).为了启用跨系统工作,Git提供了进行一些偷偷摸摸的行尾更改的功能,但不是必需的.

Aside from file names, you have also seen that Git can fiddle with line endings. Repositories made on a Linux or Unix-like system will generally use newline-only (LF-only) line endings, while files to be edited on a Windows system may require carriage-return-newline sequences (CR-LF or CRLF endings). To enable cross-system work, Git offers the ability, but not the requirement, to do some sneaky line-ending changes.

一般来说,它的工作方式是Git将某些文件称为 clean ,而将某些文件称为 smudged .提交和索引中存储的内容(即压缩的仅Git格式)始终假定为 clean .每当Git将文件从索引复制到工作树时,它都会弄脏,并且每当它从工作树中将同一文件复制到索引中时,它都会清除 文件.

The way this works in general is that Git refers to some files as clean and some as smudged. What's stored in commits and in the index—i.e., in the compressed Git-only format—is always assumed to be clean. Whenever Git copies a file from the index to the work-tree, it smudges the file, and whenever it copies that same file from the work-tree back into the index, it cleans the file.

如果启用CRLF行尾,污迹处理包括将仅LF更改为CRLF,清除过程包括将CRLF更改为仅LF. 2 这意味着只要其中的所有文件该存储库是真正干净的,在Windows系统上它们已被正确弄脏,并且在git commit清理后的文件之前重新清理它们.

If you enable CRLF line endings, the smudging process includes changing LF-only to CRLF, and the cleaning process includes changing CRLF to LF-only.2 This means that as long as all files in the repository are truly clean, they become properly smudged on your Windows system, and are re-cleaned when you git add them before you git commit the cleaned files.

但是-这是关键点-所有此过程都是可选的. Linux用户无需为此付费,因为他们将所有功能都关闭了,而Linux方面然后,Git存储库将工作树中的所有内容存储到索引版本中,即使工作树文件具有CRLF行结尾也是如此.然后可以提交这些结尾,以便提交的内容包括CRLF.结局.

But—this is the key point here—all of this process is optional. The Linux users don't pay for any of it because they turn all of it off, and the Linux-side Git repository then stores whatever is in the work-tree into the index version, even if the work-tree file has CRLF line endings. These can then be committed, so that the commits' contents include the CRLF endings.

如果将这样的文件解压缩到Windows机器上并启用了CRLF清理,则索引->工作树转换将仅保留CRLF.但是现在所有工作树文件的CRLF都将更改为仅LF,因此它们不再匹配!它们都被立即更改(但尚未准备好提交).

If you extract such a file onto a Windows machine and have CRLF cleaning turned on, the index->work-tree conversion leaves the CRLFs alone. But now all the work-tree files will have their CRLFs changed to LF-only, so they no longer match! They're all instantly changed (but not yet ready to be committed).

这种情况也非常棘手,因为Git尝试通过各种方式来了解何时弄脏或清除了工作树文件,而没有在所有的弄脏和清理过程中运行它们. (这有点慢-在某些情况下非常慢-因此通常很重要.)但是,这意味着文件的更改"在某种程度上是不可预测的并且难以诊断.诀窍是检查原始文件的内容,这是最简单的方法,如果您再次在Linux系统上克隆存储库,则在所有行尾都没有任何操作.然后,您可以使用可识别行尾的检查器来查看文件中的内容.

This situation is also extra-tricky because Git attempts, through various means, to know when work-tree files are smudged or clean without running them through all the smudging and cleaning processes. (It's kind of slow—very slow, in some cases—so this is usually important.) But this means that the "changed-ness" of files is somewhat unpredictable and hard to diagnose. The trick is to inspect the raw file content, which is easiest if you once again clone the repository on a Linux system, where there's no manipulation at all of line endings. You can then use a line-ending-aware inspector to see what's in the file.

(您可以在使用git cat-file -p的其他系统上执行此操作,以提取特定文件,而不会进行任何混淆或其他过滤器或文本转换,并使用可识别行尾的检查器检查生成的字节流.在Windows上,我不知道-我通常会避开Windows系统.MacOS具有cat -vhexdump.)

(You can do this on other systems using git cat-file -p to extract particular files without any smudging or other filters or text conversions, and examine the resulting byte-stream with a line-ending-aware inspector. How to do the latter on Windows, I have no idea—I avoid Windows systems, as a rule. MacOS has cat -v and hexdump.)

2 在这里我们说包括"而不是由……组成"是因为您可以编写自己的污迹和干净的过滤器,这些过滤器除了对CRLF进行调整外,还用于

2We say "includes" rather than "consists of" here because you can write your own smudge and clean filters, which are applied in addition to the CRLF tweaking.

这篇关于Git说有变化,但是没有变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆