非常教程

Git参考手册

基本快照 | Basic Snapshotting

git reset

命名

git-reset - 将当前 HEAD 重置为指定状态

概要

git reset [-q] [<tree-ish>] [--] <paths>…​
git reset (--patch | -p) [<tree-ish>] [--] [<paths>…​]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]

描述

在第一种和第二种形式中,将 <tree-ish> 中的条目复制到索引中。在第三种形式中,将当前分支头(HEAD)设置为 <commit> ,可选地修改索引和工作树以匹配。<tree-ish> / <commit> 默认为所有形式的 HEAD 。

git reset -q -- <paths>…​

该表单将所有 <paths> 的索引条目重置为它们在 <tree-ish> 的状态。(它不会影响工作树或当前分支。)

这意味着这git reset <paths>git add <paths>是相反的。

在运行git reset <paths>以更新索引条目之后,可以使用 git-checkout [1] 将索引中的内容检查到工作树。或者,使用 git-checkout [1] 并指定提交,您可以一次将提交中的路径内容复制到索引和工作树中。

git reset (--patch | -p) <tree-ish> <paths>…​

在索引和 <tree-ish> 之间的差异中交互选择 hunk(默认为 HEAD )。选定的区块与指数相反。

这意味着这git reset -pgit add -p是相反的,也就是说,你可以用它来选择性地重置人群。请参阅 git-add [1] 的“交互模式”部分了解如何操作该--patch模式。

git reset <mode>

此表单将当前分支头重置为 <commit> ,并可能更新索引(将其重置为 <commit> 的树),并根据 <mode> 更新工作树。如果省略 <mode> ,则默认为“--mixed”。<mode> 必须是以下之一:

--soft

根本不触摸索引文件或工作树(但将头重置为 <commit> ,就像所有模式一样)。这git status将使所有更改的文件“变更被提交”,就像它会这样。

--mixed

重置索引而不是工作树(即,保存更改的文件但未标记为提交)并报告尚未更新的内容。这是默认操作。

如果-N指定,则删除的路径将标记为 intent-to-add(请参阅 git-add [1] )。

--hard

重置索引和工作树。放弃自 <commit> 以来对工作树中跟踪文件的任何更改。

--merge

重置索引并更新工作树中 <commit> 和 HEAD 之间不同的文件,但保留索引和工作树之间不同的文件(即没有添加更改的文件)。如果 <commit> 和索引之间的文件有不同的变化,则重置会中止。

换句话说,--merge 可以做一些类似的事情git read-tree -u -m <commit>,但是会传递未合并的索引条目。

--keep

重置索引条目并更新工作树中 <commit> 和 HEAD 之间不同的文件。如果 <commit> 和 HEAD 之间的文件有本地更改,则重置会中止。

如果你想撤消一个分支以外的提交,git-revert [1] 是你的朋友。

选项

-q --quiet

只报告错误。

例子

撤消添加

$ edit                                     (1)
$ git add frotz.c filfre.c
$ mailx                                    (2)
$ git reset                                (3)
$ git pull git://info.example.com/ nitfol  (4)
  1. 您正在愉快地处理某些事情,并发现这些文件中的更改顺利进行。当你运行 “git diff” 时,你不想看到它们,因为你打算在其他文件上工作,而使用这些文件进行更改会让人分心。
  2. 有人让你去拉,而这些变化听起来值得合并。
  3. 但是,您已经弄脏了索引(即您的索引与 HEAD 提交不匹配)。但是你知道你要做的拉不会影响 frotz.c 或 filfre.c ,所以你可以恢复这两个文件的索引更改。工作树的变化仍然存在。
  4. 然后你可以拉和合并,在工作树中仍然保留 frotz.c 和 filfre.c 的变化。

撤消提交并重做

$ git commit ...
$ git reset --soft HEAD^      (1)
$ edit                        (2)
$ git commit -a -c ORIG_HEAD  (3)
  1. 当你记住你刚才提交的内容不完整,或者你拼错了你的提交信息,或者两者兼而有之时,通常会这样做。像在“重置”之前那样使树工作。
  2. 更正工作树文件。
  3. “reset”将旧头复制到 .git / ORIG_HEAD ; 从日志消息开始重做提交。如果您不需要进一步编辑该消息,则可以改为给 -C 选项。

另请参阅 git-commit [ - ] 的 --amend 选项。

撤消提交,使其成为主题分支

$ git branch topic/wip     (1)
$ git reset --hard HEAD~3  (2)
$ git checkout topic/wip   (3)
  1. 你已经做了一些提交,但意识到他们在 “master” 分支还为时尚早。您想要继续在主题分支中打磨它们,因此请从当前 HEAD 创建 “主题/ wip” 分支。
  2. 倒回主分支以摆脱这三个提交。
  3. 切换到 “topic / wip” 分支并继续工作。

撤消永久提交

$ git commit ...
$ git reset --hard HEAD~3   (1)
  1. 最后三个提交( HEAD ,HEAD ^ 和 HEAD〜2 )很差,你不想再看到它们。难道不是如果你已经给了这些提交给别人做。(有关这样做的含义,请参阅 git-rebase [1] 中的“从上游重新启动恢复”一节。)

撤消合并或拉

$ git pull                         (1)
Auto-merging nitfol
CONFLICT (content): Merge conflict in nitfol
Automatic merge failed; fix conflicts and then commit the result.
$ git reset --hard                 (2)
$ git pull . topic/branch          (3)
Updating from 41223... to 13134...
Fast-forward
$ git reset --hard ORIG_HEAD       (4)
  1. 尝试从上游更新导致很多冲突; 你现在还没有准备好花很多时间合并,所以你稍后决定这么做。
  2. “pull” 没有进行合并提交,因此 “git reset --hard” 是 “git reset --hard HEAD” 的同义词,从索引文件和工作树中清除混乱。
  3. 将主题分支合并到当前分支中,从而实现快速转发。
  4. 但是你决定主题分支尚未准备好供公众使用。“拉”或“合并”总是将当前分支的原始尖端留在 ORIG_HEAD 中,因此难以重置会使索引文件和工作树返回到该状态,并将分支的尖端重置为该提交。

撤消一个合并或拉一个不完美的工作树内

$ git pull                         (1)
Auto-merging nitfol
Merge made by recursive.
 nitfol                |   20 +++++----
 ...
$ git reset --merge ORIG_HEAD      (2)
  1. 即使你可能在你的工作树上进行了局部修改,当你知道另一个分支中的变化与它们没有重叠时,你也可以安全地说出 “git pull” 。
  2. 在检查合并的结果后,您可能会发现其他分支的变化不令人满意。运行 “git reset --hard ORIG_HEAD” 可以让你回到你所在的位置,但它会放弃你不想要的本地修改。“git reset --merge” 保留你的本地修改。

中断的工作流程

假设当你处于一个大的变化中时,你被紧急修复请求中断。工作树中的文件没有任何形状可供提交,但需要到另一个分支进行快速修补。

$ git checkout feature ;# you were working in "feature" branch and
$ work work work       ;# got interrupted
$ git commit -a -m "snapshot WIP"                 (1)
$ git checkout master
$ fix fix fix
$ git commit ;# commit with real log
$ git checkout feature
$ git reset --soft HEAD^ ;# go back to WIP state  (2)
$ git reset                                       (3)
  1. 这个提交会被吹走,所以丢弃的日志消息是 OK 的。
  2. 这将删除WIP提交历史记录中的提交,并将您的工作树设置为您创建该快照之前的状态。
  3. 此时,索引文件仍具有您所承诺的所有 WIP 更改snapshot WIP。这会更新索引以将您的 WIP 文件显示为未提交。

另见 git-stash [1] 。

重置索引中的单个文件

假设你已经添加了一个文件到你的索引,但稍后决定你不想将它添加到你的提交。您可以从索引中删除文件,同时使用 git reset 保留更改。

$ git reset -- frotz.c                      (1)
$ git commit -m "Commit files in index"     (2)
$ git add frotz.c                           (3)
  1. 这将文件从索引中删除,同时保留在工作目录中。
  2. 这会提交索引中的所有其他更改。
  3. 再次将文件添加到索引。

在改变工作树的同时放弃一些以前的提交

假设你正在处理一些事情,然后你继续工作,然后你继续工作多一点,但是现在你认为你工作树中的内容应该在另一个分支中,这与你以前承诺的事情没有任何关系。您可以启动一个新分支并重置它,同时将更改保留在工作树中。

$ git tag start
$ git checkout -b branch1
$ edit
$ git commit ...                            (1)
$ edit
$ git checkout -b branch2                   (2)
$ git reset --keep start                    (3)
  1. 这会在 branch1 中提交您的第一批编辑。
  2. 在理想的世界中,当你创建并切换到 branch2 时(例如 “git checkout -b branch2 start” ),你可能意识到早期的提交不属于新的主题,但没有人是完美的。
  3. 但是在切换到 “branch2” 之后,您可以使用 “reset --keep” 删除不需要的提交。

将提交拆分为一系列提交

假设您已经创建了大量逻辑上单独的更改并将它们一起提交。然后,稍后您决定将每个逻辑块与其自己的提交关联起来可能会更好。您可以使用 git reset 在不改变本地文件内容的情况下回退历史记录,然后使用预先填充提交消息git add -p来交互式地选择要包含到每个提交中的哪些区块git commit -c

$ git reset -N HEAD^                        (1)
$ git add -p                                (2)
$ git diff --cached                         (3)
$ git commit -c HEAD@{1}                    (4)
...                                         (5)
$ git add ...                               (6)
$ git diff --cached                         (7)
$ git commit ...                            (8)
  1. 首先,将历史记录重置为一次提交,以便删除原始提交,但保留所有更改的工作树。-N 确保任何添加了 HEAD 的新文件仍被标记,以便 git add -p 可以找到它们。
  2. 接下来,我们使用 git add -p 工具交互地选择 diff hunk 添加。这将问你关于每个差异大小顺序,你可以使用简单的命令,如“是的,包括这个”,“不包括这个”,甚至是非常强大的“编辑”设施。
  3. 一旦满足你想要包含的区块,你应该通过使用 git diff --cached 来验证为第一次提交准备了什么。这显示了所有已移入索引并即将提交的更改。
  4. 接下来,提交存储在索引中的更改。-c 选项指定从第一次提交中启动的原始消息中预填充提交消息。这有助于避免重新输入。HEAD @ {1} 是 HEAD 用于在原始重置提交之前进行提交的一种特殊符号(1次更改前)。有关更多详细信息,请参阅 git-reflog [1]。您也可以使用任何其他有效的提交引用。
  5. 您可以多次重复步骤2-4以将原始代码分解为任意次数的提交。
  6. 现在,您已将许多更改拆分为自己的提交,并可能不再使用 git add 的修补模式,以便选择所有未提交的更改。
  7. 再次检查以确认您已包含您想要的内容。您可能还希望验证一下,git diff 不会显示任何剩余的更改以后再提交。
  8. 最后创建最终提交。

讨论

下表显示了运行时发生的情况:

git reset --option target

target根据文件的状态使用不同的重置选项将 HEAD 重置为另一个提交()。

在这些表中,A ,B ,C 和 D 是文件的一些不同状态。例如,第一个表的第一行意味着如果文件处于工作树状态A ,索引状态 B ,HEAD 状态 C 和目标状态 D ,则 “git reset - 软目标“ 将使文件在状态A的工作树中和状态B的索引中。它将 HEAD(即,当前分支的顶端,如果你在一个上)重置(即移动)到 ”目标“(其中状态为 D 的文件)。

  working index HEAD target         working index HEAD
  ----------------------------------------------------
   A       B     C    D     --soft   A       B     D
--mixed  A       D     D
--hard   D       D     D
--merge (disallowed)
--keep  (disallowed)
  working index HEAD target         working index HEAD
  ----------------------------------------------------
   A       B     C    C     --soft   A       B     C
--mixed  A       C     C
--hard   C       C     C
--merge (disallowed)
--keep   A       C     C
  working index HEAD target         working index HEAD
  ----------------------------------------------------
   B       B     C    D     --soft   B       B     D
--mixed  B       D     D
--hard   D       D     D
--merge  D       D     D
--keep  (disallowed)
  working index HEAD target         working index HEAD
  ----------------------------------------------------
   B       B     C    C     --soft   B       B     C
--mixed  B       C     C
--hard   C       C     C
--merge  C       C     C
--keep   B       C     C
  working index HEAD target         working index HEAD
  ----------------------------------------------------
   B       C     C    D     --soft   B       C     D
--mixed  B       D     D
--hard   D       D     D
--merge (disallowed)
--keep  (disallowed)
  working index HEAD target         working index HEAD
  ----------------------------------------------------
   B       C     C    C     --soft   B       C     C
--mixed  B       C     C
--hard   C       C     C
--merge  B       C     C
--keep   B       C     C

“复位 - 合并”意味着在重置冲突合并时使用。任何合并操作都可以保证合并中涉及的工作树文件在启动之前不会对索引进行本地更改,并且可以将结果写入工作树。所以如果我们看到索引和目标之间以及索引和工作树之间存在某种差异,那么这意味着我们不会从一个在发生冲突后失败的状态中重置。这就是为什么我们在这种情况下不允许 - 合并选项。

在保留对工作树的修改的同时,删除当前分支中的某些最后提交时,将使用 “reset --keep” 。如果我们要删除的提交更改与我们想要保留的工作树更改之间可能存在冲突,则不允许重置。这就是为什么如果工作树和 HEAD 之间以及 HEAD 和目标之间都存在变化,则不允许它。为了安全起见,当没有合并的条目时它也被禁止。

下表显示了在没有合并条目时发生的情况:

  working index HEAD target         working index HEAD
  ----------------------------------------------------
   X       U     A    B     --soft  (disallowed)
--mixed  X       B     B
--hard   B       B     B
--merge  B       B     B
--keep  (disallowed)
  working index HEAD target         working index HEAD
  ----------------------------------------------------
   X       U     A    A     --soft  (disallowed)
--mixed  X       A     A
--hard   A       A     A
--merge  A       A     A
--keep  (disallowed)

X 表示任何状态,U 表示未合并的索引。