git checkout错误,即使git status报告工作树是干净的 [英] git checkout errors even though git status reports that working tree is clean

查看:211
本文介绍了git checkout错误,即使git status报告工作树是干净的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在本地的my-feature分支

git status报告nothing to commit, working tree clean

我想切换到开发分支并在那里做git fetchgit merge(我更喜欢git pull)

I want to switch to develop branch and do git fetch and git merge there (I prefer it over git pull)

但是,这样做会在下面产生错误

However, doing so produces error below

我首先在这里检查状态,结果表明一切都很好

Here I first check status and it shows that all is clean

mymbp:MyProj username$ git status
On branch my-feature
nothing to commit, working tree clean

接下来,我尝试签出我的开发分支,这是一个现有的本地分支

Next I try to checkout my develop branch which is an existing local branch

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

它抱怨说即使git status说什么都没有改变,myProj.sln也已被更改.

It complains that myProj.sln has been changed even though git status says nothing has changed.

再次发出git status,确认没有任何变化

Issuing git status again, confirms that nothing has changed

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标志):

Doing git ls-files --stage --debug MyProj.sln shows like below and I dont see any 4000 or 8000 (--skip-worktree or --assume-unchanged flags):

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的数量,用于解决方案前后的Global部分,但是输出很长,仅显示Release,Debug配置和一些GUIDS.尚不确定该怎么办.

Issuing git show develop:MyProj.sln shows me number of project files and their GUIDs in the solution, Global sections for pre and post solution but the output is very long showing just Release, Debug configurations and some GUIDS. Not sure what to do with that yet.

更新2

因此,它的接缝好像MyProj.sln文件在工作树中,而不在索引和提交(HEAD)中.根据@torek的解释,发出git add MyProj.sln应该将这个文件添加到索引中,但这是不正确的,因为没有添加任何内容,并且在执行git add之前和执行之后git status均不返回任何内容.同时git checkout仍然抱怨MyProj.sln已更改. git diff也什么都不返回

So, it seams as if MyProj.sln file is in work-tree but not in index and commit (HEAD). Based on @torek explanation, issuing git add MyProj.sln should add this file to index but that is not true since nothing is added and git status returns nothing before I did git add and after I did it. Meanwhile git checkout still complains that MyProj.sln has changed. git diff also returns nothing

更新3

我还发现有人建议发出这两个命令来获取提交HEAD的哈希值,然后查看其中的更改.我看到很多文件重复,有些则没有.那些似乎不是我在当前功能分支中添加的文件.那些重复的文件似乎是来自远程的文件

I also found someone suggest issuing these 2 command to get hash of commit HEAD and to then see what changed in it. I see lots of files duplicate, while some do not. Those that do not appear to be files I added in my current feature branch. Those that are duplicate appear to be files from remote

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$ 

推荐答案

每次更新这里肯定有些奇怪,尽管很难确定是什么(捕获的输出是图像,因此无法检查奇怪的Unicode.问题).在提交树的git ls-tree -r输出中,任何文件都不应列出两次.我从未从Git中看到过这种行为.大写和小写都有 问题,尤其是在Windows和MacOS上,可能会导致这种行为,但与您在此处显示的内容不符.

Edit per updates: Something is definitely odd here, though it's hard to say for sure what (the captured output is images so it's not possible to check for weird Unicode issues, for instance). No file should ever be listed twice in git ls-tree -r output on a commit-tree. I have never seen this kind of behavior from Git. There are issues with uppercase vs lowercase, especially on Windows and MacOS, that can cause this kind of behavior, but that doesn't match what you're showing here.

首先,请注意:您的标签提到了MacOS. MacOS文件系统默认情况下不区分大小写,因此,如果您有一个名为README.TXT的文件并要求系统查看名为readme.txt的文件,它将显示为README.TXT.如果您要求系统添加一个名为readme.txt的新文件,它将代替 overwite 现有的 README.TXT并保留大写名称.因此,请注意其名称仅在以下情况下不同的文件:Git提交可能具有myproj.sln文件,它将覆盖您的MyProj.sln文件.

First, a quick note: your tags mention MacOS. MacOS file systems are by default case-insensitive, so that if you have a file named README.TXT and ask the system to view the file named readme.txt, it shows you README.TXT. If you ask the system to add a new file named readme.txt it will instead overwite the existing README.TXT and keep the uppercase name. So watch out for files whose name differs only in case: the Git commit might have a myproj.sln file that will overwrite your MyProj.sln file.

至少有两种可能性,但让我们首先考虑最可能的可能性:

There are at least two possibilities, but let's take the most likely first:

  • 这意味着存在一个不在当前索引和提交中但在当前工作树中名为MyProj.sln的文件.您要求Git进行git checkout的提交中的同一文件 .因此,如果您成功地git checkout其他提交,则Git将覆盖工作树文件. Git警告您,您将丢失该文件的 current 内容.

  • This means there is a file that is not in the current index and commit, but is in the current work-tree, named MyProj.sln. This same file is in the commit you've asked Git to git checkout. So Git will overwrite the work-tree file if you do successfully git checkout that other commit. Git is warning you that you will lose the current contents of that file.

或者,在当前索引和工作树中有一个名为MyProj.sln的文件.工作树副本与索引副本不匹配.通常,git status会告诉您文件已被修改,但是您已经设置了两个指示Git的索引标志位之一:不要查找文件的更改,和/或不告诉如果您不小心发现了一些变化,请与我联系,只需将索引副本保持原样即可.这两个标志位是--assume-unchanged--skip-worktree.

Or, there is a file that is in the current index and work-tree, named MyProj.sln. The work-tree copy does not match the index copy. Normally, git status would tell you that the file is modified, but you've set one of the two index flag bits that tell Git: don't look for changes to the file, and/or don't tell me about changes if you accidentally find some, just keep the index copy around the way it is. These two flag bits are --assume-unchanged and --skip-worktree.

在这两种情况下,如果您确实成功检出了要Git检出的提交,则将覆盖MyProj.sln的工作树副本.如果可以,请立即继续并删除文件,然后git checkout将继续.

In both cases, if you do successfully check out the commit you're asking Git to check out, that will overwrite the work-tree copy of MyProj.sln. If that is OK, just go ahead and remove the file now, and the git checkout will proceed.

要查看情况是什么

git ls-files --stage --debug MyProj.sln

如果没有输出,则文件不在索引中(因此也基于git status输出或缺少输出而不在当前提交中).反过来,这意味着此刻它只是一个未跟踪的工作树文件.

If you get no output, the file is not in the index (and hence also not in the current commit, based on the git status output, or lack of output). That in turn means that it's just an untracked work-tree file at the moment.

如果您确实获得了输出,它应该类似于我在另一个文件中得到的输出:

If you do get output, it should resemble this output that I get here for a different file:

$ 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>显示了假设不变的和skip-worktree位,尽管不是人类友好的格式:skip-worktree是4000而另一个是8000(如果都设置了,您将得到c000).设置skip-worktree位,我实际上得到:

The flags: <number> shows the assume-unchanged and skip-worktree bits, although not in a human-friendly format: skip-worktree is 4000 and the other is 8000 (if both are set you'll get c000). Setting the skip-worktree bit, I actually get:

size: 96311   flags: 40004000

在设置假定不变的位时会得到:

while setting the assume-unchanged bit gives me:

size: 96311   flags: 8000


您要切换到的提交(develop的提示)具有文件的提交版本,您可以通过以下方式查看该文件的提交版本(没有覆盖当前副本):


The commit you're asking to switch to (the tip of develop) has a committed version of the file, which you can see (without having it overwrite the current copy) with:

git show develop:MyProj.sln

请注意,一旦您git checkout develop,该文件将位于所有三个活动位置:当前提交,索引和工作树.如果my-feature的尖端提交 没有文件,则从develop切换回my-feature将会从工作树中删除文件.记住其中大部分的方法是:

Note that once you git checkout develop, that file will be in all three active places: the current commit, the index, and the work-tree. If the tip commit of my-feature does not have the file, switching back from develop to my-feature will remove the file from the work-tree. The way to remember most of this is:

  • 通过索引进行提交.
  • 因此,
  • 商品首先被提取到索引中(然后提取到工作树中).
  • 索引跟踪工作树中应提交的内容.索引副本是提交的副本. git status将索引与工作树进行比较,以告诉您应复制到索引中的内容.
  • 切换提交时,索引中没有但需要基于新提交的工作树文件得到创建; 文件>在索引中,但是需要根据新提交出现在该索引中,然后将其删除.
  • 索引中没有
  • 工作树中的文件未被跟踪,并且被单独保留.
  • Commits are made from the index.
  • Commits are therefore extracted into the index first (and then on into the work-tree).
  • The index keeps track of what's in the work-tree that should be committed. The index copy is the one that goes into the commit. git status compares the index to the work-tree to tell you what you should copy into the index.
  • When switching commits, work-tree files that aren't in the index, but need to be based on the new commit, get created; files that are in the index, but need to not be there based on the new commit, get removed.
  • Files in the work-tree that aren't in the index are untracked, and are left alone.

在那之后,假设设置不变和跳过工作树位(如果您进行了设置)只是对原本基本一致的规则的细微调整. .gitignore规则也开始变得有意义:.gitignore中列出的文件是git status 不会抱怨未被跟踪的文件. (但是,一个重要的副作用是,在某些情况下,.gitignore使Git可以自由地 clobber 这样的未经跟踪的文件,很难记住,也很难解释.)

After that point, the assume-unchanged and skip-worktree bits, if you set them, are just minor tweaks to the otherwise largely self-consistent rules. The .gitignore rules start to make sense as well: a file listed in .gitignore is one that git status won't complain about as being untracked. (However, an important side effect, that .gitignore makes Git feel free to clobber such untracked files in some cases, is tougher to remember, or explain for that matter.)

这篇关于git checkout错误,即使git status报告工作树是干净的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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