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.cfilfre.c,所以你恢复了这两个文件的索引修改。 你在工作树上的修改仍然存在。

然后你可以拉出并合并,留下frotz.cfilfre.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 --hardgit 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没有显示任何剩余的修改,以便以后提交。

最后创建最后的提交。