用简单的英语,"git reset"有什么作用?

e-s*_*tis 657 git reset

我看到有趣的帖子解释了微妙之处git reset.

不幸的是,我读的越多,我就越不能完全理解它.我来自SVN背景,Git是一个全新的范例.我很容易变得善变,但Git更具技术性.

我认为git reset很接近hg revert,但似乎存在差异.

究竟究竟做了git reset什么?请包括以下详细说明:

  • 选项--hard,--soft--merge;
  • 你使用的奇怪符号HEADHEAD^HEAD~1;
  • 具体用例和工作流程;
  • 对工作副本,HEAD全球压力水平的影响.

Cas*_*bel 962

通常,git reset函数是获取当前分支并将其重置为指向其他位置,并可能带来索引和工作树.更具体地说,如果您的主分支(当前已检出)是这样的:

- A - B - C (HEAD, master)
Run Code Online (Sandbox Code Playgroud)

并且你意识到你希望主人指向B,而不是C,你会用git reset B它来移动它:

- A - B (HEAD, master)      # - C is still here, but there's no branch pointing to it anymore
Run Code Online (Sandbox Code Playgroud)

题外话:这与结账不同.如果你跑git checkout B,你会得到这个:

- A - B (HEAD) - C (master)
Run Code Online (Sandbox Code Playgroud)

你最终处于一个独立的HEAD状态.HEAD,工作树,索引全部匹配B,但主分支留在了C.如果你D在这一点上做了一个新的提交,你会得到这个,这可能不是你想要的:

- A - B - C (master)
       \
        D (HEAD)
Run Code Online (Sandbox Code Playgroud)

请记住,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/foopath/to/foo中的所有内容git reset -- .重置为other-branch中的状态,将当前目录重置为HEAD中的状态,并简单地将git reset所有内容重置为HEAD中的状态.

主要工作树和索引选项

有四个主要选项可以控制在重置期间工作树和索引发生的情况.

请记住,索引是git的"临时区域" - 当你git add准备提交时,它就是事情的发展方向.

  • --hard使所有内容与您重置的提交相匹配.这可能是最容易理解的.您所有的本地更改都会被破坏.一个主要用途是吹走你的工作而不是切换提交:git reset --hard意味着git reset --hard HEAD,即不要改变分支,但要摆脱所有的局部变化.另一种是简单地将分支从一个地方移动到另一个地方,并使索引/工作树保持同步.这可以真正让你失去工作,因为它会修改你的工作树.非常确定你想在运行之前扔掉当地的工作reset --hard.

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

  • --soft不会触及索引工作树.您的所有文件都是完整的--mixed,但所有更改都显示为changes to be committedgit 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进行修改,因为它们不是尝试合并的一部分.

想知道更多?

我觉得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.

插入符号和波浪形

  • 文档是好的,即使它需要永远阅读它们并且它们非常密集并且需要永远地验证它们说它的工作方式就像你已经知道它是如何工作的那样.听起来不像文档对我有好处...... (31认同)
  • @ e-satisf:git checkout将移动HEAD,但将分支留在原处.这适用于您想要移动分支的时间. (5认同)
  • 这个SO答案给出了一个简单易懂的解释:stackoverflow.com/questions/3528245/whats-the-difference-between-git-reset-mixed-soft-and-hard (4认同)
  • 好的。我刚刚得到了一些非常重要的东西。你说“没有分支指向它”,这让我很烦恼。现在我懂了。分支不是一个更改列表,它只是指向历史记录中某个位置的指针,不是吗?这就是为什么 SVN 的人不理解它,我们没有以正确的方式看待它。非常有用的帖子,希望您能从中得到很多回报。 (2认同)
  • @Kirby 我需要更长的时间才能阅读这样的内容。这些文档完整、正确且简洁,这意味着它们很密集。这是重要的信息;如果不进行总结和近似,你永远无法在短时间内传达它。 (2认同)

Joh*_*lla 78

请记住,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.
Run Code Online (Sandbox Code Playgroud)

-

  • --mixed当您想要查看另一次提交时的内容时,请使用(这是默认设置),但您不希望丢失已有的任何更改.

  • 使用--merge时要移动到一个新的地方,但包括你已经进入了工作树的变化.

  • 使用--hard擦拭的一切,并开始在新的一个新的石板提交.

  • 这不是`reset --merge`的预期用例.它不执行三向合并.它实际上只是用于重置冲突的合并,如文档中所述.你会想用`checkout --merge`做你正在谈论的事情.如果你想移动分支,我认为唯一的方法是跟进一些结账/重置以拖动它. (2认同)
  • 我发现这个答案最简单,最有帮助 (2认同)

Dan*_*ich 35

博客Pro Git中的帖子重置揭秘给出了一个非常明智的解释和.git resetgit checkout

在该帖子顶部的所有有用的讨论之后,作者将规则简化为以下简单的三个步骤:

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

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

也有--merge--keep选择,但我宁愿让事情变得更简单,现在-这将是另一篇文章.

  • 我只花了 13 年的时间编写代码才最终坐下来理解这些概念 (2认同)

lov*_*ove 25

当您提交git的东西时,首先必须暂存(添加到索引)您的更改.这意味着在git认为它们是提交的一部分之前,你必须git添加你想要包含在这个提交中的所有文件.让我们先来看看git repo的图像: 在此输入图像描述

所以,现在很简单.我们必须在工作目录中工作,创建文件,目录和所有.这些更改是未跟踪的更改.要跟踪它们,我们需要使用git add命令将它们添加到git索引.一旦将它们添加到git索引中.如果我们想将它推送到git存储库,我们现在可以提交这些更改.

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

使用:-

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的复位就是命令"修复未提交的错误"混帐复归就是命令"修复COMMITED错误".

这意味着如果我们在某些更改中犯了一些错误并提交并将其推送到git repo,那么git revert就是解决方案.如果我们在推送/提交之前已经识别出相同的错误,我们可以使用git reset来解决问题.

我希望它可以帮助你摆脱困惑.

  • 这是OP提出的一个很好的简单英语答案. (2认同)

Sno*_*ash 6

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