'git reset --hard HEAD~1'和'git reset --soft HEAD~ 1'有什么区别?

hlswsv35  于 2023-02-14  发布在  Git
关注(0)|答案(5)|浏览(162)

我试图在git中取消提交。使用git reset --hard HEAD~1有危险吗?
git reset的不同选项之间有什么区别?

y0u0uwnf

y0u0uwnf1#

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是一个有趣而有用的工具。它只重置当前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这样的命令。

pieyvz9o

pieyvz9o2#

Git重置有5种主要模式:软、混合、合并、硬、保留,它们之间的区别是改变或不改变头、阶段(索引)、工作目录
Git reset --很难改变头、索引和工作目录。
Git reset --soft只会改变头文件,不改变索引和工作目录。
换句话说,如果你想撤销你的提交,--soft就足够了,但是在那之后,你的索引和工作目录中仍然有错误提交的修改,你可以修改文件,修复它们,把它们添加到索引中,然后再次提交。
使用--hard,你的项目就完全是一张白纸。就好像上次提交后没有任何改变一样。如果你确定这是你想要的,那就继续前进。但是一旦你这样做了,你就会完全失去上次提交的内容。(注:仍然有恢复丢失的提交的方法)。

os8fio9y

os8fio9y3#

这是一个有用的文章,它以图形方式显示了reset命令的解释。
https://web.archive.org/web/20171119010424/http://git-scm.com/blog/2011/07/11/reset.html
Reset --hard可能非常危险,因为它会在不检查的情况下覆盖您的工作副本,所以如果您根本没有提交该文件,它就会消失。
至于源代码树,据我所知,没有办法撤销提交,它很可能会使用重置的掩护下反正

hpxqektj

hpxqektj4#

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

--soft

完全不接触索引文件或工作树(但像所有模式一样,将头重置为)。这会使所有更改过的文件都处于“待提交的更改”状态,正如git status所写的那样。

--hard

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

8ehkhllq

8ehkhllq5#

就这么简单,reset --hard <commit-id>会让你进入提交状态,并忘记提交状态后所做的所有更改,在其他情况下,reset --soft <commit-id>也会让你回到提交状态,但保持提交状态后提交的文件未暂存,你可以玩它。
注意:如果你是在本地机器环境下做的,你必须强制推送到你更新的工作git push -f origin <branch-name>,因为远程分支提交id是不同步的。

相关问题