git reset --hard HEAD~1
是否危险?
git reset
的不同选项有什么区别?git reset
命令有五种 "模式":soft、mixed、hard、merge 和 keep。本文将从前三种模式开始介绍,因为这是你通常会遇到的模式。接下来你会发现一个不错的小奖励,所以请继续关注。
假设你有一个类似于以下历史记录的代码库:
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
命令时,你将从当前分支中移除最近一次提交,但文件更改将保留在工作树中。此外,更改也将保留在索引中,因此接下来如果执行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中未提交的更改!git reset
删除提交时,提交并不会真正丢失,只是没有指向它或任何子提交的引用。你仍然可以通过找到其SHA-1键来恢复使用git reflog
等命令“删除”的提交。--hard
几乎从来不是正确的选择,因为--keep
更安全,并适用于大多数--hard
适用的情况。训练你的手指使用--keep
可能会在某一天拯救你... - Matthieu MoyGit reset有5种主要模式:soft、mixed、merged、hard、keep。它们之间的区别在于是否更改head、stage(索引)、工作目录。
Git reset --hard会更改head、索引和工作目录。
Git reset --soft仅更改head,不更改索引和工作目录。
换句话说,如果您想撤消提交,--soft就足够了。但是之后,您仍然可以在索引和工作目录中看到坏提交的更改。您可以修改文件,将其修复,将其添加到索引并再次提交。
使用--hard将使您在项目中完全获得干净的板 slate。就好像没有任何来自上一次提交的更改一样。如果您确定这就是您想要的,请继续操作。但是一旦执行此操作,您将完全失去上一个提交。(注意:仍然有方法可以恢复丢失的提交)。
git reset --help
,它很好地解释了五种模式中的至少两种(在我看来)。 官方文档链接:https://git-scm.com/docs/git-reset - ThanksForAllTheFish
--soft
此模式不会触及索引文件或工作树(但像所有模式一样,会将HEAD重置为新的提交)。这将使得所有已修改的文件都成为“待提交的更改”,就像git status所显示的那样。
--hard
重置索引和工作树。自上次提交以来在工作树中对已跟踪文件所做的任何更改都将被丢弃。
reset --hard <commit-id>
命令可以让你回到某个提交状态,并忘记该提交后所有的更改。而 reset --soft <commit-id>
命令也可以让你回到某个提交状态,但保留了在该提交后未提交的文件,你可以对其进行操作。git push -f origin <branch-name>
,因为远程分支提交 ID 不同步。