你能解释一下“git reset”在纯英文中的作用吗?

我看到有趣的post解释有关git reset微妙之处。

不幸的是,我读得越多,看起来就越不完整。 我来自SVN背景,Git是一个全新的范例。 我很容易,但Git更技术性。

我认为git reset很接近于hg revert ,但似乎有差异。

那么git reset做什么的? 请包括以下详细的解释:

  • 选项 – --soft , – --soft--merge ;
  • HEAD使用的奇怪符号,如HEAD^HEAD~1 ;
  • 具体的使用情况和工作stream程;
  • 对工作副本, HEAD和你的全球压力水平的影响。

一般来说, git reset的function是取当前分支并将其重置到其他地方,并可能带来索引和工作树。 更具体地说,如果你的主分支(当前签出)是这样的:

 - A - B - C (HEAD, 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) 

记住,重置不会提交,只是更新一个分支(这是一个提交的指针)指向一个不同的提交。 其余的只是你的索引和工作树发生的细节。

用例

我在下一节的各种选项描述中介绍了git reset许多主要用例。 它可以真正用于各种各样的事情; 共同的线索是,它们都涉及重置分支,索引和/或工作树以指向/匹配给定的提交。

要注意的事情

  • --hard可能会让你真的失去工作。 它修改你的工作树。

  • git reset [options] commit可以导致你(有点)失去提交。 在上面的玩具例子中,我们失去了C提交。 它仍然在回购,你可以通过查看git reflog show HEADgit reflog show master来find它,但是它不能从任何分支实际访问。

  • Git会在30天后永久删除这样的提交,但在此之前,您可以通过再次指向一个分支来恢复C( git checkout C; git branch <new branch name> )。

参数

解释手册页,最常见的用法是formsgit reset [<commit>] [paths...] ,它将给定的提交path重置给他们的状态。 如果没有提供path,那么整个树就会被重置,如果没有提供提交,它将被视为HEAD(当前提交)。 这是一个跨git命令的常见模式(例如checkout,diff,log,尽pipe确切的语义有所不同),所以不要太奇怪。

例如, 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之前丢掉本地的工作。

  • --mixed是默认的,即git reset意味着git reset --mixed 。 它重置索引,但不是工作树。 这意味着你的所有文件都是完整的,但是原来的提交和你重置的文件之间的任何差异都会显示为本地修改(或未跟踪的文件)和git状态。 当你意识到你做了一些不好的提交时使用它,但是你想保留所有你已经完成的工作,所以你可以修复它并重新提交。 为了提交,你必须再次添加文件到索引( git add ... )。

  • --soft不会触摸索引工作树。 你所有的文件和--mixed都是完好无损的,但是所有的变化都显示为git状态的变化(例如,在准备提交时签入)。 当你意识到你做了一些不好的提交时使用它,但是工作都很好 – 你所需要做的就是以不同的方式重新提交。 该索引是未触及的,所以你可以立即提交,如果你想要的 – 结果提交将具有所有相同的内容,因为你在重置之前。

  • --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的工作方式让他们真的沉入其中。 特别是,如果你花时间仔细阅读它们,那些详细说明索引和工作树中文件状态的表格对于所有的各种选项和情况都是非常有帮助的。 (但是,是的,他们非常密集 – 他们以非常简洁的forms传达了上述很多信息。)

奇怪的表示法

你提到的“奇怪符号”( HEAD^HEAD~1 )只是简单的指定提交的简写,而不必使用像3ebe3f6这样的散列名。 它在git-rev-parse手册页的“指定修订版本”部分中有完整的文档,有很多示例和相关的语法。 脱字符号和代字符实际上意味着不同的东西 :

  • HEAD~HEAD~的缩写,意思是提交的第一个父代。 HEAD~2表示提交的第一个父代的第一个父代。 把HEAD~n看作“n在HEAD之前提交”或者“HEAD的第n代祖先”。
  • HEAD^ (或HEAD^1 )也表示提交的第一个父代。 HEAD^2表示提交的第二个父代。 请记住,正常的合并提交有两个父母 – 第一个父母是合并提交,第二个父母是合并的提交。 一般来说,合并实际上可以有许多父母(章鱼合并)。
  • ^~运算符可以串在一起,如HEAD~3^2HEAD~3^2的第三代祖先的第二个父母, HEAD^^2HEAD^^2的第一个父亲的第二个父代,甚至HEAD^^^ ,相当于HEAD~3

脱字符和代字符

记住在git你有:

  • 指针 ,它告诉你你正在做什么提交
  • 工作树 ,表示您的系统上的文件的状态
  • 中间阶段 (也称为索引 ),“阶段”变化,以便他们以后可以一起承担

请包括以下详细的解释:

--hard --soft , – --soft--merge ;

按照危险性的顺序排列:

  • --soft移动HEAD但不接触暂存区域或工作树。
  • --mixed移动HEAD和更新暂存区域,但不是工作树。
  • --merge移动HEAD ,重置暂存区域,并尝试将工作树中的所有更改移动到新的工作树中。
  • --hard移动头, 调整你的集结区和工作树到新的头,扔掉一切。

具体的使用案例和工作stream程;

  • 当你想移动到另一个提交时使用--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所有东西都抹掉,并在新的提交中开始一个新的石板。

在Pro Git博客中发布的“ 重新揭秘”内容对git resetgit checkout提供了一个非常简单的解释。

经过所有有用的讨论后,作者将这些规则简化为以下简单的三个步骤:

基本上就是这样。 reset命令以特定顺序覆盖这三棵树,当你告诉它时停止。

  1. 移动HEAD指向的任何分支(如果 – --soft停止)
  2. 那么,使索引看起来像这样(除非 – --hard ,停下来)
  3. 那么,使工作目录看起来像那样

还有--merge--keep选项,但我现在宁愿保持简单 – 这将是另一篇文章。

当你提交一些东西,你必须首先阶段(添加到索引)你的变化。 这意味着在git认为它们是提交的一部分之前,你必须添加你希望包含在这个提交中的所有文件。 我们先来看一下git仓库的形象: 在这里输入图像描述

所以,现在它很简单。 我们必须在工作目录,创build文件,目录和所有。 这些变化是没有跟踪的变化。 为了跟踪它们,我们需要使用git add命令将它们添加到git索引中。 一旦他们被添加到git索引。 我们现在可以提交这些更改,如果我们想把它推到git仓库。

但突然我们知道了,在提交时我们有一个额外的文件,我们在索引中添加不需要推入git仓库。 这意味着我们不希望在索引中的文件。 现在的问题是如何从git索引中删除该文件,既然我们使用git add将它们放在索引中,那么使用git rm是合乎逻辑的? 错误! git rm将简单地删除文件并将删除添加到索引。 那么现在该怎么做:

使用:-

混帐重置

它清除你的索引,保持你的工作目录不变。 (简单地将所有东西都打开)。

它可以使用与它的选项数量。 使用git reset有三个主要选项:–hard, – soft和–mixed 。 除了HEAD指针之外,这些还会影响重置时得到的重置。

首先,重新设置一切。 您的当前目录将与您一直关注该分支的情况完全相同。 工作目录和索引被更改为提交。 这是我经常使用的版本。 git reset – hard就像svn revert

接下来,完全相反, ,不重置工作树或索引。 它只移动HEAD指针。 这使得您的当前状态的任何更改都与您在目录中切换到的提交不同,并且“提交”提交。 如果你在本地提交了一个提交,但是没有把提交推送到git服务器上,你可以重置到前一个提交,并重新提交一个好的提交信息。

最后, – 混合重置索引,但不是工作树。 所以变化都在那里,但是“未分离”,将需要git add'ed或git commit -a 。 我们有时使用这个,如果我们承诺比git commit更多的话,我们可以使用git reset –mixed来退出commit,添加我们想要提交的东西,然后提交它们。

git revert和git reset之间的区别 : –


简单地说, git reset是一个“修复无法解决的错误”的命令, git revert是一个“修复错误”的命令。

这意味着如果我们在某些变化中犯了一些错误,并且提交并推送到git repo,那么git revert就是解决scheme。 如果我们在推送/提交之前发现了相同的错误,我们可以使用git reset来解决这个问题。

我希望这会帮助你摆脱困惑。

TL; DR

git reset分段重置为最后的提交。 使用--hard还可以将工作目录中的文件重置为上次提交。

更长的版本

但是,这显然是简单的,因此许多相当冗长的答案。 在撤消更改的情况下,阅读git reset是更有意义的。 例如看到这个:

如果git恢复是一个“安全”的方式来撤消更改,你可以把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

请注意,这是一个简单的解释,旨在作为寻求理解这个复杂function的第一步。

对于希望在每个命令之后可视化他们的项目状态看起来像的视觉学习者可能是有帮助的:


对于那些使用terminal打开颜色(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 ),你会看到B和C的东西在'unstaged文件'区域准备好移动到staged,然后提交

git reset --hard A ,你不会再看到B和C的变化(就像他们从来没有存在过)

有一个非常好的文章来解释重置(包括结帐/反向和他们的比较),希望它有帮助。 https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/summary