如果我更改文件、添加更改、提交并拉取,Git 会声称我有未提交的更改。当我再次尝试提交时,我收到一条“无需提交,工作树干净”的消息。
[Annas-MacBook-Pro:Project Anya$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 4 and 3 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
Annas-MacBook-Pro:Project Anya$ git pull origin master
anna@anna-git's password:
From ssh://anna-git/git/Project
* branch master -> FETCH_HEAD
error: Your local changes to the following files would be overwritten by merge:
index.html
js/app.js
sass/custom.scss
Please commit your changes or stash them before you merge.
Aborting
Run Code Online (Sandbox Code Playgroud)
我确定我没有再次更改文件,但即使某些东西以某种方式更改了它们,它也不会让我再次提交它们。为什么 git 认为我有本地更改?我该如何解决这个问题?
--assume-unchanged或--skip-worktree你使用这些标志让 Git 对你撒谎,以便让事情对你更方便。但是现在,谎言又回来咬你了。
请注意,这git pull仅表示“运行git fetch,然后运行第二个命令,通常git merge”并且错误来自该git merge步骤。所以并不是pull失败了;它的合并失败了。这很重要,因为有关失败原因以及如何处理的答案与使用git merge和不使用git pull. (这是很多原因,我建议避免一个git pull:它隐藏了太多从你那很好,当一切工程.... :-))
这种失败有两种可能的原因,通过两种略有不同的消息来区分。在这两种情况下,我们可以肯定地说你有这些文件。
以下是合并失败的关键行:
Run Code Online (Sandbox Code Playgroud)error: Your local changes to the following files would be overwritten by merge: index.html js/app.js sass/custom.scss
作为一个重要的旁注,它指的是对这些文件的本地更改,而不仅仅是“这些本地文件”。此错误消息的另一种形式开始代替The following untracked working tree files。如果您收到该错误,我们会知道一些密切相关但又不完全相同的信息。
这是git status输出:
Run Code Online (Sandbox Code Playgroud)nothing to commit, working tree clean
考虑到第一个抱怨的措辞,这似乎是——见鬼,这是——矛盾的。但是对此有一个解释,与index 有关。
git statusGit 的索引是,大致上,您构建下一次提交的位置。当您几乎准备好进行提交时——已经修改了要修改的任何工作树文件,删除了要删除的任何工作树文件,并添加了要添加的任何新工作树文件——您必须做两件事进行新的提交:
git add),以及git commit原因是从 index而不是从工作树git commit进行新提交。因此,您必须将任何新版本的文件复制到索引中,或者从索引中删除任何已删除的文件。
当你运行时git status,Git 运行两个 git diffs。一个将当前提交(称为 )HEAD与索引进行比较。另一个将索引与工作树进行比较。第一个git diff告诉您已经复制到索引的内容(如果有),以便在您进行的下一次提交中有所不同。第二个git diff告诉你在你的工作树中有什么改变,如果有的话,但没有复制到索引,所以它必须在git add它进入你的下一次提交之前被编辑。
第二个git diff也可以找到未跟踪的文件。未跟踪的文件只是“工作树中不在索引中的文件”。这真的很简单:文件必须在工作树中,不能在索引中,才能不被跟踪。
通常,当 Git 发现未跟踪的文件时,它会抱怨它们: 你不想提交这个文件吗?不是吗?嗯?嗯? 您可以通过将它们添加到文件中(列出它们的名称或与它们匹配的名称模式)来关闭它们.gitignore。这使 Git 关闭,但不会使文件未被跟踪:这仍然由“在工作树中,但不在索引中”决定。
一旦文件的索引,Git会一直告诉你,你的工作树中的文件被更新。 你不想提交这个文件吗?不是吗?嗯?嗯? 你可以不关混帐了这个用.gitignore:该文件是在指数; 他们被“跟踪”;列出它们.gitignore没有任何效果。
如果你想让 Git 不再像迷路的小狗一样发牢骚,你可以运行git update-index --assume-unchanged或git update-index --skip-worktree. 这告诉 Git 在文件的索引条目上设置一个标志位:是的,这个文件可以被修改。但如果是,请假装不是。 然后git status不会一直说你不想提交这个文件吗?不是吗?嗯?嗯?
但现在这个谎言是个问题。
无论git checkout和git merge使用,因此写上索引和工作树。我会在git checkout这里描述,因为它更简单,但问题是一样的。在许多情况下,许多文件,移动时从一个提交到另一个,Git不会有对指数和工作树写。但是,在几乎所有情况下,对于某些文件,它确实必须写入索引和工作树。
例如,假设您正在进行哈希 ID 为 的提交badbeef。在那个特定的提交中,有一个index.html. 现在你告诉 Git 检查一个不同的提交,它的哈希 ID 是cafedad. 在那个特定的承诺,有同样的版本js/app.js。但是:这些是相同的版本,还是不同的版本js/app.js?
如果它们相同,Git 可以从badbeef到移动,根本cafedad不接触js/app.js。但如果不是,混帐必须去掉一个最在索引和工作树,并用替换它们js/app.js从其他承诺。
如果 的索引和工作树版本js/app.js与 的HEAD提交版本匹配js/app.js,则覆盖文件没什么大不了的。它在另一个提交中:如果你想要旧版本,你可以从另一个提交中得到它。 但是,如果它们不匹配,则将它们写在上面是一件大事。这可能会破坏宝贵的文件内容。
什么Git是告诉你的是,承诺要合并也有那些相同的三个文件,而且它有一个不同的版本,这些文件的比你在你的索引和工作树。如果您要强制 Git 进行合并,这会将您的这些文件的版本替换为这些文件的其他提交版本。因此,您必须:
Run Code Online (Sandbox Code Playgroud)Please commit your changes or stash them before you merge.
但git status什么也没说,因为你告诉它撒谎。
你必须告诉 Git 不要再骗你了。如果你设置了--assume-unchanged,用 清除它--no-assume-unchanged。如果你设置了--skip-worktree,用 清除它--no-skip-worktree。现在git status将向您展示现实。
当然,首先设置这些是有原因的。所以现在你必须解决这个问题。解决这个问题,提交或隐藏你的文件,然后合并,你就完成了。