git checkout不会删除应该删除的文件

git checkout is not removing files that it should

使用公共回购,我想让我的主分支从过去恢复到某种承诺。我已经检查了选项,对我来说最好的是简单地签出所需的提交,然后提交到主分支。但是,当我执行签出时,它不会删除在指定的提交哈希之后添加到master中的一些文件。

因此,例如,如果我想重新提交aaa1

1
2
3
4
5
6
$ cd working-copy-top-dir
$ git checkout master
$ git checkout -- .
$ git clean -fd
$ git checkout aaa1 .
$ git clean -fd

但此时,在aaa1之后添加的一些文件仍在工作副本中。什么是checkout命令,以使工作副本数据返回到aaa1的状态?

1
2
$ git --version
git version 2.7.2.windows.1


tl;dr:首先移除所有内容

当您使用git checkout aaa1 .时,您告诉Git将aaa1转换为commit,找到commit(更准确地说,它的树),然后将commit中的每个文件复制到索引/分段区域和工作树中。

我们假设,为了论证,您从包含两个文件的master开始,READMEhello

1
2
3
4
5
6
7
8
9
$ git checkout master
[output snipped]
$ ls
README   hello
$ cat README
Yay, you read me!
$ cat hello
world
$

更进一步说,commit aaa1存在,其中有两个文件:READMEaddendum。它的READMEThank you for reading.让我们结账:

1
2
3
4
$ git checkout aaa1 -- .
[output snipped]
$ ls
README    addendum  hello

(我加上了--:这里实际上并不需要,但这是很好的做法。)README的内容是更新后的README。文件addendum也已被提取。文件hello未被删除,与master中的版本保持不变。更新后的READMEhello分阶段进行:

1
2
3
$ git status --short
M  README
A  addendum

hello没有删除:

1
2
3
4
$ git ls-files --stage
100644 ac6f2cf1acbe1b6f11c7be2288fbae72b982823c 0   README
100644 7ddf1d71e0209a8512fe4862b4689d6ff542bf99 0   addendum
100644 cc628ccd10742baea8241c5924df992b5c019f71 0   hello

使用git clean,即使使用-x,也不会产生任何效果:无需清理;没有未保存的文件(hello是分阶段的,只是没有修改)。

您特别想让工作树匹配commit aaa1,逐字节。为此,您必须找到索引中的文件,但不在aaa1中,然后删除它们。

不过,还有一种更简单的方法:把所有东西都拿走。然后,用你的git checkout aaa1 -- .aaa1中提取所有东西。这将填写aaa1中的索引和工作树:需要恢复到删除前的状态的任何文件都将恢复(恢复到aaa1中的状态,与HEAD中的状态相同)。任何需要更改以匹配它们在aaa1中的方式的文件都将被恢复(恢复到它们在aaa1中的方式,这是不同的)。

1
2
3
4
5
6
7
8
9
10
11
12
$ git rm -rf .
rm 'README'
rm 'addendum'
rm 'hello'
$ git checkout aaa1 -- .
$ git ls-files --stage
100644 ac6f2cf1acbe1b6f11c7be2288fbae72b982823c 0   README
100644 7ddf1d71e0209a8512fe4862b4689d6ff542bf99 0   addendum
$ git status --short
M  README
A  addendum
D  hello

您现在可以提交,并且您将对master有一个新的提交,不管以前有什么,它与aaa1有完全相同的树。

(这是否是一个好主意完全是另一回事,但它会让你达到理想的状态。)


你想把回购回那个状态吗?或者你只是想让你的本地回购看起来像那样?

请参阅https://git-scm.com/docs/git-reset了解git reset。

案例1:如果你愿意的话

1
git reset --hard [commit hash]

它将使您的本地代码和本地历史就像提交时一样。但是如果你想把这个推给其他有着新历史的人,它就会失败。

案例2:如果你这样做的话

1
git reset --soft [commit hash]

它将使您的本地文件更改为原来的样子,但将您的历史记录等保持不变。

我在这里找到了答案。你也可以在这里看到相关的答案。


git stash可能是清理工作树的最快方法。然后,git checkout-b$newbranch$commit-sha1-you-want创建一个你要使用的分支。完成所有工作后,git stash会弹出来恢复工作树。


Git签出将不会删除自上次提交以来添加的文件。要做到这一点,我需要git revert

不过,我发现git checkout thehash .更容易使用,而且不难看出自散列之后添加了哪些文件:

1
git diff --name-status HEAD thehash