【问题标题】:What is difference between 'git reset --hard HEAD~1' and 'git reset --soft HEAD~1'?'git reset --hard HEAD~1' 和 'git reset --soft HEAD~1' 有什么区别?
【发布时间】:2014-08-25 11:26:21
【问题描述】:

我试图撤消我在 git 中的提交。使用git reset --hard HEAD~1有危险吗?

git reset 的不同选项有什么区别?

【问题讨论】:

标签: git undo git-reset


【解决方案1】:

Git 重置有 5 种主要模式:soft、mixed、merged、hard、keep。 它们之间的区别在于改变或不改变head、stage(index)、工作目录

Git reset --hard 将改变头部、索引和工作目录。
Git reset --soft 只会改变头部。索引、工作目录没有变化。

所以换句话说,如果你想撤销你的提交,--soft 应该足够好了。但在那之后,您的索引和工作目录中仍然存在错误提交的更改。您可以修改文件、修复它们、将它们添加到索引并再次提交。

使用 --hard,您可以在项目中彻底搞定。就好像上次提交没有任何变化一样。如果您确定这是您想要的,请继续前进。但是一旦你这样做了,你将完全失去你的最后一次提交。 (注意:仍有办法恢复丢失的提交)。

【讨论】:

    【解决方案2】:

    git reset 知道五种“模式”:软、混合、硬、合并和保持。我将从前三个开始,因为这些是您通常会遇到的模式。之后你会发现一个不错的小红包,敬请期待。


    假设您有一个类似历史的存储库:

    7e05a95  (HEAD -> main) Update a
    e62add5  Update b
    ca9ae0a  Update a
    9b6060d  Add c
    eebe372  Add b
    947586a  Add a
    

    最新的提交 (7e05a95) 包含这些更改:

    diff --git a/a b/a
    index b66ba06..28b68e2 100644
    --- a/a
    +++ b/a
    @@ -1 +1 @@
    -new content
    +new new content
    

    现在,当您以各种不同的模式运行 git reset 时会发生什么?一起来了解一下吧!

    使用git reset --soft HEAD~1 时,您将从当前分支中删除最后一次提交,但文件更改将保留在您的working tree 中。此外,更改将保留在您的索引上,因此使用 git commit 将创建一个提交,其更改与您之前“删除”的提交完全相同。

    这在实践中会是什么样子?像这样:

    > git reset --soft HEAD^ # Assuming HEAD points at 7e05a95
    > git status
    On branch main
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
        modified:   a
    

    如您所见,文件 a 中的更改已在索引中,并准备再次提交。

    混合

    这是默认模式,与软模式非常相似。当使用git reset HEAD~1“删除”一个提交时,你仍然会将更改保留在工作树中,但不会保留在索引中;因此,如果您想“重做”提交,则必须在提交之前添加更改 (git add)。

    实际上,结果可能如下所示:

    > git reset --mixed HEAD^ # Assuming HEAD points at 7e05a95
    > git status
    On branch main
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
        modified:   a
    
    no changes added to commit (use "git add" and/or "git commit -a")
    

    文件a的更改仍然存在,但它们不在索引上。

    使用git reset --hard HEAD~1 时,除了上次提交中引入的更改之外,您将丢失所有未提交的更改和所有未跟踪的文件。这些更改不会保留在您的工作树中,因此执行git status 命令会告诉您您的存储库中没有任何更改。

    小心使用这个。如果您不小心删除了 git 从未跟踪过的未提交更改(说明:已提交或至少添加到索引中),您将无法使用 git 恢复它们。

    一个实际的例子可能如下所示:

    > git reset --hard HEAD^ # Assuming HEAD points at 7e05a95
    > git status
    On branch main
    nothing to commit, working tree clean
    

    如您所见,没有任何变化。假设您在文件 b 中也有一些未提交的更改,这些也会丢失!

    > echo 'some uncommitted changes' > b
    > git status
    On branch main
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
        modified:   b
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    > git reset --hard HEAD^ # Assuming HEAD points at 7e05a95
    > git status
    On branch main
    nothing to commit, working tree clean
    

    奖金

    保持

    git reset --keep HEAD~1 是一个有趣且有用的。它只重置 current HEAD 和给定提交之间不同的文件。如果其中一个或多个文件有未提交的更改,它将中止重置。它基本上充当hard 的更安全版本。

    让我们重温之前的示例,您在 b 中有一些未提交的更改:

    > echo 'some uncommitted changes' > b
    > git status
    On branch main
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
        modified:   b
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    > git reset --keep HEAD^ # Assuming HEAD points at 7e05a95
    > git status
    On branch main
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
        modified:   b
    
    no changes added to commit (use "git add" and/or "git commit -a")
    

    您删除了文件 a 中的更改,但保留了文件 b 中未提交的更改!

    重申一下:“hard”将删除所有更改,而“keep”仅删除重置提交中的更改。


    git reset documentation 中深入解释了这些模式。

    注意
    在执行git reset 删除提交时,提交并没有真正丢失,只是没有指向它或其任何子项的引用。您仍然可以通过查找它的 SHA-1 密钥来恢复使用 git reset“删除”的提交,例如使用诸如 git reflog 之类的命令。

    【讨论】:

    • 我不同意这三个是我们通常应该使用的。它们是最先出现的 3 个,所以人们再谈这 3 个,但 --hard 几乎从来都不是正确的做法,因为 --keep 更安全,适用于 --hard 工作的大多数场景。训练你的手指使用--keep 可能会在某一天拯救你……
    • 我并没有试图建议我们应该使用它们,只是这些命令是人们大多数时候都会遇到的。随意编辑您认为合适的答案。
    • 添加更多细节,在 git reset --soft HEAD~1 之后,使用 git commit --reuse-message=HEAD@{1} 将最后一次提交与保留的旧索引重用为此处显示stackoverflow.com/a/25930432/2883282
    • @MatthieuMoy,晚了三年,但我在keep 上添加了一个部分。 ;)
    • 如何撤消最后一次提交?请帮忙。如果我使用 git reset --soft HEAD~1 我收到:致命:模糊参数'HEAD~1':未知修订或路径不在工作树中。使用 '--' 将路径与修订分开,如下所示:'git [...] -- [...]'
    【解决方案3】:

    这是一篇有用的文章,它以图形方式显示了重置命令的解释。

    https://git-scm.com/docs/git-reset

    Reset --hard 可能非常危险,因为它会在不检查的情况下覆盖您的工作副本,因此如果您根本没有提交文件,它就会消失。

    至于源代码树,我不知道撤消提交的方法。无论如何,它很可能会在幕后使用重置

    【讨论】:

    • +1 获取官方文档的链接。我还要提到git reset --help,它很好地解释了(在我看来)五种模式,或者至少是 OP 要求的两种模式。
    • 链接已损坏。可能这是当前版本:git-scm.com/docs/git-reset
    【解决方案4】:

    这是使用 git reset --hardgit reset --soft 的主要区别:

    --soft
    

    根本不接触索引文件或工作树(但将头部重置为 ,就像所有模式一样)。正如 git status 所说的那样,这会使您所有更改的文件都“提交更改”。

    --hard
    

    重置索引和工作树。此后对工作树中跟踪文件的任何更改都将被丢弃。

    【讨论】:

    • 这就是我要找的。简洁准确。
    猜你喜欢
    • 2021-07-04
    • 2017-12-10
    • 2019-09-05
    • 2021-10-28
    • 2011-09-06
    • 2023-03-23
    • 2020-04-07
    • 2018-01-13
    相关资源
    最近更新 更多