Git:reset 命令

Oct 24, 2021

目录


ref: https://git-scm.com/docs/git-reset


命令


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

git-reset - Reset current HEAD to the specified state


描述


前三条命令用于将 <tree-ish> 中的条目拷贝到索引中。 最后一条命令用于将当前分支(HEAD)重置到特定 <commit>, 同时可以选择是否修改索引和工作目录。

所有命令中 <tree-ish>/<commit> 的默认值是 HEAD

1git reset [-q] [<tree-ish>] [--] <pathspec>…
2git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]

这两种格式的命令会将所有于 <pathspec> 匹配的索引项(index entries) 重置到 <tree-ish> 的状态。(他不会影响工作目录(working tree)和当前分支)

也意味着: git reset <pathspec>git add <pathspec> 的逆操作。 这个命令等同于 git restore [--source=<tree-ish>] --staged <pathspec> ...

在执行 git reset <pathspec> 更新了索引之后, 可以使用 git-restore 将索引中的修改应用到工作目录中。

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

交互式的选择 索引和 <tree-ish> 中的不同。 选中的修改会被同步到索引中.

也意味着: git reset -p git add -p 的逆操作。

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

此命令将当前分支重置到与 <commit> 相同的状态。 如果指定了 <mode>,索引和工作目录也会同时被更新到 <commit> 相同的状态。

如果没有指定 <mode>, 默认值为 --mixed

<mode> 的值可以是以下之一:

  • --soft

不重置索引文件和工作目录中的文件(但是会重置 HEAD 到 <commit>, 就像所有mode下都会做的那样)。 所有修改过的文件都会保持 “Changes to be committed” 状态,使用 git status 可以查看。

  • --mixed

重置索引文件,不重置工作目录中的文件, 并且报告那些没有被更新的文件。 这是默认行为。

如果指定了 -N 选项,被删除的目录会被标记为 “intent-to-add” (参考 git-add)

  • --hard

重置索引文件和工作目录中的文件。 <commit> 之后的任何对跟踪状态的文件的修改都会被丢弃。

  • --merge

重置索引文件,更新工作目录中的那些在 <commit> 中和 HEAD 中不同的文件,但是保留那些索引中和工作目录中不同的项(例如那些被修改了,但是没有被 add 的文件)。 如果一个文件在 <commit> 和索引中不同,但是没有被 stage,reset 操作会被终止。

  • --keep

重置索引文件,更新工作目录中的那些在 <commit> 中和 HEAD 中不同的文件。 如果一个文件在 <commit> 中和 在HEAD 中不同,那么此操作会被中止。

  • --[no-]recurse-submodules

当工作目录被更新了,使用 --recurse-submodules 会根据 superproject 同时递归的重置所有当前活跃的子模块.


选项


  • -q, --quiet, --no-quiet

不显示回显消息,只报告错误。 默认行为由 reset.quiet 配置项决定。 使用 --quiet--no-quiet 可以覆盖该配置项。

  • --pathspec-from-file=<file>

<file> 形式来指定 pathspec,而不是命令行参数的形式。 如果 <file> 指定为 -, 那么从标准输入读取 pathspec。 pathspec 的元素之间通过 LF 或者 CR/LF 指定。

  • --pathspec-file-nul

仅仅在搭配 --pathspec-from-file 使用才有意义。 使用 NUL 作为 pathspec 的元素之间的分隔符。

  • --

不要将更多的参数解释为选项。 (Do not interpret any more arguments as options.)

  • <pathspec>..

限制受操作影响的路径。

更多详细信息,请参考 pathspec


例子


Undo add

场景: 你修改了一些文件,并且 add 了他们,此时你因为其他原因需要更新远程的修改到本地。 你可以这样操作:

1edit                                     
2git add frotz.c filfre.c
3mailx                                    
4git reset                                
5git pull git://info.example.com/ nitfol  

执行完上述命令之后,关于 frotz.c filfre.c 的修改依然在,不会被重置。

Undo a commit and redo

场景: 当你及其你刚刚提交的内容不完整,或者你拼错了提交信息,或者两者都有,这是非常常见的场景。 你可以如下操作:

1git commit ...
2git reset --soft HEAD^
3edit
4git commit -a -c ORIG_HEAD

使用 git reset --soft HEAD^ 将老的 HEAD 保存到 .git/ORIG_HEAD 中。

重新编辑拼写错的提交消息,重新提交。

Undo commits permanently

场景: 你已经提交了三次(HEAD, HEAD^, HEAD~2),但是你觉得这三次修改有问题,需要回滚。 你可以如下操作:

1git commit ...
2git reset --hard HEAD~3

undo a merge or pull

场景: 你尝试获取远程更新,但是更新操作导致了严重的冲突。 此时你不想花费时间解决冲突,可以回滚更新操作。 你可以如下操作:

1git pull
2	Auto-merging nitfol
3	CONFLICT (content): Merge conflict in nitfol
4	Automatic merge failed; fix conflicts and then commit the result.
5git reset --hard

此处的 git reset --hard 等同于 git reset --hard HEAD, 用于重置工作目录和索引。

Reset a single file in the index

场景: 你已经将一个文件添加到索引中,但后来决定不将其添加到提交中。您可以通过 git reset 从索引中删除该文件,同时保持所做的更改。

1git reset -- frotz.c    # 将此文件从索引中移除,但是保留工作目录中的修改
2git commit -m "Commit files in index"
3git add frotz.c

讨论


下面的表格展示了当你运行以下命令时所发生的情况:

1git reset --options target

具体的行为取决于你在使用 resetHEAD 重置为另一个 commit 时,你的文件的状态。

以下表格中,A, B, C, D代表同一个文件的不同状态。 例如, 第一行的意思是:

  • 文件在工作目录中的状态是 A
  • 文件在索引中的状态是 B
  • 文件在 HEAD 中的状态是 C
  • 文件在 target 中的状态是 D

然后执行 git reset --soft target, 执行后:

  • 文件在工作目录中的状态依然是 A,没有变化
  • 文件在索引中的状态依然是 B,没有变化
  • 文件在 HEAD 中的状态变为 D,从 C -> D.
1working index HEAD target         working index HEAD
2----------------------------------------------------
3 A       B     C    D     --soft   A       B     D
4                          --mixed  A       D     D
5                          --hard   D       D     D
6                          --merge (disallowed)
7                          --keep  (disallowed)
1working index HEAD target         working index HEAD
2----------------------------------------------------
3 A       B     C    C     --soft   A       B     C
4                          --mixed  A       C     C
5                          --hard   C       C     C
6                          --merge (disallowed)
7                          --keep   A       C     C
1working index HEAD target         working index HEAD
2----------------------------------------------------
3 B       B     C    D     --soft   B       B     D
4                          --mixed  B       D     D
5                          --hard   D       D     D
6                          --merge  D       D     D
7                          --keep  (disallowed)
1working index HEAD target         working index HEAD
2----------------------------------------------------
3 B       B     C    C     --soft   B       B     C
4                          --mixed  B       C     C
5                          --hard   C       C     C
6                          --merge  C       C     C
7                          --keep   B       C     C
1working index HEAD target         working index HEAD
2----------------------------------------------------
3 B       C     C    D     --soft   B       C     D
4                          --mixed  B       D     D
5                          --hard   D       D     D
6                          --merge (disallowed)
7                          --keep  (disallowed)
1working index HEAD target         working index HEAD
2----------------------------------------------------
3 B       C     C    C     --soft   B       C     C
4                          --mixed  B       C     C
5                          --hard   C       C     C
6                          --merge  B       C     C
7                          --keep   B       C     C

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.

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.

The following tables show what happens when there are unmerged entries:

1working index HEAD target         working index HEAD
2----------------------------------------------------
3 X       U     A    B     --soft  (disallowed)
4			  --mixed  X       B     B
5			  --hard   B       B     B
6			  --merge  B       B     B
7			  --keep  (disallowed)
1working index HEAD target         working index HEAD
2----------------------------------------------------
3 X       U     A    A     --soft  (disallowed)
4                          --mixed  X       A     A
5                          --hard   A       A     A
6                          --merge  A       A     A
7                          --keep  (disallowed)

END!!!


Tags