通常,git reset
的功能是获取当前分支并将其重置为指向其他位置,并可能将索引和工作树一起使用。更具体地说,如果您的master分支(当前已签出)是这样的:
- A - B - C (HEAD, master)
并且您意识到您希望master指向B,而不是C,您将使用git reset B
它来移动它:
- A - B (HEAD, master) # - C is still here, but there's no branch pointing to it anymore
离题:这与结帐不同。如果您运行git checkout B
,则会得到以下信息:
- A - B (HEAD) - C (master)
您最终处于分离的HEAD状态。HEAD
,工作树,索引全部匹配B
,但master分支留在C
。如果此时进行新的提交D
,您将得到此信息,这可能不是您想要的:
- A - B - C (master)
\
D (HEAD)
请记住,reset不会提交提交,它只会更新一个分支(这是指向提交的指针)以指向另一个提交。剩下的只是索引和工作树发生的细节。
用例
git reset
在下一节中,我将在各种选项的描述中介绍许多主要用例。它确实可以用于各种各样的事物。共同的线程是所有这些都涉及重置分支,索引和/或工作树以指向/匹配给定的提交。
要注意的事情
--hard
会导致您真的失去工作。它修改了您的工作树。
git reset [options] commit
可能导致您(某种程度上)丢失提交。在上面的玩具示例中,我们丢失了commit C
。它仍在存储库中,您可以通过查看git reflog show HEAD
或来找到它git reflog show master
,但实际上不再可以从任何分支访问它。
Git在30天后会永久删除此类提交,但是在此之前,您可以通过再次将分支指向C来恢复它(git checkout C; git branch <new branch name>
)。
争论
解释手册页,最常见的用法是形式git reset [<commit>] [paths...]
,它将把给定路径从给定提交重置为其状态。如果未提供路径,则会重置整个树,如果未提供提交,则将其视为HEAD(当前提交)。这是整个git命令的通用模式(例如,checkout,diff,log,尽管确切的语义有所不同),所以这并不奇怪。
例如,将git reset other-branch path/to/foo
path / to / foo中的所有内容git reset -- .
重置为other-branch中的状态,将当前目录重置为HEAD中的状态,简单地将git reset
所有内容重置为HEAD中的状态。
主要工作树和索引选项
有四个主要选项可以控制重置期间工作树和索引的处理方式。
记住,索引是git的“临时区域”-当您git add
准备提交时,它就是这里的去处。
--hard
使所有内容都与您已重置的提交匹配。这可能是最容易理解的。您所有的本地更改都会受到破坏。一种主要用途是浪费您的工作,但不切换提交:git reset --hard
means git reset --hard HEAD
,即,不更改分支,但摆脱所有本地更改。另一个只是将分支从一个位置移动到另一个位置,并使索引/工作树保持同步。这确实会使您失去工作,因为它修改了您的工作树。非常非常确定要在运行任何操作之前先放弃本地工作reset --hard
。
--mixed
是默认值,即git reset
means git reset --mixed
。它重置索引,但不重置工作树。这意味着您的所有文件都是完整的,但是原始提交和您重置为的所有提交之间的任何差异都将以git状态显示为本地修改(或未跟踪的文件)。当您意识到自己做了一些错误的提交,但是想要保留所有已完成的工作,以便对其进行修复和重新提交时,请使用此功能。为了提交,您必须再次将文件添加到索引(git add ...
)。
--soft
不触及索引或工作树。和一样--mixed
,您的所有文件均完好无损,但所有更改都显示为changes to be committed
git status(即已签入,准备提交)。当您意识到自己做了一些错误的提交,但工作很顺利时,请使用此功能-您要做的就是以不同的方式重新提交它。索引未更改,因此您可以根据需要立即提交-所生成的提交将具有与重置之前相同的内容。
--merge
是最近添加的,旨在帮助您中止失败的合并。这是必要的,因为git merge
只要这些修改在不受合并影响的文件中,实际上就可以让您尝试与脏工作树(具有本地修改的工作树)进行合并。git reset --merge
重置索引(例如--mixed
-所有更改都显示为本地修改),并重置受合并影响的文件,但将其他文件保留下来。希望这将使一切恢复到错误合并之前的状态。通常将其用作git reset --merge
(含义git reset --merge HEAD
),因为您只想重置合并,而不实际移动分支。(HEAD
由于合并失败,尚未更新)
更具体地说,假设您已经修改了文件A和B,并尝试在一个分支中合并了修改文件C和D的文件。由于某种原因合并失败,因此您决定中止该文件。您使用git reset --merge
。它使C和D恢复它们的状态HEAD
,但由于A和B并不是合并尝试的一部分,因此您只需对A和B进行修改。
想知道更多?
我确实认为man git reset
这确实非常有用-也许您确实需要git的工作方式让他们真正陷入困境。特别是,如果您花时间仔细阅读它们,则这些表详细列出了所有各种选项和案例的索引和工作树中的文件状态,这些非常有用。(但是,是的,它们非常密集-他们以非常简洁的形式传达了很多上述信息。)
奇怪的符号
您提到的“奇怪记号”(HEAD^
和HEAD~1
)只是用于指定提交的简写形式,而不必使用诸如的哈希名称3ebe3f6
。在git-rev-parse的手册页的“指定修订”部分中有完整的文档,并提供了许多示例和相关语法。插入符号和波浪号实际上表示不同的含义:
HEAD~
的缩写HEAD~1
,表示提交的第一父级。HEAD~2
表示提交的第一父级的第一父级。可以认为HEAD~n
是“在HEAD之前提交了n次提交”或“ HEAD的第n代祖先”。
HEAD^
(或HEAD^1
)也表示提交的第一父级。HEAD^2
表示提交的第二个父级。请记住,普通的合并提交有两个父级-第一个父级是merged-into提交,第二个父级是已合并的提交。通常,合并实际上可以有任意多个父母(章鱼合并)。
- 的
^
和~
运营商可以被串在一起,如在HEAD~3^2
,第三代祖先的第二亲本HEAD
,HEAD^^2
,的第一个亲本的第二个亲本HEAD
,或甚至HEAD^^^
,这相当于HEAD~3
。