【问题标题】:git reset --hard HEAD vs git checkout <file>git reset --hard HEAD vs git checkout <file>
【发布时间】:2017-10-17 23:50:02
【问题描述】:

我有一个文件foo.py。我对工作目录进行了一些更改,但没有 暂存 或提交任何更改。我知道我可以使用git checkout foo.py 来摆脱这些更改。我还阅读了有关使用 git reset --hard HEAD 的信息,它实质上会重置您的工作目录、暂存区和提交历史记录以匹配最新提交。

在我的情况下,有什么理由更喜欢使用其中一个而不是另一个,我的更改仍在工作目录中?

【问题讨论】:

    标签: python git


    【解决方案1】:

    在我的情况下,我的更改仍在工作目录中,是否有任何理由更喜欢使用其中一个而不是另一个?

    不,因为他们会完成同样的事情。

    在[一般情况下,但不是在我的特定情况下],是否有任何理由更喜欢使用 [git checkout -- path/to/file] 而不是 [git reset --hard]?

    是的:这只会影响一个文件。如果您的习惯是 git reset --hard 撤消对一个文件的更改,并且您对 other 文件也有工作树和/或阶段性更改,而您 git reset --hard,您可能会运气不佳这些更改无需手动重建即可恢复。

    请注意,还有第三个构造:git checkout HEAD path/to/file。这个和没有HEAD(用--代替1)的区别在于,一个 HEAD的意思是复制永久、不可更改的提交文件首先进入索引/暂存区域,然后进入工作树-- 表示将索引/暂存区中的文件版本复制到工作树中。


    1使用-- 的原因是为了确保 Git 不会将文件名与其他任何内容(例如分支名称)混淆。例如,假设您将文件命名为master,只是为了固执。那么,git checkout master 是什么意思?它应该检查分支master,还是提取文件mastergit checkout -- master 中的 -- 让 Git 和人类清楚地知道这意味着“提取文件 master”。


    总结或注意事项

    每个文件始终存在三个活动副本:

    • HEAD 中的一个;
    • 索引/暂存区中的一个;
    • 工作树中的一个。

    git status 命令查看所有三个,首先比较 HEAD-vs-index — 这为 Git 提供了“要提交的更改”列表 — 然后是 index-vs-work-tree 第二个。第二个为 Git 提供“未暂存以进行提交的更改”列表。

    git add 命令从工作树复制到索引中。

    git checkout 命令从HEAD 复制到索引然后复制到工作树,或者只是从索引复制到工作树。所以有点复杂,有多种操作模式:

    • git checkout -- <em>path/to/file</em>:从索引复制到工作树。 HEAD 中的内容在这里无关紧要。 -- 通常是可选的,除非文件名看起来像一个分支名称(例如,一个名为 master 的文件)或一个选项(例如,一个名为 -f 的文件)。

    • git checkout HEAD -- <em>path/to/file</em>:从HEAD 提交复制到索引,然后到工作树。 HEAD 中的内容覆盖索引中的内容,然后覆盖工作树中的内容。 -- 通常是可选的,除非文件名看起来像一个选项(例如,-f)。

      始终使用-- 是一个好习惯。

    git reset 命令很复杂(它有多种操作模式)。

    (这并不是说git checkout很简单:它也有很多操作模式,可能太多了。但我认为git reset至少差一点。)

    【讨论】:

    • 不是在抱怨,但事后看来,我的回答读起来就像是你的 tl;dr... 没有帮助,我之前发布了它;-)
    • @NichtJens:我发布我的时没有看到你的 :-)(可能的原因/借口:我的浏览器表现不佳,需要重新启动)
    • 这个答案可以改写以澄清git checkout HEAD path/to/filegit checkout path/to/file 不同。使用 HEAD,它从分支中签出,没有 HEAD,它从索引中“签出”。我很困惑,因为三件事发生了变化: -- 被删除,“/”被插入到路径中,并且 HEAD 被添加。在我意识到我错过了什么之前,我不得不搜索其他网站。
    • @johk95:索引包含 (mode,name,hash) 元组,因此“复制到索引”只是意味着在索引中找到正确的插槽并更新 3 元组的哈希部分。说明此步骤的原因是索引 always 包含将进入下一次提交的 every 文件。在冲突合并解决期间,索引将包含每个文件最多 3 个条目,并且复制到索引会擦除所有非零阶段条目,将它们替换为单个阶段零条目,这将冲突标记为已解决。 git checkout &lt;commit&gt; -- &lt;path&gt; 操作执行此操作。有一个新命令[继续]
    • @johk95:可能还值得注意的是,git add 也将通过相同的过程解决冲突:它写入索引。在工作树和最后提交版本都匹配的情况下,“写入索引”just 将三个非零阶段条目折叠为一个阶段零条目,或者只写入原始条目哈希 ID 返回(保持索引条目不变,如果没有更改其他索引条目,则意味着 Git 甚至不必费心将索引数据写回)。
    【解决方案2】:

    也许这会有所帮助:

    来源: https://www.patrickzahnd.ch

    【讨论】:

      【解决方案3】:

      在您的限制下,没有区别。但是,如果有分阶段的更改,则有:

      reset 恢复分阶段的更改。

      checkout 不...

      【讨论】:

        猜你喜欢
        • 2020-04-07
        • 2018-01-13
        • 2017-12-10
        • 2011-09-06
        • 2011-07-04
        • 2016-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多