我看到有趣的帖子解释了关于git reset
微妙之处。 git
不幸的是,我读的越多,我就越不能彻底理解它。 我来自SVN背景,Git是一个全新的范例。 我很容易变得善变,但Git更具技术性。 安全
我认为git reset
接近hg revert
,但彷佛存在差别。 服务器
那么git reset
究竟作了什么? 请包括如下详细说明: svn
--hard
, - --soft
和--merge
; HEAD
使用的奇怪符号,如HEAD^
和HEAD~1
; HEAD
和您的全球压力水平的影响。 当您提交git的东西时,首先必须暂存(添加到索引)您的更改。 这意味着在git认为它们是提交的一部分以前,你必须git添加你想要包含在这个提交中的全部文件。 让咱们先来看看git repo的图像: 工具
因此,如今很简单。 咱们必须在工做目录中工做,建立文件,目录和全部。 这些更改是未跟踪的更改。 要跟踪它们,咱们须要使用git add命令将它们添加到git索引。 一旦将它们添加到git索引中。 若是咱们想将它推送到git存储库,咱们如今能够提交这些更改。 学习
但忽然间咱们知道咱们提交了一个额外的文件,咱们在索引中添加了不须要推入git存储库。 这意味着咱们不但愿索引中的该文件。 如今的问题是如何从git索引中删除该文件,由于咱们使用git add将它们放在索引中,因此使用git rm是合乎逻辑的? 错误! git rm将简单地删除该文件并将删除添加到索引中。 那么如今该怎么办: ui
使用:- spa
git重置 线程
它清除您的索引,保持您的工做目录不变。 (只是取消暂停一切)。 指针
它能够与许多选项一块儿使用。 使用git reset有三个主要选项: - hard, - soft和--mixed 。 重置时,这些会影响除HEAD指针以外的重置。
首先, - 硬重置一切。 您当前的目录将彻底像您一直关注该分支同样。 工做目录和索引将更改成该提交。 这是我常用的版本。 git reset --hard就像svn revert 。
接下来,彻底相反的-soft ,不会重置工做树和索引。 它只移动HEAD指针。 这使您的当前状态的任何更改都与您在目录中切换到的提交不一样,而且“暂存”以进行提交。 若是您在本地进行提交但还没有将提交推送到git服务器,则能够重置为先前的提交,并从新发送一个良好的提交消息。
最后, - mix复制索引,但不重置工做树。 所以,全部更改仍然存在,可是“未分级”而且须要git add'ed或git commit -a 。 咱们有时会使用这个,若是咱们使用git commit -a承诺了更多,咱们可使用git reset -mixed返回提交,添加咱们想要提交的东西并提交它们。
git revert和git reset之间的区别 : -
在简单的话,git的复位是“修复未提交的错误”和Git将其还原为命令,以“修复COMMITED错误”的命令。
这意味着若是咱们在某些更改中犯了一些错误并提交并将其推送到git repo,那么git revert就是解决方案。 若是咱们在推送/提交以前已经识别出相同的错误,咱们可使用git reset来解决问题。
我但愿它能够帮助你摆脱困惑。
通常来讲, git reset
的功能是获取当前分支并将其重置为指向其余位置,并可能带来索引和工做树。 更具体地说,若是您的主分支(当前已检出)是这样的:
- 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
,但主分支在C
处留下。 若是你在这一点上作了一个新的提交D
,你会获得这个,这可能不是你想要的:
- A - B - C (master) \ D (HEAD)
请记住,reset不会进行提交,它只是更新一个分支(指向提交的指针)以指向不一样的提交。 其他的只是索引和工做树会发生什么的详细信息。
我git reset
在下一节中对各类选项的描述中介绍git reset
许多主要用例。 它能够真正用于各类各样的事情; 常见的线程是全部这些都涉及重置分支,索引和/或工做树以指向/匹配给定的提交。
--hard
可能会让你真的失去工做。 它会修改您的工做树。
git reset [options] 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
全部内容重置为其余分支中的状态, git reset -- .
将当前目录重置为HEAD中的状态,而且简单的git reset
会将全部内容重置为HEAD中的状态。
有四个主要选项能够控制在重置期间工做树和索引起生的状况。
请记住,索引是git的“临时区域” - 当你说准备提交git add
时,事情就会发生。
--hard
使一切都与你重置的提交相匹配。 这多是最容易理解的。 您全部的本地更改都会被破坏。 一个主要用途是吹走你的工做而不是切换提交: git reset --hard
意味着git reset --hard HEAD
,即不要更改分支可是去除全部本地更改。 另外一种是简单地将分支从一个地方移动到另外一个地方,并使索引/工做树保持同步。 这能够真正让你失去工做,由于它会修改你的工做树。 很是肯定你想在运行任何reset --hard
以前扔掉当地的工做 - reset --hard
。
--mixed
是默认值,即git reset
意味着git reset --mixed
。 它重置索引,但不重置工做树。 这意味着您的全部文件都是完整的,但原始提交与您重置的文件之间的任何差别都将显示为具备git status的本地修改(或未跟踪文件)。 当你意识到你作了一些很差的提交时,使用它,但你想保留你已经完成的全部工做,这样你就能够修复它并从新发送。 为了提交,你必须再次将文件添加到索引( git add ...
)。
--soft
不会触及索引或工做树。 全部文件都与--mixed
同样完整,但全部更改都显示为changes to be committed
使用git status changes to be committed
(即在准备提交时签入)。 当你意识到你作了一些很差的提交时使用它,可是工做都很好 - 你须要作的就是以不一样的方式从新发送它。 索引是不变的,所以您能够根据须要当即提交 - 结果提交将具备与重置以前相同的内容。
--merge
最近被添加,旨在帮助您停止失败的合并。 这是必要的,由于git merge
实际上容许您尝试与脏工做树(具备本地修改的工做树)合并,只要这些修改在不受合并影响的文件中。 git reset --merge
重置索引(如--mixed
- 全部更改都显示为本地修改),并重置受合并影响的文件,但--mixed
其余文件。 这将有望恢复在糟糕合并以前的一切。 你一般会将它用做git reset --merge
(意思是git reset --merge HEAD
),由于你只想重置合并,而不是实际移动分支。 ( HEAD
还没有更新,由于合并失败)
更具体地说,假设您已经修改了文件A和B,而且尝试在修改了文件C和D的分支中进行合并。因为某种缘由合并失败,而且您决定停止它。 你使用git reset --merge
。 它将C和D带回到它们在HEAD
,但仅对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
表示提交的第二个父级。 请记住,正常的合并提交有两个父级 - 第一个父级是合并的提交,第二个父级是合并的提交。 通常来讲,合并实际上能够有任意多的父母(章鱼合并)。 ^
和~
运算符能够串成,如在HEAD~3^2
,第三代祖先的第二个亲本HEAD
, HEAD^^2
,的第一个亲本的第二个亲本HEAD
,甚至HEAD^^^
,至关于HEAD~3
。 请记住,在git
你有:
HEAD
指针 ,它告诉您正在进行的提交 请包括如下详细说明:
--hard
, ---soft
和--merge
;
随着危险程度的增长:
--soft
移动HEAD
但不触及暂存区域或工做树。 --mixed
移动HEAD
并更新暂存区域,但不更新工做树。 --merge
移动HEAD
,重置暂存区域,并尝试将工做树中的全部更改移动到新的工做树中。 --hard
移动HEAD
并将你的临时区域和工做树调整到新HEAD
,扔掉全部东西。 具体用例和工做流程;
--soft
。 你须要这个不多见。 -
# git reset --soft example touch foo // Add a file, make some changes. git add foo // git commit -m "bad commit message" // Commit... D'oh, that was a mistake! git reset --soft HEAD^ // Go back one commit and fix things. git commit -m "good commit" // There, now it's right.
-
当您想要查看另外一次提交时的内容时,请使用--mixed
(这是默认设置),但您不但愿丢失已有的任何更改。
若是要移动到新位置,请使用--merge
,但将已有的更改合并到工做树中。
使用--hard
擦除全部内容并在新提交中开始新的事件。
请注意,这是一个简化的解释,旨在做为了解这一复杂功能的第一步。
对于想要在每一个命令以后可视化项目状态的视觉学习者可能会有所帮助:
对于那些使用打开颜色的终端的人(git config --global color.ui auto):
git reset --soft A
你会看到B和C的东西是绿色的(上演并准备提交)
git reset --mixed A
(或git reset A
),你会看到B和C的东西是红色的(未分阶段,准备上演(绿色),而后提交)
git reset --hard A
你将不会再看到B和C的变化(就好像它们从未存在过)
或者对于那些使用像'Tower'或'SourceTree'这样的GUI程序的人
git reset --soft A
,你会在'staged files'区域看到B和C的东西准备提交
git reset --mixed A
(或git reset A
),你会在'unstaged files'区域看到B和C的东西,准备移动到staged而后提交
git reset --hard A
你将不会再看到B和C的变化(就好像它们从未存在过)
TL; DR
git reset
Staging重置为上次提交。 使用--hard
还能够将工做目录中的文件重置为上次提交。
更长的版本
但这显然是简单化的,所以许多至关冗长的答案。 在撤消更改的上下文中,我更有意义地阅读git reset
。 例如看到这个:
若是git revert是一种撤消更改的“安全”方式,您能够将git reset视为危险方法。 使用git reset撤消(而且任何ref或reflog再也不引用提交)时,没法检索原始副本 - 它是永久撤消。 使用此工具时必须当心,由于它是惟一可能丢失工做的Git命令之一。
来自https://www.atlassian.com/git/tutorials/undoing-changes/git-reset
还有这个
在提交级别,重置是一种将分支的提示移动到另外一个提交的方法。 这可用于从当前分支中删除提交。
来自https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations