foo.py
的文件。我对工作目录进行了一些更改,但是还没有将这些更改添加到暂存区或提交更改。我知道可以使用git checkout foo.py
来取消这些更改。我还了解到可以使用git reset --hard HEAD
来重置您的工作目录、暂存区和提交历史记录以匹配最新提交。在我的情况下,我的更改仍然在工作目录中,是否有理由更喜欢使用其中之一呢?
在我的情况下,我对工作目录中的更改还没有提交,是否有理由更喜欢使用其中一种方法?
没有,因为它们都可以完成同样的任务。
总的来说(但不是在我的特定情况下),是否有理由更喜欢使用 [
git checkout -- path/to/file
] 而不是 [git reset --hard
]?
是的:这只会影响一个文件。如果你习惯于使用 git reset --hard
撤消对一个文件的更改,并且你还有工作树和/或暂存的其他文件的更改,那么如果你运行 git reset --hard
,你可能无法恢复这些更改,除非手动重建它们。
注意,还有第三种命令:git checkout HEAD path/to/file
。与不带 HEAD
的命令相比(用 --
代替1),两者的区别在于带有 HEAD
的命令意味着首先将永久不可更改的提交中的文件版本复制到索引/暂存区,然后再复制到工作树。而带有 --
的命令意味着将索引/暂存区中的文件版本复制到工作树。
1使用 --
的原因是确保 Git 永远不会将文件名与其他任何内容混淆,例如分支名称。例如,假设你将一个文件命名为 master
,那么 git checkout master
是什么意思?它应该检出分支 master
还是提取文件 master
?git checkout -- master
中的 --
使其对 Git 和人类都清晰明了,表示“提取文件 master
”。
每个文件始终有三个活动副本:
HEAD
中的一个;git status
命令查看这三个副本,首先比较 HEAD
vs. 索引,这给 Git 提供了“要提交的更改列表”,然后比较索引 vs. 工作树。第二个比较给 Git 提供了“未暂存的更改列表”。
git add
命令将文件从工作树复制到索引中。
git checkout
命令有多种操作模式,可以从 HEAD
复制到索引再到工作目录,也可以直接从索引复制到工作目录。因此,它有一定的复杂性:
git checkout -- path/to/file
:将文件从索引复制到工作目录,不考虑 HEAD
中的内容。如果文件名看起来像分支名称(例如一个名为 master
的文件)或选项(例如一个名为 -f
的文件),则 --
通常是可选的。
git checkout HEAD -- path/to/file
:将文件从 HEAD
提交中复制到索引,然后再复制到工作目录。这里的 HEAD
覆盖了索引中的内容,索引又覆盖了工作目录中的内容。除非文件名看起来像选项(例如 -f
),否则 --
通常是可选的。
最好总是使用 --
,养成好习惯。
git reset
命令也很复杂(它有许多操作模式)。git checkout
很简单:它也有许多操作模式,可能太多了。但我认为 git reset
至少稍微复杂一些。)在您的限制下,没有区别。但如果有分阶段的更改,则会有区别:
reset
会还原已分阶段的更改。
checkout
则不会……
HEAD
提交复制到索引,然后到工作树。我可以将“复制到索引”想象为在将文件重置为最后一次提交的版本后将其添加到暂存区(==索引)吗?由于如果工作树版本等于最后提交的版本,则git add
不会执行任何操作,所以为什么要强调这一步骤的重要性? - johk95git checkout <commit> --<path>
操作会执行此操作。有一个新的命令[cont]。 - torekgit restore
,可以将文件从提交或索引复制到您的工作树,并且在从提交复制时可以绕过这种写入索引模式。如果您希望避免“解决正在进行的冲突”的副作用,则可以使用此功能。 - torekgit add
也可以通过相同的过程解决冲突:它会写入索引。当工作树和最后提交版本都匹配时,“写入索引”操作只会将三个非零阶段条目合并为一个零阶段条目,或者仅将原始哈希 ID 写回(这将保持索引条目不变,并且如果没有更改其他索引条目,则意味着 Git 甚至不必费心写回索引数据)。 - torek