Git在结帐之前不会删除新文件

时间:2016-03-29 21:29:51

标签: git git-checkout

我开始使用快照a0c53b9的特定存储库。我更改了一些文件,并在目录kernel/u-boot/中添加了其他文件,并提交了快照9c06fb7

事实证明我不会对u-boot/使用我的更改,但仍希望能够引用它们。我因此做了以下事情:

git checkout a0c53b9 u-boot/
git commit -m "profound and eclectic description of change"

奇怪的是,我发现在结帐时将已修改的文件从9c06fb7恢复为a0c53b9,但它没有删除a0c53b9中添加的文件。这些不是未跟踪的文件,因此许多其他答案中的git clean -fd建议并不适用。

假设已修改预先存在的文件u-boot/common/usb.c,并添加了新文件u-boot/board/xilinx/zynq/crypto/sha.h。在git checkout a0c53b9 u-boot/之后,文件u-boot/common/usb.c已恢复为a0c53b9状态,但文件u-boot/board/xilinx/zynq/crypto/sha.h仍然存在,而不是已被删除。

我做错了吗?如何让这些以前添加的文件消失?

2 个答案:

答案 0 :(得分:2)

如何做你想做的事

问题摘要:当你使用git checkout commit-hash path(在这种情况下是git checkout a0c53b9 u-boot/)时,git会提取该路径 - 在这种情况下,一个充满文件的目录 - 但不是git rm 当前在该目录中 的特定提交中的任何文件。这意味着,如果您现在要进行新的提交,它将使用较旧的u-boot代码,但会将新文件与旧代码混合在一起。

简单的解决方案是,首先,确保您不需要任何这些文件 - 没有未提交的工作要保存 - 然后只是git rm -rf u-boot/(不是常规的rm)整个目录。这将清除工作树并安排所有要删除的文件,但在实际提交任何内容之前,现在运行git checkout a0c53b9 u-boot/,这将重新填充索引和工作树提交u-boot/中的a0c53b9个文件。删除没有旧版本的已删除文件,并从旧版本还原已删除的旧版本文件。

背景,或TL; DR部分:为什么git以这种方式行事

git checkout命令实际上是几个(多少取决于你如何计算)不同的命令:

  • git checkout name(其中 name 命名一个有效的现有分支)从当前提交切换到新提交,将您置于给定分支 {{ 1}} 的。即使每gitrevisions name 应该解析为提交ID而不是分支名称(尽管这种情况非常罕见且不应该发生),这也是如此。如果某些工作树文件被破坏,此操作可能会失败(但name将强制切换)。
  • -f从当前提交切换到新提交,将您带到任何分支(进入“分离的HEAD”模式)。它与提供分支名称相同。 git checkout hash 可以是解析为提交ID的任何内容,包括标记或远程跟踪分支名称;它只是不能成为现有的分支名称,因为它属于第一种情况。
  • hash使用给定的 git checkout -b name 创建一个新分支(其他参数可能会影响分支的创建方式)。它通常不会失败,因为您通常会在当前提交时创建一个新分支,这意味着只需要更改name间接:工作树中未提交的工作仍然未提交。
  • HEAD从索引中将一些文件提取到工作树中,破坏任何未提交的工作。请注意,如果您之前git checkout -- path - 编辑了 git add ,然后再修改了该文件,则会恢复您path编辑的版本,而不是版本git add提交。
  • HEAD从给定的 git checkout hash -- path 中提取一些文件到工作树中,将它们写成通过索引(即,索引条目也已更新)。它与前一个(从索引中检出)方法相同:在两种情况下,工作树在命令完成时匹配索引。 hash 参数可以是git可以解析为树的任何内容:这包括分支,标记和远程跟踪分支名称。 Git不会更改当前提交,只会更改索引和工作树。

请注意,前三个列出的表单在工作树中小心地避免 clobbering工作,而最后两个故意破坏工作。 (我个人认为至少这两种模式应该是不同的命令。也就是说,如果path始终是安全的并且hash是“不安全”的命令,那就更好了。记得什么时候要小心。)

当你这样做时:

hash

您使用的是git <something-like-checkout>的最后一种形式,即git <something-like-clobbber>。 (这里的双破折号实际上并不是必需的。它将散列与路径分开,并且是必需的 - 至少可能 - 在使用第四种形式时。假设你要查看一个leet-speak文件从索引中命名为git checkout a0c53b9 u-boot/ 。但文件名git checkout - 1337中的“feed cat”也是一个有效的哈希前缀。双击是你告诉git你做第四个的方式-form checkout而不是二次结账。)

当您使用最后两种git checkout hash -- path形式中的任何一种时,git不会更改 当前提交,它只是提取某些文件(多个)。在这种情况下,git将删除文件。您提取的文件是“f33dc47中的所有内容”,如您所见,git确实更新了这些文件,它只是没有删除f33dca7中的任何其他文件。这是git checkout的正确行为。

在您的情况下,您希望进行一项新提交,其中包含“新的所有内容,但旧的u-boot/,包括而非,其中包含新的u-boot/个文件当我们得到一切时,我们一起去旅行。那么,如何清理目录,以避免有额外的文件?答案在于注意git checkout通过索引写入工作树;因此,如果您首先清空工作树和该目录中所有文件的索引,然后从旧提交中重新填充,您将得到您想要的。

答案 1 :(得分:0)

  

如何让这些以前添加的文件消失?

您始终可以找到所需文件的SHA-1,检查出来,添加&amp;用期望的内容再次提交。

# Checkout the given file from a given SHA-1
git checkout SHA-1 -- full_path_fo_file

另一个更简单的选择是查看旧文件的内容(如果您使用IDE,您通常会拥有该文件的本地历史记录,或者使用git log --follow,并且如果您拥有以前添加和提交的内容它