Git手册 - Git的后悔药reflog reset和revert

2021-05-05
git
约 1730 字 预计阅读 4 分钟

一些写入性的操作,比如提交,合并,推送,拉取,等等都有可能存在误操作,git有完整的机制可以在这些步骤发生错误的时候进行还原操作, 比较依赖的工具有rebase,reset,reflog, revert, rebase在前面专门有一篇,这里不重复了

1. git reset

1.1. 介绍

先看看官方手册

see: git-reset

1
2
3
4
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>]

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

–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

Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated. This is the default action.

If -N is specified, removed paths are marked as intent-to-add (see [git-add1]).

默认值,索引回到指定提交, 缓存区被重置, 工作区不变

–hard

Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded.

工作区,缓存区,全部重置到指定的索引,直接回到刚提交到那次commit的状态

–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.

In other words, --merge does something like a git read-tree -u -m <commit>, but carries forward unmerged index entries.

–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.

examples

1
2
3
4
git reset -- frotz.c
git reset --soft HEAD^
git reset --hard HEAD~3
git reset --keep v1.0.2

1.2. 使用场景

最常用的就是下面3个

  • --hard
  • --soft
  • --mixed(默认)

–hard

放弃本地目前所有的缓存和未缓存的修改,也就是做错了,从头再来的意思

–soft

保留目前的工作进度,工作区和缓存区都不变,但是想应用在之前的某次提交上,一般是上一次的提交,相当于给某次提交打补丁

–mixed

保留工作进度,但是缓存区被重置(和soft比,就是缓存区被重置了),和soft的应用场景差不多

2. git reflog

git在回退以后,是看不到前面的commit了,这样如果对reset后悔了,就没有办法了吗?办法是有的,就是git reflog

reflog默认是开启的,也可以在config里进行设置

reflog可以看到所有操作的过程,类似于动作的log,不仅仅是commit的log,记录所有merge,commit,rebase,reset等等信息

reflog保存在.git\logs\refs\heads里,可以打开进行查看

git reflog的输出如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{0}: reset: moving to HEAD
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{1}: reset: moving to 7c3ad60
ef2b08d HEAD@{2}: commit: test1
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{3}: reset: moving to 7c3ad60
7390b1e HEAD@{4}: commit: test1
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{5}: rebase (finish): returning to refs/heads/develop
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{6}: rebase (start): checkout HEAD~20
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{7}: rebase (skip) (finish): returning to refs/heads/develop
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{8}: rebase (start): checkout master
ff5d36b HEAD@{9}: reset: moving to ff5d36b9495
99ea1b4 HEAD@{10}: pull origin develop: Fast-forward
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{11}: rebase (skip) (finish): returning to refs/heads/develop
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{12}: rebase (start): checkout master
ff5d36b HEAD@{13}: reset: moving to HEAD~1
99ea1b4 HEAD@{14}: rebase (abort): updating HEAD
960bd3b HEAD@{15}: rebase (continue): chore: add versionrc file for standard-version
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) HEAD@{16}: rebase (start): checkout master

也可以查看指定的分支

1
git reflog show develop

输出

1
2
3
4
5
6
7
8
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) develop@{0}: reset: moving to 7c3ad60
ef2b08d develop@{1}: commit: test1
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) develop@{2}: reset: moving to 7c3ad60
7390b1e develop@{3}: commit: test1
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) develop@{4}: rebase (skip) (finish): refs/heads/develop onto 7c3ad6040c1b5dcf739ca6e0446fbc85c6337f6a
ff5d36b develop@{5}: reset: moving to ff5d36b9495
99ea1b4 develop@{6}: pull origin develop: Fast-forward
7c3ad60 (HEAD -> develop, origin/master, origin/develop, azure/master, master, branch) develop@{7}: rebase (skip) (finish): refs/heads/develop onto 7c3ad6040c1b5dcf739ca6e0446fbc85c6337f6a

如果想要退回到某一步

1
git reset --hard develop@{4}

注意在powershell里大括号是需要转义的,用`来进行转义

3. 修改某次提交

除了用git rebase 中的edit,也可以用commit --fixup

3.1. git commit –fixup

具体操作流程如下

想在某次提交中增加一些改动

第一步, 暂存

1
git add .

第二步,提交

1
git commit --fixup SHA-id

这里的sha-hash就是要修改的commit的hash

第三步,rebase

1
git rebase -i autosquash SHA-HASH

这里的hash是要squash的SHA的前一个

4. 放弃本地修改回到remote的最后的状态

1
2
3
git fetch origin
git checkout master
git reset --hard origin/master

5. git revert

git revert 和 reset很像,都用来回滚到某次提交,但是区别如下

  • git reset是cimmit向后发展, git revert是commit向前发展
  • git reset会删除一些commit, git revert不会删除commit,只会增加commit

看图片就可以清楚的了解两者的区别

image-20210523080551097

使用起来比reset简单一点

1
2
3
4
# 回滚到某个commit
git revert a72ef02
# 回滚到某个commit, 如果还想手动更改, 不要自动commit可以这样
git revert 12eu1n3 --no-commit
TAG: git scm
文章作者 : Cocding