简体中文 ▾ Topics ▾ Latest version ▾ git-reset last updated in 2.50.0

名称

git-reset - 重置当前HEAD到指定的状态

概述

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

描述

In the first three forms, copy entries from <tree-ish> to the index. In the last form, set the current branch head (HEAD) to <commit>, optionally modifying index and working tree to match. The <tree-ish>/<commit> defaults to HEAD in all forms.

git reset [-q] [<tree-ish>] [--] <pathspec>...
git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]

These forms reset the index entries for all paths that match the <pathspec> to their state at <tree-ish>. (It does not affect the working tree or the current branch.)

这意味着, git reset <pathspec>git add <pathspec> 相反。该命令等同于 git restore [--source=<treeish>] --staged <pathspec>...

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

git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]

Interactively select hunks in the difference between the index and <tree-ish> (defaults to HEAD). The chosen hunks are applied in reverse to the index.

This means that git reset -p is the opposite of git add -p, i.e. you can use it to selectively reset hunks. See the "Interactive Mode" section of git-add[1] to learn how to operate the --patch mode.

git reset [<mode>] [<commit>]

This form resets the current branch head to <commit> and possibly updates the index (resetting it to the tree of <commit>) and the working tree depending on <mode>. Before the operation, ORIG_HEAD is set to the tip of the current branch. If <mode> is omitted, defaults to --mixed. The <mode> must be one of the following:

--soft

Does not touch the index file or the working tree at all (but resets the head to <commit>, just like all modes do). This leaves all your changed files "Changes to be committed", as git status would put it.

--mixed

重置索引,但不重置工作树(即保留已修改的文件,但不标记为提交)并报告哪些内容未更新。这是默认动作。

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

--hard

Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded. Any untracked files or directories in the way of writing any tracked files are simply deleted.

--merge

Resets the index and updates the files in the working tree that are different between <commit> and HEAD, but keeps those which are different between the index and working tree (i.e. which have changes which have not been added). If a file that is different between <commit> and the index has unstaged changes, reset is aborted.

换句话说, --merge 做的事情类似于 git read-tree -u -m <提交> ,但会保留尚未合并的索引条目。

--keep

Resets index entries and updates files in the working tree that are different between <commit> and HEAD. If a file that is different between <commit> and HEAD has local changes, reset is aborted.

--[no-]recurse-submodules

When the working tree is updated, using --recurse-submodules will also recursively reset the working tree of all active submodules according to the commit recorded in the superproject, also setting the submodules' HEAD to be detached at that commit.

关于这三个命令的区别,见git[1]中的 "重置、恢复和还原"。

选项

-q
--quiet

静默模式,只报告错误。

--refresh
--no-refresh

在混合重置后刷新索引,默认启用。

--pathspec-from-file=<file>

Pathspec is passed in <file> instead of commandline args. If <file> is exactly - then standard input is used. Pathspec elements are separated by LF or CR/LF. Pathspec elements can be quoted as explained for the configuration variable core.quotePath (see git-config[1]). See also --pathspec-file-nul and global --literal-pathspecs.

--pathspec-file-nul

只有在使用 --pathspec-from-file 选项时才有意义。指定路径元素用 NUL 字符分隔,所有其他字符都按字面意思(包括换行符和引号)表示。

--

不将之后的参数解释为选项。

<路径规范>...

限制受操作影响的路径。

更多细节请参见 gitglossary[7] 中的 路径规范 条目。

实例

撤销添加
$ 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. 有人要求你 pull,而且这些变化听起来值得合并。

  3. 然而,你已经破坏了索引(也就是说,你的索引与 HEAD 提交不匹配)。但你知道你要做的 pull 并不影响 frotz.cfilfre.c ,所以你恢复了这两个文件的索引修改。 你在工作树上的修改仍然存在。

  4. 然后你可以拉出并合并,留下 frotz.cfilfre.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[1]--amend 选项。

撤销一个提交,使其成为一个主题分支
$ git branch topic/wip          (1)
$ git reset --hard HEAD~3       (2)
$ git switch topic/wip          (3)
  1. 你已经做了一些提交,但意识到它们在 "master " 分支中还不成熟。 你想在一个主题分支中继续完善它们,所以在当前的 HEAD 之外创建了 topic/wip 分支。

  2. 回溯主分支,去掉这三个提交。

  3. 切换到 topic/wip 分支并继续工作。

永久撤销提交
$ git commit ...
$ git reset --hard HEAD~3 (1)
  1. 最后三个提交(HEADHEAD^,和 HEAD~2 )是坏的,你不希望再看到它们。 如果你已经把这些提交给了别人,请 不要 这样做。 参见 git-rebase[1] 中的 “从上游仓库重建中恢复” 一节,了解这样做的意义。)

撤销合并或拉动
$ git pull                         (1)
自动合并nitfol
CONFLICT(内容):nitfol的合并冲突
自动合并失败;修复冲突,然后提交结果。
$ git reset --hard                 (2)
$ git pull . topic/branch          (3)
从41223...更新到13134...
快进
$ git reset --hard ORIG_HEAD       (4)
  1. 试图从上游更新导致了很多冲突;你现在还没有准备好花费大量的时间来合并,所以你决定以后再做这个。

  2. "pull " 没有进行合并提交,所以 git reset --hardgit reset --hard HEAD 的同义词,可以清除索引文件和工作树上的混乱。

  3. 将一个主题分支合并到当前分支,这导致了快进。

  4. 但你决定这个主题分支还不适合公开使用。"pull " 或 "merge" 总是将当前分支的原始尖端保留在 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 switch feature ;# 你在 "feature "分支工作,并且
$ work work work;# 被打断了
$ git commit -a -m "snapshot WIP"               (1)
$ git switch master
$ fix fix fix
$ git commit ;# 提交时有真实日志
$ git switch feature
$ git reset --soft HEAD^ ;# 回到 WIP 状态         (2)
$ git reset                                       (3)
  1. 这个提交将会被丢弃,所以可以使用一个临时的提交信息。

  2. 这将从提交历史中删除 "WIP" 提交,并将你的工作树设置为刚刚做出快照之前的状态。

  3. 此时,索引文件仍然包含您提交为 "快照 WIP" 的所有工作进度更改。这会更新索引来显示您的工作进度文件为未提交状态。

    也请参见 git-stash[1]

重置索引中的单个文件

假设你在索引中添加了一个文件,但后来决定不想把它加入你的提交中。你可以用 git reset 将该文件从索引中删除,同时保留你的修改。

$ git reset -- frotz.c <1>.
$ git commit -m "将文件存入索引" (2)
$ git add frotz.c (3)
  1. 这将从索引中删除该文件,同时将其保留在工作目录中。

  2. 这将提交索引中的所有其他变化。

  3. 再次将该文件添加到索引中。

在工作树中保留修改,同时丢弃一些以前的提交内容

假设你正在处理一些事情,并提交了它,然后你又继续做了一会儿,但现在你认为你在工作树中的内容应该位于另一个与您之前提交的内容无关的分支中。你可以启动一个新的分支并在保留工作树中更改的情况下重置它。

$ git tag start
$ git switch -c branch1
$ 编辑
$ git commit ...                            (1)
$ 编辑
$ git switch -c branch2                     (2)
$ git reset --keep start                    (3)
  1. 这将提交你在 branch1 中的第一次编辑。

  2. 在理想的世界里,你可以在创建并切换到 "branch2"(即 "git switch -c branch2 start")时意识到先前的提交不属于新主题,但人无完人。

  3. 但你可以用 reset --keep 来删除你切换到 branch2 后不需要的提交。

将一个提交分割成一连串的提交

假设你创建了很多逻辑上独立的修改,并将它们一起提交。然后,后来你决定让每个逻辑块与自己的提交相关联可能更好。你可以使用 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. First, reset the history back one commit so that we remove the original commit, but leave the working tree with all the changes. The -N ensures that any new files added with HEAD are still marked so that git add -p will find them.

  2. 接下来,我们使用 git add -p 工具,交互式地选择要添加的差异块。这将逐个询问每个差异块,你可以使用简单的命令,如 "是,包括这个" , "不,不包括这个" ,甚至是非常强大的 "编辑 " 工具。

  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 目标

来重置 HEAD 到另一个提交( target ),根据文件的状态,有不同的重置选项。

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

工作树  索引  HEAD  目标                 工作树   索引   HEAD
------------------------------------------------------------
  A      B     C     D    --soft           A       B      D
			  --mixed          A       D      D
			  --hard           D       D      D
			  --merge (不允许)
			  --keep (不允许)
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
工作树  索引  HEAD  目标                 工作树   索引   HEAD
------------------------------------------------------------
  B      B     C     D     --soft          B       B      D
			  --mixed         B       D      D
			  --hard          D       D      D
			  --merge         D       D      D
			  --keep(不允许)
工作树  索引  HEAD  目标                 工作树   索引   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
工作树  索引  HEAD  目标                 工作树   索引   HEAD
------------------------------------------------------------
  B      C     C     D     --soft          B       C      D
			  --mixed         B       D      D
			  --hard(硬的)    D       D      D
			  --merge (不允许)
			  --keep (不允许)
工作树  索引  HEAD  目标                 工作树   索引   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

git reset --merge is meant to be used when resetting out of a conflicted merge. Any mergy operation guarantees that the working tree file that is involved in the merge does not have a local change with respect to the index before it starts, and that it writes the result out to the working tree. So if we see some difference between the index and the target and also between the index and the working tree, then it means that we are not resetting out from a state that a mergy operation left after failing with a conflict. That is why we disallow --merge option in this case.

git reset --keep is meant to be used when removing some of the last commits in the current branch while keeping changes in the working tree. If there could be conflicts between the changes in the commit we want to remove and the changes in the working tree we want to keep, the reset is disallowed. That’s why it is disallowed if there are both changes between the working tree and HEAD, and between HEAD and the target. To be safe, it is also disallowed when there are unmerged entries.

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

工作树  索引  HEAD  目标                 工作树   索引   HEAD
------------------------------------------------------------
  X      U      A     B    --soft(不允许)
			  --mixed         X       B      B
			  --hard          B       B      B
			  --merge         B       B      B
			  --keep (不允许)
工作树  索引  HEAD  目标                 工作树   索引   HEAD
------------------------------------------------------------
   X     U     A     A     --soft (不允许)
			  --mixed         X       A      A
			  --hard          A       A      A
			  --merge         A       A      A
			  --keep (不允许)

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

GIT

属于 git[1] 文档

scroll-to-top