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

In plain English, what does “git reset” do?

我看过一些有趣的文章,解释了关于git reset的微妙之处。

不幸的是,我读到的越多,我就越不完全理解它。我来自SVN背景,而Git是一个全新的范例。我很容易变化无常,但Git更具技术性。

我认为git resethg revert很接近,但似乎有区别。

那么,git reset究竟做了什么?请详细说明:

  • 期权--hard--soft--merge
  • HEAD一起使用的奇怪符号,如HEAD^HEAD~1
  • 具体用例和工作流程;
  • 对工作副本、HEAD和全球压力水平的影响。


一般来说,git reset的功能是获取当前分支并将其重置为其他位置,并可能将索引和工作树带到一起。更具体地说,如果您的主分支(当前已签出)如下所示:好的。

1
- A - B - C (HEAD, master)

你意识到你想让大师指向b而不是c,你会用git reset B把它移到那里:好的。

1
- A - B (HEAD, master)      # - C is still here, but there's no branch pointing to it anymore

题外话:这和结账不同。如果你运行git checkout B,你会得到:好的。

1
- A - B (HEAD) - C (master)

你最终进入了一种超然的状态。HEAD,工作树,索引都匹配B,但主分支留在C。如果您在这一点上作出新的承诺,那么您将得到这一点,这可能不是您想要的:好的。

1
2
3
- A - B - C (master)
       \
        D (HEAD)

记住,reset不进行提交,它只是更新一个分支(指向提交的指针)以指向不同的提交。剩下的只是您的索引和工作树发生了什么的细节。好的。用例

我在下一节中对各种选项的描述中介绍了git reset的许多主要用例。它实际上可以用于各种各样的事情;常见的线程是,它们都涉及到重置分支、索引和/或工作树以指向/匹配给定的提交。好的。要小心的事情

  • --hard会使你真正失去工作。它会修改您的工作树。好的。

  • git reset [options] commit会使你(某种程度上)失去承诺。在上面的玩具示例中,我们丢失了commit C。它仍在回购中,您可以通过查看git reflog show HEADgit reflog show master找到它,但实际上它不再可以从任何分支访问。好的。

  • Git会在30天后永久删除这类承诺,但在此之前,您可以通过再次指向它的分支来恢复C(git checkout C; git branch )。好的。

论据

套用手册页,最常见的用法是git reset [] [paths...]格式,它将把给定的路径从给定的提交重置为它们的状态。如果没有提供路径,则会重置整个树,如果没有提供提交,则认为它是头(当前提交)。这是跨g it命令的一种常见模式(例如,checkout、diff、log,尽管确切的语义有所不同),所以这不应该太令人惊讶。好的。

例如,git reset other-branch path/to/foo将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状态的changes to be committed(即已签入以准备提交)。当你意识到你做了一些不好的承诺,但工作都是好的-你需要做的就是以不同的方式重新承诺。索引未被修改,因此如果需要,可以立即提交-结果提交将具有与重置前相同的内容。好的。

  • 最近增加了--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的缩写,表示commit的第一个父代。HEAD~2表示承诺的第一个母公司的第一个母公司。把HEAD~n看作是"头前的N承诺"或"头的第n代祖先"。
  • HEAD^HEAD^1也指承诺的第一个母公司。HEAD^2表示承诺的第二方母公司。记住,正常的合并提交有两个父级——第一个父级是合并到提交中的,第二个父级是合并后的提交。一般来说,合并可以有任意多个父母(章鱼合并)。
  • ^~操作符可以串在一起,如HEAD~3^2中,HEAD第三代祖先的第二代父代、HEAD^^2中,HEAD第一代父代的第二代父代,甚至HEAD^^^中,相当于HEAD~3

caret and tilde。好的。好啊。


记住,在git中,您有:

  • HEAD指针,它告诉您正在处理什么提交。
  • 工作树,表示系统上文件的状态
  • 临时区域(也称为索引),它会更改"阶段",以便以后可以一起提交。

Please include detailed explanations about:

--hard, --soft and --merge;

危险性的增加顺序:

  • --soft移动HEAD,但不接触集结区或工作树。
  • --mixed移动HEAD并更新临时区域,但不更新工作树。
  • --merge移动HEAD,重置临时区域,并尝试将工作树中的所有更改移动到新的工作树中。
  • --hard移动HEAD,调整你的集结地和工作树到新的HEAD,扔掉所有东西。

concrete use cases and workflows;

  • 当你想转移到另一个任务中去,在不"失去你的位置"的情况下,使用--soft。你很少需要这个。

——

1
2
3
4
5
6
# 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给出了一个非常简单的解释。

在文章顶部进行了所有有益的讨论之后,作者将规则简化为以下简单的三个步骤:

That is basically it. The reset command overwrites these three trees in a specific order, stopping when you tell it to.

  • Move whatever branch HEAD points to (stop if --soft)
  • THEN, make the Index look like that (stop here unless --hard)
  • THEN, make the Working Directory look like that
  • There are also --merge and --keep options, but I would rather keep things simpler for now - that will be for another article.


    当你向Git提交一些东西时,你首先必须准备(添加到索引中)你的更改。这意味着您必须在Git将其视为提交的一部分之前,Git添加您希望包含在此提交中的所有文件。让我们先看看Git回购的图像:enter image description here

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

    但是突然间我们知道了,在提交我们有一个额外的文件,我们在索引中添加了这个文件,不需要在Git存储库中进行推送。这意味着我们不希望该文件出现在索引中。现在的问题是如何从git索引中删除该文件,因为我们使用git add将其放入索引中,所以使用git rm是合乎逻辑的?错了!git rm只需删除文件并将删除内容添加到索引中。那么现在该怎么做:

    用途:

    git reset

    它会清除您的索引,使您的工作目录保持不变。(简单地把所有东西都拆开)。

    它可以与许多选项一起使用。Git Reset有三个主要选项可供使用:--硬、--软和--混合。当你重置时,除了头部指针之外,这些都会影响get的重置。

    首先,硬重置一切。您当前的目录将与您一直跟踪该分支时的目录完全相同。工作目录和索引将更改为该提交。这是我最常使用的版本。git reset——hard类似于svn revert。

    接下来,完全相反的-soft不会重置工作树或索引。它只移动头部指针。这将使您的当前状态中的任何更改都不同于您要在目录中就地切换到的提交,并"分段"进行提交。如果您在本地提交,但没有将提交推送到Git服务器,则可以重置为上一次提交,并使用良好的提交消息重新提交。

    最后,—mixed重置索引,但不重置工作树。所以这些更改仍然存在,但是是"未分页的",需要git-add ed或git-commit-a。如果我们提交的内容超过了git-commit-a的预期,我们有时会使用这个方法,我们可以使用git-reset退出commit-mixed,添加我们想要提交的内容,只需提交东南方。

    Git Revert和Git Reset之间的差异:

    简单来说,git reset是一个"修复未提交错误"的命令,而git revert是一个"修复已提交错误"的命令。

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

    我希望它能帮助你摆脱困惑。


    DR

    git reset resets Staging to the last commit. Use --hard to also reset files in your Working directory to the last commit.

    较长版本

    但这显然是简单化的,因此有许多相当冗长的答案。对于我来说,在撤销变更的背景下阅读git reset更有意义。例如,请参见:

    If git revert is a"safe" way to undo changes, you can think of git
    reset as the dangerous method. When you undo with git reset(and the
    commits are no longer referenced by any ref or the reflog), there is
    no way to retrieve the original copy—it is a permanent undo. Care must
    be taken when using this tool, as it’s one of the only Git commands that has the potential to lose your work.

    来自https://www.atlassian.com/git/tutorials/undong-changes/git-reset

    还有这个

    On the commit-level, resetting is a way to move the tip of a branch to a different commit. This can be used to remove commits from the current branch.

    来自https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations


    请注意,这是一个简化的解释,旨在作为理解这一复杂功能的第一步。

    对于希望在每个命令之后可视化项目状态的视觉学习者来说,这可能会有所帮助:

    对于那些使用已打开颜色的终端的用户(git config--global color.ui auto):

    git reset --soft A,你会看到B和C的东西是绿色的(阶段性的,准备好承诺的)

    git reset --mixed A(或git reset A),你会看到b和c的东西是红色的(未老化的,准备好上演的(绿色的),然后承诺)

    你再也看不到B和C的变化了(就好像它们从未存在过一样)。

    或者对于那些使用类似"tower"或"sourcetree"的GUI程序的用户

    git reset --soft A你会看到b和c的东西在"分阶段文件"区域准备提交

    EDOCX1(或EDOCX1(或EDOCX1)(2)),您将在"未归档文件"区域中看到b和c的内容,准备转移到阶段,然后提交

    你再也看不到B和C的变化了(就好像它们从未存在过一样)。


    签出将头部指向特定的提交。

    重置将分支指向特定的提交。(分支是指向提交的指针。)

    顺便说一句,如果你的头没有指向一个分支也指向的提交,那么你有一个分离的头。(原来是错的。请参见注释…)