git checkout 错误,即使 git status 报告工作树是干净的
Posted
技术标签:
【中文标题】git checkout 错误,即使 git status 报告工作树是干净的【英文标题】:git checkout errors even though git status reports that working tree is clean 【发布时间】:2019-04-12 08:04:52 【问题描述】:我在本地my-feature
分店
git status
举报nothing to commit, working tree clean
我想切换到开发分支并在那里做git fetch
和git merge
(我更喜欢它而不是git pull
)
但是,这样做会产生以下错误
这里我首先检查状态,它表明一切都很干净
mymbp:MyProj username$ git status
On branch my-feature
nothing to commit, working tree clean
接下来我尝试检查我的开发分支,它是一个现有的本地分支
On branch my-feature
nothing to commit, working tree clean
mymbp:MyProj username$ git checkout develop
error: Your local changes to the following files would be overwritten by checkout:
MyProj.sln
Please commit your changes or stash them before you switch branches.
Aborting
它抱怨myProj.sln
已更改,即使git status
表示没有任何更改。
再次发出git status
,确认没有任何变化
mymbp:MyProj username$ git status
On branch my-feature
nothing to commit, working tree clean
更新 1
执行git ls-files --stage --debug MyProj.sln
如下所示,我没有看到任何 4000 或 8000(--skip-worktree
或 --assume-unchanged
标志):
mymbp:MyProj username$ git ls-files --stage --debug MyProj.sln
100644 40c3593ed572beb2139c189455274f8900a1340c 0 MyProj.sln
ctime: 1541703970:521058155
mtime: 1541637062:121492660
dev: 16777220 ino: 8470003
uid: 501 gid: 20
size: 55684 flags: 0
mymbp:MyProj username$
发布git show develop:MyProj.sln
会显示解决方案中的项目文件数量及其 GUID,用于前后解决方案的全局部分,但输出很长,仅显示发布、调试配置和一些 GUID。还不知道该怎么处理。
更新 2
因此,似乎 MyProj.sln 文件在工作树中,但不在索引和提交 (HEAD) 中。根据@torek 的解释,发出 git add MyProj.sln 应该将此文件添加到索引中,但事实并非如此,因为没有添加任何内容,并且 git status 在我执行 git add 之前和之后都没有返回任何内容。同时 git checkout 仍然抱怨 MyProj.sln 已更改。 git diff 也不返回任何内容
更新 3
我还发现有人建议发出这 2 个命令来获取提交 HEAD 的哈希值,然后查看其中发生了什么变化。我看到很多文件重复,而有些则没有。那些似乎不是我在当前功能分支中添加的文件。那些重复的似乎是来自远程的文件
mymbp:MyProj username$ git rev-parse HEAD
1ca8d8a7c5eff0f2a03eb185f1b25aff27c1d2fd
mymbp:MyProj username$ git ls-tree -r 1ca8d8a7c5eff0f2a03eb185f1b25aff27c1d2fd
这是它的输出
更新 4
我的配置是:
mymbp:MyProj username$ git config --list
credential.helper=osxkeychain
core.excludesfile=/Users/username/.gitignore_global
core.autocrlf=input
difftool.sourcetree.cmd=opendiff "$LOCAL" "$REMOTE"
difftool.sourcetree.path=
mergetool.sourcetree.cmd=/Applications/Sourcetree.app/Contents/Resources/opendiff-w.sh "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED"
mergetool.sourcetree.trustexitcode=true
user.name=User Name
user.email=username@somesystems.com
color.ui=true
color.status.changed=blue normal
color.status.untracked=red normal
color.status.added=magenta normal
color.status.updated=green normal
color.status.branch=yellow normal bold
color.status.header=white normal bold
commit.template=/Users/username/.stCommitMsg
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
core.precomposeunicode=true
remote.origin.url=https://github.com/SomeSystems/MyProj.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.develop.remote=origin
branch.develop.merge=refs/heads/develop
branch.feat-1.remote=origin
branch.feat-1.merge=refs/heads/feat/feat-1
branch.1234-refactoring.remote=origin
branch.1234-refactoring.merge=refs/heads/1234-refactoring
mymbp:MyProj username$
【问题讨论】:
文件MyProj.sln
真的被添加到当前分支了吗?
另一个 git status 怎么说
它已经存在了几个月,但无论如何,即使添加了它,git status 也应该将其视为未跟踪。另一个 git 状态?每次我在这个分支中执行 git status 时,它说工作树是干净的,我重新启动并尝试了几次,每次结果都和上面一样
如果您有未跟踪的文件并且您收到该消息,可能是因为它已被添加到分支(由其他人?)。
不,这是我的本地功能分支,没有人碰过它。另外,该文件未显示为未跟踪。 Git status 显示没有任何变化, git commit 显示它已经如上文所述。我更新为 clerify
【参考方案1】:
每次更新编辑:这里肯定有些奇怪,尽管很难确定是什么(捕获的输出是图像,因此无法检查奇怪的 Unicode 问题,例如)。任何文件都不应该在提交树的git ls-tree -r
输出中列出两次。我从未在 Git 中看到过这种行为。 存在大写和小写的问题,尤其是在 Windows 和 MacOS 上,可能会导致这种行为,但这与您在此处显示的内容不符。
原答案如下
首先,快速说明:您的标签提到了 MacOS。 MacOS 文件系统默认不区分大小写,因此如果您有一个名为README.TXT
的文件并要求系统查看名为readme.txt
的文件,它会显示README.TXT
。如果您要求系统添加一个名为 readme.txt
的新文件,它将改为 覆盖 现有 README.TXT
并保留大写名称。因此,请注意名称不同的文件,以防万一:Git 提交可能有一个 myproj.sln
文件,该文件将覆盖您的 MyProj.sln
文件。
至少有两种可能性,但让我们先看最有可能的:
这意味着有一个文件不在当前索引和提交中,但在在当前工作树中,名为MyProj.sln
。在您向 Git 提交给git checkout
的提交中是。因此,如果您成功完成git checkout
其他提交,Git 将覆盖工作树文件。 Git 警告您,您将丢失该文件的 当前 内容。
或者,当前索引和工作树中有一个是的文件,名为MyProj.sln
。工作树副本与索引副本不匹配。通常,git status
会告诉您文件已被修改,但您设置了告诉 Git 的两个索引标志位之一:不要查找文件的更改,和/或不要告诉如果你不小心发现了一些更改,请保持索引副本保持原样。这两个标志位是--assume-unchanged
和--skip-worktree
。
在这两种情况下,如果您确实成功签出了您要求 Git 签出的提交,那将覆盖 MyProj.sln
的工作树副本。如果没问题,请立即删除文件,git checkout
将继续。
看看是什么情况:
git ls-files --stage --debug MyProj.sln
如果没有输出,则该文件不在索引中(因此也不在当前提交中,基于git status
输出或缺少输出)。这反过来意味着它目前只是一个未跟踪的工作树文件。
如果你确实得到了输出,它应该类似于我在这里为不同的文件得到的输出:
$ git ls-files --stage --debug Makefile
100644 b08d5ea258c69a78745dfa73fe698c11d021858a 0 Makefile
ctime: <number>:<number>
mtime: <number>:<number>
dev: <number> ino: <number>
uid: <number> gid: <number>
size: <number> flags: <number>
flags: <number>
显示了假设不变和跳过工作树位,尽管不是人类友好的格式:跳过工作树是4000
,另一个是8000
(如果两者都设置了,你会得到c000
)。设置skip-worktree位,我实际上得到:
size: 96311 flags: 40004000
虽然设置假设不变位给了我:
size: 96311 flags: 8000
您要求切换到的提交(develop
的提示)具有该文件的已提交版本,您可以通过以下方式查看(不会覆盖当前副本):
git show develop:MyProj.sln
请注意,一旦您git checkout develop
,该文件将位于所有三个活动位置:当前提交、索引和工作树。如果my-feature
的提示提交确实没有 有该文件,则从develop
切换回my-feature
将从工作树中删除该文件。记住大部分内容的方法是:
git status
将索引与工作树进行比较,以告诉您应该将什么复制到索引中。
切换提交时,不在索引中但需要基于新提交的工作树文件,创建;文件>是在索引中,但需要不基于新的提交,得到删除。
工作树中不在索引中的文件未被跟踪,并且被单独留下。
在那之后,假设不变和跳过工作树位(如果您设置它们)只是对原本基本上自洽的规则的微小调整。 .gitignore
规则也开始变得有意义:.gitignore
中列出的文件是 git status
不会抱怨未被跟踪的文件。 (然而,一个重要的副作用是,.gitignore
让 Git 在某些情况下可以随意破坏这些未跟踪的文件,这更难记住或解释。)
【讨论】:
如果文件不在在索引中,git add
会将它复制到索引中,现在它在在索引中并且将在您进行的下一次提交中。如果您希望它被提交(永久保存,或者至少只要提交本身继续存在),就这样做。
没有看到更新,但它们很奇特。任何文件都不应以相同的名称列出两次;这里很多都列出了两次(也有相同的 blob 哈希 ID)。这些名称似乎并不复杂:例如,没有明显的大写与小写问题。可能存在 UTF-8 编码的名称,但通常会在名为 schön
的文件中看到此问题,而且我在这里也看不到重音符号。
行尾不影响 Git 内部数据结构。您可以使用 git ls-tree -r HEAD | vis -ctl
将制表符和换行符显示为 \t
和 \$
,但我怀疑有人一直在使用损坏的 Git 版本并生成坏树对象。
嗯,是的,\$
的重点是让任何 尾随 空格可见,以防一个文件名为 X 而另一个名为 Xvis
命令还将对各种控制和转义序列进行编码,以便它们变得可见; -t
编码标签(如\011
或-c
,如\t
)。以上是关于git checkout 错误,即使 git status 报告工作树是干净的的主要内容,如果未能解决你的问题,请参考以下文章