Setup and Config
Getting and Creating Projects
Basic Snapshotting
Branching and Merging
Sharing and Updating Projects
Inspection and Comparison
Patching
Debugging
External Systems
Server Admin
Guides
- gitattributes
- Command-line interface conventions
- Everyday Git
- Frequently Asked Questions (FAQ)
- Glossary
- Hooks
- gitignore
- gitmodules
- Revisions
- Submodules
- Tutorial
- Workflows
- All guides...
Administration
Plumbing Commands
-
2.54.0
2026-04-20
-
2.53.0
2026-02-02
-
2.52.0
2025-11-17
- 2.51.1 → 2.51.2 no changes
-
2.51.0
2025-08-18
- 2.50.1 no changes
-
2.50.0
2025-06-16
- 2.39.4 → 2.49.1 no changes
-
2.39.3
2023-04-17
- 2.36.1 → 2.39.2 no changes
-
2.36.0
2022-04-18
- 2.34.1 → 2.35.8 no changes
-
2.34.0
2021-11-15
- 2.27.1 → 2.33.8 no changes
-
2.27.0
2020-06-01
- 2.25.1 → 2.26.3 no changes
-
2.25.0
2020-01-13
- 2.23.1 → 2.24.4 no changes
-
2.23.0
2019-08-16
- 2.22.1 → 2.22.5 no changes
-
2.22.0
2019-06-07
- 2.21.1 → 2.21.4 no changes
-
2.21.0
2019-02-24
- 2.20.1 → 2.20.5 no changes
-
2.20.0
2018-12-09
- 2.15.4 → 2.19.6 no changes
-
2.14.6
2019-12-06
-
2.13.7
2018-05-22
-
2.12.5
2017-09-22
- 2.1.4 → 2.11.4 no changes
-
2.0.5
2014-12-17
概述
gitreset'[-q] [<目录树对象>] [--] <路径规范>…gitreset'[-q] [--pathspec-from-file=<文件> [--pathspec-file-nul]] [<目录树对象>]gitreset'(--patch|-p) [<目录树对象>] [--] [<路径规范>…]gitreset'[--soft|--mixed[-N] |--hard|--merge|--keep] [-q] [<提交>]
描述
从这一点来看,以下任一命令的结果都是如此:
-
gitreset[<mode>] <commit> 改变HEAD所指向的提交。这使得撤销各种 Git 操作成为可能,例如提交、合并、变基和拉取。 -
当你指定文件或目录或传递
--patch时,gitreset会更新指定文件的暂存版本。- git reset [<模式>] [<提交>]
-
将当前分支头(
HEAD)设置为指向 <commit>。根据 <mode> 的不同,还会更新工作目录和/或索引以匹配 <commit> 的内容。<commit> 默认为HEAD。在操作之前,ORIG_HEAD被设置为当前分支的末端。模板目录将是以下之一(按顺序):
-
--mixed -
保持工作目录不变。更新索引以匹配新的
HEAD,因此不会有任何暂存内容。如果指定了
-N,则删除的路径将被标记为要添加(请参阅 git-add[1])。 -
--soft -
保持工作树文件和索引不变。例如,如果没有暂存的更改,可以使用 git reset --soft HEAD~5; git commit 将最近 5 次提交合并为 1 次提交。即使工作树中有更改也能正常工作,这些更改不会被触动,但这样的用法可能会导致混淆。
-
--hard -
用 <commit> 中的版本覆盖所有文件和目录,可能会覆盖未跟踪的文件。不在 <commit> 中的已跟踪文件会被删除,以使工作树匹配 <commit>。更新索引以匹配新的
HEAD,因此不会有任何暂存内容。 -
--merge -
重置索引并更新工作区中与 <提交> 和
HEAD之间不同的文件,但保留那些在索引和工作区之间不同的文件(即尚未被添加的修改)。如果 <提交> 和索引之间不同的文件有未暂存的更改,重置操作将被中止。 -
--keep -
重置索引条目并更新工作区中与 <提交> 和
HEAD之间不同的文件。 如果 <提交> 和HEAD之间不同的文件有本地修改,重置操作将被中止。 -
--recurse-submodules -
--no-recurse-submodules -
当更新工作区时,使用 --recurse-submodules 还将递归性地根据超级项目中记录的提交来重置所有活动子模块的工作区,同时将子模块的 HEAD 设置为分离在该提交处。
-
- git reset [-q] [<目录树对象>] [--] <路径规范>…
- git reset [-q] [--pathspec-from-file=<文件> [--pathspec-file-nul]] [<目录树对象>]
-
对于所有指定的文件或目录,将暂存版本设置为来自给定提交或树(默认为
HEAD)的版本。这意味着,
gitreset<pathspec> 与gitadd<pathspec> 相反。该命令等同于gitrestore[--source=<treeish>]--staged<pathspec>... 。在此模式下,
gitreset只更新索引(不更新HEAD或工作树文件)。如果你想同时更新文件和索引条目,请使用 git-restore[1]。 - git reset (--patch | -p) [<目录树对象>] [--] [<路径规范>…]
-
交互式选择索引和 <目录树对象> (默认为
HEAD)之间差异的代码块。选择的代码块将逆序应用于索引。这意味着
gitreset-p与gitadd-p相反,即您可以用它来有选择地重置代码块。参见 git-add[1] 的 "交互模式"部分,了解如何操作--patch模式。
关于这三个命令的区别,见git[1]中的 "重置、恢复和还原"。
选项
-
-q -
--quiet -
静默模式,只报告错误。
-
--refresh -
--no-refresh -
在混合重置后刷新索引,默认启用。
-
--pathspec-from-file=<file> -
Pathspec 在 <文件> 中传递,而不是在命令行参数中传递。如果 <文件> 正好是
-,则使用标准输入。路径规范元素由 LF 或 CR/LF 分隔。可以引用配置变量core.quotePath的路径规范元素(请参见 git-config[1])。另请参见--pathspec-file-nul和全局--literal-pathspecs。 -
--pathspec-file-nul -
只有在使用
--pathspec-from-file选项时才有意义。指定路径元素用 NUL 字符分隔,所有其他字符都按字面意思(包括换行符和引号)表示。 -
-U<n> -
--unified=<n> -
生成带有 <n> 行上下文的差异。上下文行数默认为
diff.context或 3(如果未设置配置变量)。(由于历史原因,不带 <n> 的-U被默认接受为-p的同义词)。 -
--inter-hunk-context=<n> -
显示块差异之间的上下文,最多显示指定的 <number> 行,从而合并彼此接近的块。 默认认为
diff.interHunkContext,如果配置选项未设置,则默认为0。
-
-- -
不将之后的参数解释为选项。
- <路径规范>...
-
限制受操作影响的路径。
更多细节请参见 gitglossary[7] 中的 路径规范 条目。
实例
- 撤销添加
-
$ edit (1) $ git add frotz.c filfre.c $ mailx (2) $ git reset (3) $ git pull git://info.example.com/ nitfol (4)
-
你正在愉快地工作,发现这些文件中的修改都很有秩序。 你不希望在运行
gitdiff时看到它们,因为你打算在其他文件上工作,而这些文件的变化会让你分心。 -
有人要求你 pull,而且这些变化听起来值得合并。
-
然而,你已经破坏了索引(也就是说,你的索引与
HEAD提交不匹配)。但你知道你要做的 pull 并不影响frotz.c或filfre.c,所以你恢复了这两个文件的索引修改。 你在工作区上的修改仍然存在。 -
然后你可以拉出并合并,留下
frotz.c和filfre.c的修改仍在工作区上。
-
- 撤销一个提交并重做
-
$ git commit ... $ git reset --soft HEAD^ (1) $ edit (2) $ git commit -a -c ORIG_HEAD (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)
-
你已经做了一些提交,但意识到它们在 "master " 分支中还不成熟。 你想在一个主题分支中继续完善它们,所以在当前的
HEAD之外创建了topic/wip分支。 -
回溯主分支,去掉这三个提交。
-
切换到
topic/wip分支并继续工作。
-
- 永久撤销提交
-
$ git commit ... $ git reset --hard HEAD~3 (1)
-
最后三个提交(
HEAD,HEAD^,和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)
-
试图从上游更新导致了很多冲突;你现在还没有准备好花费大量的时间来合并,所以你决定以后再做这个。
-
"pull " 没有进行合并提交,所以
gitreset--hard是gitreset--hardHEAD的同义词,可以清除索引文件和工作区上的混乱。 -
将一个主题分支合并到当前分支,这导致了快进。
-
但你决定这个主题分支还不适合公开使用。"pull " 或 "merge" 总是将当前分支的原始尖端保留在
ORIG_HEAD,所以硬重置到它会使你的索引文件和工作区回到那个状态,并将分支尖端重置到那个提交。
-
- 撤消合并或拉动肮脏的工作区的行为
-
$ git pull (1) Auto-merging nitfol Merge made by recursive. nitfol | 20 +++++---- ... $ git reset --merge ORIG_HEAD (2)
-
即使你的工作区中可能有局部的修改,当你知道另一个分支中的修改没有与之重叠时,你可以放心地
gitpull。 -
在检查了合并的结果后,你可能会发现另一个分支的修改不尽人意。 运行
gitreset--hardORIG_HEAD可以让你回到原来的位置,但它会丢弃你的本地修改,这是你不想要的。gitreset--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)
-
这个提交将会被丢弃,所以可以使用一个临时的提交信息。
-
这将从提交历史中删除 "WIP" 提交,并将你的工作区设置为刚刚做出快照之前的状态。
-
此时,索引文件仍然包含您提交为 "快照 WIP" 的所有工作进度更改。这会更新索引来显示您的工作进度文件为未提交状态。
也请参见 git-stash[1]。
-
- 重置索引中的单个文件
-
假设你在索引中添加了一个文件,但后来决定不想把它加入你的提交中。你可以用
gitreset将该文件从索引中删除,同时保留你的修改。$ git reset -- frotz.c <1>. $ git commit -m "将文件存入索引" (2) $ git add frotz.c (3)
-
这将从索引中删除该文件,同时将其保留在工作区中。
-
这将提交索引中的所有其他变化。
-
再次将该文件添加到索引中。
-
- 在工作区中保留修改,同时丢弃一些以前的提交内容
-
假设你正在处理一些事情,并提交了它,然后你又继续做了一会儿,但现在你认为你在工作区中的内容应该位于另一个与您之前提交的内容无关的分支中。你可以启动一个新的分支并在保留工作区中更改的情况下重置它。
$ git tag start $ git switch -c branch1 $ 编辑 $ git commit ... (1) $ 编辑 $ git switch -c branch2 (2) $ git reset --keep start (3)
-
这将提交你在
branch1中的第一次编辑。 -
在理想的世界里,你可以在创建并切换到 "branch2"(即 "git switch -c branch2 start")时意识到先前的提交不属于新主题,但人无完人。
-
但你可以用
reset--keep来删除你切换到branch2后不需要的提交。
-
- 将一个提交分割成一连串的提交
-
假设你创建了很多逻辑上独立的修改,并将它们一起提交。然后,后来你决定让每个逻辑块与自己的提交相关联可能更好。你可以使用 git reset 来回溯历史,而不改变本地文件的内容,然后连续使用
gitadd-p来交互式地选择哪些块包含在每个提交中,使用gitcommit-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)-
首先,将历史记录重置回前一个提交以删除原始提交,但保留了工作区上的所有修改。使用 -N 确保任何使用
HEAD添加的新文件仍然被标记,以便gitadd-p能够找到它们。 -
接下来,我们使用
gitadd-p工具,交互式地选择要添加的差异块。这将逐个询问每个差异块,你可以使用简单的命令,如 "是,包括这个" , "不,不包括这个" ,甚至是非常强大的 "编辑 " 工具。 -
一旦对你想要包括的块感到满意,你应该使用
gitdiff--cached来验证为第一次提交准备的内容。这将显示所有已经移入索引并即将提交的更改。 -
接下来,提交存储在索引中的修改。
-c选项指定从你第一次提交时的原始信息中预先填入提交信息。这对避免重复输入很有帮助。HEAD@{1}是一个特殊的符号,表示HEAD在最初的重置提交(1次变更前)之前处于的提交。 更多细节见 git-reflog[1]。你也可以使用任何其他有效的提交引用。 -
你可以多次重复第 2-4 步,将原始代码分解成任意数量的提交。
-
现在你已经把许多更改拆成了自己的提交,可能不再使用
gitadd的补丁模式,以便选择所有剩余的未提交的修改。 -
再一次检查以确认你已经包含了你想要的东西。你可能还想确认 git diff 没有显示任何剩余的修改,以便以后提交。
-
最后创建最后的提交。
-
讨论
下面的表格显示了运行时发生的情况:
git reset --option 目标
来重置 HEAD 到另一个提交( target ),根据文件的状态,有不同的重置选项。
在这些表中, A 、 B 、C 和 D 是一个文件的一些不同状态。例如,第一个表格的第一行意味着如果一个文件在工作区中处于 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 (不允许)
工作区 索引 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 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
reset --merge 旨在在从已冲突的合并中重置时使用。任何合并操作都保证在开始之前,参与合并的工作区文件相对于索引没有本地更改,并且会将结果写入工作区。所以如果我们看到索引和目标之间以及索引和工作区之间有一些差异,那就意味着我们不是在从一个合并操作因冲突失败后留下的状态中重置。这就是为什么我们在这种情况下不允许使用 --merge 选项。
reset --keep 旨在移除当前分支中的一些最后的提交时保留工作区中的修改。如果想要移除的提交中的更改与想要保留的工作区中的更改之间存在冲突,则不允许重置。这就是为什么如果工作区和 HEAD 之间,以及 HEAD 和目标之间都有更改时不允许重置。为了安全起见,当有未合并的条目时,也不允许这样做。
下表显示了有未合并的条目时发生的情况:
工作区 索引 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] 文档