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>]
描述
在前三种形式中,从<treeish>复制条目到索引。 在最后一个表格中,将当前的分支头(
HEAD)设置为<commit>,可以选择修改索引和工作树来匹配。
<tree-ish>/<commit>在所有表格中默认为
HEAD。
git reset [-q] [<tree-ish>] [--] <pathspec>… git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
这些表格将所有符合<pathspec>的路径的索引项重置为<treeish>
时的状态。 (它不影响工作树或当前分支)。
这意味着,git reset <pathspec>与
git add <pathspec>相反。该命令等同于
git restore [–source=<treeish>] –staged <pathspec>…。
运行 git reset <pathspec> 来更新索引条目后,您可以使用 git-restore 来检查索引中的内容到工作树上。另外,使用 git-restore 并用 –source 指定一个提交,你可以一次性将一个路径的内容从提交中复制到索引和工作树上。
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>…]
在索引和<tree-ish>(默认为
HEAD)之间的差异中交互式地选择猎物。 选择的猎物将被反向应用到索引中。
这意味着 git reset -p 与 git add -p 相反,也就是说,你可以用它来有选择地重置 hunks。
git reset [<mode>] [<commit>] 此命令将当前分支头重置为< commit > ,并根据< mode >可能更新索引(将其重置为< commit >的树)和工作树。在操作之前, ORIG_HEAD被设置为当前分支的末端。如果省略< mode > ,则默认为–mixed 。 < mode >必须是以下之一:
–soft
完全不碰索引文件或工作树(但将头部重置为
<commit>
,就像所有模式一样)。这使你的所有更改的文件都是 “待提交的更改”,正如git status
所说的。–mixed
重置索引,但不重置工作树(即保留已修改的文件,但不标记为提交)并报告未更新的内容。这是默认动作。
如果指定了-N ,则删除的路径将被标记为intent-to-add (参见git-add ) 。
–hard
重置索引和工作树。自< commit >以来对工作树中跟踪的文件所做的任何更改都将被丢弃。在写入任何跟踪文件时,将简单地删除路径中的任何未跟踪文件或目录。
–merge
重置索引并更新工作树中在
<commit>和
HEAD之间不同的文件,但保留那些在索引和工作树之间不同的文件(即那些有未被添加的修改)。 如果一个在<commit>
和索引之间不同的文件有未分阶段的变化,重置将被中止。换句话说,
--merge
做的是类似于git read-tree -u -m <commit>
的事情,但会转发未合并的索引条目。–keep
重置索引项并更新工作树中
<commit>和
HEAD之间不同的文件。 如果一个在<commit>
和HEAD
之间不同的文件有本地修改,重置将被中止。–[no-]recurse-submodules
当工作树被更新时,使用 –recurse-submodules 也将根据超级项目中记录的提交,递归地重置所有活动的子模块的工作树,同时也将子模块的 HEAD 设置为在该提交中被分离。
选项
-q
–quiet
安静,只报告错误。
–refresh
–no-refresh
在混合重置后刷新索引,默认启用。
–pathspec-from-file=<file>
Pathspec在 <file> 中传递,而不是在命令行参数中传递。如果 <file> 正好是 -,则使用标准输入。Pathspec 元素由 LF 或 CR/LF 分隔。可以引用配置变量 core.quotePath 的 Pathspec 元素(请参见 git-config)。另请参见 –pathspec-file-nul 和全局
–literal-pathspecs。
–pathspec-file-nul
仅在与–pathspec-from-file一起使用时有意义。路径规范元素由NUL字符分隔,所有其他字符均按字面意义解释(包括换行符和引号) 。
–
不将之后的参数解释为选项。
<pathspec>…
限制受操作影响的路径。
实例
撤销添加
$ edit (1) $ git add frotz.c filfre.c $ mailx (2) $ git reset (3) $ git pull git://info.example.com/ nitfol (4)
你正在愉快地工作,发现这些文件中的修改都很有秩序。 你不希望在运行`git diff’时看到它们,因为你打算在其他文件上工作,而这些文件的变化会让你分心。
有人要求你拉,而且这些变化听起来值得合并。
然而,你已经破坏了索引(也就是说,你的索引与HEAD
提交不匹配)。 但你知道你要做的拉动并不影响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 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 pull (1) 自动合并nitfol CONFLICT(内容)。nitfol的合并冲突 自动合并失败;修复冲突,然后提交结果。 $ git reset --hard (2) $ git pull . topic/branch (3) 从41223...更新到13134... 快进 $ git reset --hard ORIG_HEAD (4)
试图从上游更新导致了很多冲突;你现在还没有准备好花费大量的时间来合并,所以你决定以后再做这个。
“pull”没有进行合并提交,所以git reset --hard
是git reset --hard HEAD
的同义词,它清除了索引文件和工作树上的混乱。
将一个主题分支合并到当前分支,这导致了快进。
但你决定这个主题分支还不适合公开使用。 “pull”或 “merge”总是在ORIG_HEAD
中留下当前分支的原始提示,所以硬重置到它会使你的索引文件和工作树回到那个状态,并将分支的提示重置到那个提交。
撤消合并或拉动肮脏的工作树的行为
$ git pull (1) Auto-merging nitfol Merge made by recursive. nitfol | 20 +++++---- ... $ git reset --merge ORIG_HEAD (2)
即使你的工作树中可能有局部的修改,当你知道另一个分支中的修改没有与之重叠时,你可以放心地说git pull
。
在检查了合并的结果后,你可能会发现另一个分支的修改不尽人意。 运行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)
这个提交会被吹走,所以扔掉的日志信息是可以的。
这将从提交历史中删除 “WIP”提交,并将你的工作树设置为刚刚做出快照之前的状态。
在这一点上,索引文件仍然有你提交的所有WIP修改,作为 “快照WIP”。 这样就可以更新索引,将你的WIP文件显示为未提交的。
重置索引中的单个文件
假设你在索引中添加了一个文件,但后来决定不想把它加入你的提交中。你可以用git reset将该文件从索引中删除,同时保留你的修改。
$ git reset -- frotz.c <1>. $ git commit -m "将文件存入索引" (2) $ git add frotz.c (3)
这将从索引中删除该文件,同时将其保留在工作目录中。
这将提交索引中的所有其他变化。
再次将该文件添加到索引中。
在工作树中保留修改,同时丢弃一些以前的提交内容
假设你正在做某件事,并提交了它,然后你又继续做了一会儿,但现在你认为你工作树中的内容应该在另一个分支中,而这个分支与你之前提交的内容毫无关系。你可以启动一个新的分支,并重置它,同时保留工作树中的变化。
$ git tag start $ git switch -c branch1 $ edit $ git commit ... (1) $ edit $ git switch -c branch2 (2) $ git reset --keep start (3)
这将提交你在 branch1
中的第一次编辑。
在理想的世界里,你可以在创建并切换到 “分支2”(即 “git switch -c branch2 start”)时意识到先前的提交不属于新主题,但人无完人。
但你可以用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)
首先,将历史记录向后重设一次提交,这样我们就删除了原始提交,但保留了工作树上的所有修改。N确保任何用HEAD
添加的新文件仍然被标记,以便git add -p
能够找到它们。
接下来,我们使用 “git add -p”工具,交互式地选择要添加的diff hunks。这将依次询问每个差异块,你可以使用简单的命令,如 “是,包括这个”,“不,不包括这个”,甚至是非常强大的 “编辑”工具。
一旦对你想要包括的hunks感到满意,你应该通过使用git diff --cached
来验证为第一次提交准备了什么。这将显示所有已经移入索引并即将提交的修改。
接下来,提交存储在索引中的修改。-c
选项指定从你第一次提交时的原始信息中预先填入提交信息。这对避免重复输入很有帮助。HEAD@{1}
是一个特殊的符号,表示HEAD
在最初的重置提交(1次变更前)之前曾经处于的提交。 更多细节见 git-reflog。你也可以使用任何其他有效的提交参考。
你可以多次重复第2-4步,将原始代码分解成任意数量的提交。
现在你已经把许多修改拆成了自己的提交,可能不再使用git add
的补丁模式,以便选择所有剩余的未提交的修改。
再一次检查以确认你已经包含了你想要的东西。你可能还想确认git diff没有显示任何剩余的修改,以便以后提交。
最后创建最后的提交。