Git 不会在签出之前的快照时删除新文件
Git doesn't remove new files on checkout of prior snapshot
我在快照 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
仍然存在而不是被删除。
我是不是做错了什么?如何让这些以前添加的文件消失?
How do I get these previously added files to go away?
您总能找到所需文件的 SHA-1,检查它,添加并再次提交所需内容。
# Checkout the given file from a given SHA-1
git checkout SHA-1 -- full_path_fo_file
另一个更简单的选项是查看旧文件的内容(如果你使用 IDE 你通常会有文件的本地历史记录,或者使用 git log --follow
并且一旦你有内容和以前一样添加并提交它。
如何做你想做的事
问题总结:当你使用git checkout <em>commit-hash</em> <em>path</em>
(在本例中为 git checkout a0c53b9 u-boot/
),git 提取该路径——在本例中为一个充满文件的目录——但不 git rm
任何 的文件not 在该特定提交中 当前在该目录中 。这意味着如果您现在要进行新的提交,它将具有较旧的 u-boot
代码,但会将新文件与旧代码混合在一起。
简单的解决方案是,首先,确保您不需要任何这些文件——没有未提交的工作要保存——然后只需要 git rm -rf u-boot/
(不是常规的 rm
)整个目录。这将清除工作树并安排删除所有文件,但在您实际提交任何内容之前,now 您 运行 git checkout a0c53b9 u-boot/
,这将重新填充提交 a0c53b9
中 u-boot/
文件的索引和工作树。删除的没有旧版本的文件保持删除状态,删除的有旧版本的文件从旧版本恢复。
背景,或 TL;DR 部分:为什么 git 会这样
git checkout
命令真的有好几个(多少取决于你怎么算)不同的命令:
git checkout <em>name</em>
(其中 name
名称一个有效的现有分支)从当前提交切换到新提交,将您置于给定分支 name
。即使根据 gitrevisions
,name
应该解析为提交 ID 而不是分支名称(尽管这种情况很少见,不应该发生)。如果某些工作树文件被破坏(但 -f
无论如何都会强制切换),此操作可能会失败。
git checkout <em>hash</em>
从当前提交切换到新提交,让您离开任何分支(进入 "detached HEAD"模式)。在其他方面与给出分支名称相同。 hash
可以是解析为提交 ID 的任何内容,包括标签或远程跟踪分支名称;它不能是现有的分支名称,因为它属于第一种情况。
git checkout -b <em>name</em>
使用给定的 [=20= 创建一个新分支](附加参数会影响分支的创建方式)。它通常不会失败,因为您通常会在当前提交时创建一个新分支,这意味着只有 HEAD
间接需要更改:工作树中未提交的工作仍然未提交。
git checkout -- <em>path</em>
从索引中提取一些文件到工作树中,破坏任何未提交的工作。请注意,如果您之前 git add
编辑了 path
,然后又修改了文件,这将恢复您 git add
编辑的版本,而不是HEAD
提交中的版本。
git结帐<em><code>hash
--path
从给定的 hash
中提取一些文件到工作树中,将它们 写入 索引(即,索引条目也会更新)。它在其他方面与之前的(从索引中检出)方法相同:在这两种情况下,工作树在命令完成时与索引匹配。 hash
参数可以是 git 可以解析为树的任何内容:这包括分支、标记和远程跟踪分支名称。 Git 不更改当前提交,仅更改索引和工作树。
请注意,前三个列出的形式小心地 避免 破坏工作树中的工作,而后两个故意破坏工作。 (我个人认为至少这两种模式应该是不同的命令。也就是说,如果 git <something-like-checkout>
总是安全的并且 git <something-like-clobbber>
是 "unsafe" 命令就好了。那么更容易记住何时要小心。)
当您这样做时:
git checkout a0c53b9 u-boot/
您使用的是 git checkout
的最后一种形式,即 git checkout <em>hash</em> -- <em>path </em>
。 (这里的双破折号实际上并不是必需的。它把散列和路径分开,并且 是 是必需的——至少在使用第四种形式时可能是这样。假设你想查看一个 leet -说出索引中名为 f33dc47
的文件。但是文件名 f33dca7
—1337 中的 "feed cat"—也是一个有效的哈希前缀。双破折号是您告诉 [=165 的方式=] 您正在执行第四种结帐而不是第二种结帐。)
当您使用 git checkout
的最后两种形式之一时,git 不会 改变 您的 当前 提交,它只是 提取一些文件 。在这种情况下,git 将 不会 删除文件。您提取的文件是 "everything in u-boot/
",如您所见,git 确实更新了这些文件,只是没有删除 u-boot/
中的任何其他文件。这是 git checkout
.
的正确行为
在您的情况下,您想要进行具有 "new everything else, but an old u-boot/
, including not having the new u-boot/
files that came along for the ride when we got everything" 的新提交。那么,如何清理目录,以避免有多余的文件呢?答案在于注意到 git checkout <em>hash</em> -- <em>path</em>
通过索引写入进入工作树;因此,如果您首先清空该目录中所有文件的工作树和索引,然后从旧提交中重新填充两者,您将得到您想要的。
我在快照 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
仍然存在而不是被删除。
我是不是做错了什么?如何让这些以前添加的文件消失?
How do I get these previously added files to go away?
您总能找到所需文件的 SHA-1,检查它,添加并再次提交所需内容。
# Checkout the given file from a given SHA-1
git checkout SHA-1 -- full_path_fo_file
另一个更简单的选项是查看旧文件的内容(如果你使用 IDE 你通常会有文件的本地历史记录,或者使用 git log --follow
并且一旦你有内容和以前一样添加并提交它。
如何做你想做的事
问题总结:当你使用git checkout <em>commit-hash</em> <em>path</em>
(在本例中为 git checkout a0c53b9 u-boot/
),git 提取该路径——在本例中为一个充满文件的目录——但不 git rm
任何 的文件not 在该特定提交中 当前在该目录中 。这意味着如果您现在要进行新的提交,它将具有较旧的 u-boot
代码,但会将新文件与旧代码混合在一起。
简单的解决方案是,首先,确保您不需要任何这些文件——没有未提交的工作要保存——然后只需要 git rm -rf u-boot/
(不是常规的 rm
)整个目录。这将清除工作树并安排删除所有文件,但在您实际提交任何内容之前,now 您 运行 git checkout a0c53b9 u-boot/
,这将重新填充提交 a0c53b9
中 u-boot/
文件的索引和工作树。删除的没有旧版本的文件保持删除状态,删除的有旧版本的文件从旧版本恢复。
背景,或 TL;DR 部分:为什么 git 会这样
git checkout
命令真的有好几个(多少取决于你怎么算)不同的命令:
git checkout <em>name</em>
(其中name
名称一个有效的现有分支)从当前提交切换到新提交,将您置于给定分支name
。即使根据gitrevisions
,name
应该解析为提交 ID 而不是分支名称(尽管这种情况很少见,不应该发生)。如果某些工作树文件被破坏(但-f
无论如何都会强制切换),此操作可能会失败。git checkout <em>hash</em>
从当前提交切换到新提交,让您离开任何分支(进入 "detached HEAD"模式)。在其他方面与给出分支名称相同。hash
可以是解析为提交 ID 的任何内容,包括标签或远程跟踪分支名称;它不能是现有的分支名称,因为它属于第一种情况。git checkout -b <em>name</em>
使用给定的 [=20= 创建一个新分支](附加参数会影响分支的创建方式)。它通常不会失败,因为您通常会在当前提交时创建一个新分支,这意味着只有HEAD
间接需要更改:工作树中未提交的工作仍然未提交。git checkout -- <em>path</em>
从索引中提取一些文件到工作树中,破坏任何未提交的工作。请注意,如果您之前git add
编辑了path
,然后又修改了文件,这将恢复您git add
编辑的版本,而不是HEAD
提交中的版本。git结帐<em><code>hash
--path
从给定的hash
中提取一些文件到工作树中,将它们 写入 索引(即,索引条目也会更新)。它在其他方面与之前的(从索引中检出)方法相同:在这两种情况下,工作树在命令完成时与索引匹配。hash
参数可以是 git 可以解析为树的任何内容:这包括分支、标记和远程跟踪分支名称。 Git 不更改当前提交,仅更改索引和工作树。
请注意,前三个列出的形式小心地 避免 破坏工作树中的工作,而后两个故意破坏工作。 (我个人认为至少这两种模式应该是不同的命令。也就是说,如果 git <something-like-checkout>
总是安全的并且 git <something-like-clobbber>
是 "unsafe" 命令就好了。那么更容易记住何时要小心。)
当您这样做时:
git checkout a0c53b9 u-boot/
您使用的是 git checkout
的最后一种形式,即 git checkout <em>hash</em> -- <em>path </em>
。 (这里的双破折号实际上并不是必需的。它把散列和路径分开,并且 是 是必需的——至少在使用第四种形式时可能是这样。假设你想查看一个 leet -说出索引中名为 f33dc47
的文件。但是文件名 f33dca7
—1337 中的 "feed cat"—也是一个有效的哈希前缀。双破折号是您告诉 [=165 的方式=] 您正在执行第四种结帐而不是第二种结帐。)
当您使用 git checkout
的最后两种形式之一时,git 不会 改变 您的 当前 提交,它只是 提取一些文件 。在这种情况下,git 将 不会 删除文件。您提取的文件是 "everything in u-boot/
",如您所见,git 确实更新了这些文件,只是没有删除 u-boot/
中的任何其他文件。这是 git checkout
.
在您的情况下,您想要进行具有 "new everything else, but an old u-boot/
, including not having the new u-boot/
files that came along for the ride when we got everything" 的新提交。那么,如何清理目录,以避免有多余的文件呢?答案在于注意到 git checkout <em>hash</em> -- <em>path</em>
通过索引写入进入工作树;因此,如果您首先清空该目录中所有文件的工作树和索引,然后从旧提交中重新填充两者,您将得到您想要的。