git 重置导致工作目录和阶段发生变化

git reset resulting in changes to both working directory and stage

我有一个包含很多文件的提交。

提交中的一个文件有几个更改,我想撤消其中一个。

所以,我想我可以将该特定文件重置回 HEAD~,留下我在工作目录中所做的未完成的更改。然后,我可以使用 git add -p 并只进行所需的更改,然后是 git commit --amend.

首先,我确保我的工作目录或阶段没有明显的变化。

然后,我运行这个命令:

git reset HEAD~ -- path/to/file

但是,令我惊讶的是,git status 现在显示了我的工作目录和阶段的更改。使用 gitk 进一步检查表明我的工作目录和阶段中的更改是相同的。

我哪里错了?

这种重置:

  • 影响HEAD本身或当前分支(因此它与[=13的any不同=], git reset --mixed, 或 git reset --soft);
  • 是否影响索引的内容;
  • 影响工作树的内容。

因此:

So, I was thinking I could reset that particular file back to HEAD~ leaving the outstanding changes I had made in the working-directory. Then, I could use git add -p and only stage the desired changes, followed by git commit --amend.

...真是个好计划!但是正如您所见,git status 的输出变得有点令人惊讶:

git status now shows changes to both my working-directory and stage.

原因是git status所做的包括运行宁两个git diff。如果您可以将索引和工作树命名为 git diff 的参数(您不能),那可能是:

  • git diff --name-status HEAD <index>: 这是"changes to be committed".
  • git diff --name-status <index> <work-tree>: 这是"changes not staged for commit".

由于 path/to/fileindex 版本现在匹配 path/to/fileHEAD~1 版本,这与 HEAD版本,第一个git diff表示存在"staged changes"。

同样,工作树版本与索引版本不匹配,因此git status表示还存在未暂存的更改。

事实上你现在可以 运行 git add -p。 Git 将索引版本提取到一个临时文件,将索引版本与工作树版本进行比较,并让您向索引版本添加更改(从工作树版本)。

你可以走另一条路

如果您希望能够看到您在做什么,不过,最好在开始时做一个git reset --soft HEAD~1。这种复位:

  • 是否影响当前分支,使用HEAD找出那个分支是什么并调整它;
  • 影响索引的内容;和
  • 影响工作树的内容。

您现在的处境与以前类似,但现在您需要:

git reset HEAD path/to/file

使索引版本与 HEAD 版本匹配,现在 HEAD 命名了所需的提交。您不想要的提交(您打算 --amend)现在是分支提示的 "one past the end":

             X  [bad commit, now shoved out of the way]
            /
...--o--o--@   <-- branch

现在 git status 有意义,因为它将 @ 与索引进行比较而不是 X 与索引进行比较。 (和以前一样,git status 也将索引与工作树进行比较。)现在您可以按预期 git add -p,然后 git commit 没有 --amend 部分。

你不必这样做;你可以继续你目前的计划。不过,如果您更喜欢此处的 git status 结果,则可以通过 git reset --soft HEAD~1 立即将当前计划转换为其他计划。这将更改当前分支名称,使其停止指向 X 并开始指向 @,并且什么都不改变。