Git 常用撤销操作

1 没有 add 撤销

git checkout <file-path>

这样就可以把文件恢复到 git 版本里的样子。

2 add 后撤销

如果修改的文件已经 add 了,可以用下面的方法撤销 add。

git reset HEAD <file-name> # 撤销某个文件
git reset # 撤销所有文件

同样,另一个操作也可以达到一样的效果

git rm --cached <file-name> # 删除文件
git rm -r --cached <dir-name> # 删除目录

3 删除操作 add 后撤销

一个删除操作 add 了,这个时候 checkout 是没有用的,会提示 error: pathspec ‘xxxxxx’ did not match any file(s) known to git.。

git rm –cached 也没用,错误类似。

只能使用 git reset HEAD <file_name> 将这个文件变为没有 add 的状态,再 checkout。

4 撤销 commit 操作

我现在做了一些修改,然后提交了。

如果想撤销这个 commit,但是自己的修改不变,可以使用下面的方法。

git reset HEAD~1

如果想练修改也撤销掉,就使用

git reset --hard HEAD~1

5 已经被跟踪的文件改为不跟踪

有的文件在加入版本库之后又需要放入到 .gitignore 文件里不再被追踪。可以这样

git rm <file-path> # git rm -r <dir-path>
git add <file-path>
git commit -m'xxx' 
# 然后把这个文件加入到 .gitignore 文件里就可以被正常排除了

6 merge 后要撤销

merge 操作如果不是 fast-forwarded 模式的都会有一次提交,查看日志就像这样:

commit 2f9e61e4520c03c9d4f6618411c6f283e4e214a8 (HEAD -> master)
Merge: 6dba022 6b04fc2
Author: Laily <i@laily.net>
Date:  Mon Sep 18 22:42:38 2017 +0800

    Merge branch 'dev'

commit 字段是这次合并生成的 commit 的 id,这个 commit 又称为 merge commit。Merge 这个字段后有两个值,分别是 merge 的两个分支最后的 commit id。我这次合并是在 master 分支上合并了 dev 分支,所以这个 6dba022 是 master 分支在合并前的最后一次 commit id,6b04fc2 则是 dev。

如果这个时候我想要撤销这个合并操作,则可以用下面的命令

git revert 2f9e61e4520c03c9d4f6618411c6f283e4e214a8 -m 1

这样会增加一次提交,revert 掉了这个合并。

-m 1 表示保留 merge 字段中第一个 commit id 的信息,也就是撤销后恢复到 master 分支原本的状态,如果是 -m 2 就是恢复到 dev 分支的状态。

这个方法有两个问题

  • 如果合并的时候是 fast-forwarded 模式则不会生成 merge commit。所以以防需要回滚,可以在合并的时候使用 git merge –no-ff dev 这样强制生成一个 merge commit。

  • 使用了 revert 回滚之后如果又需要再次合并 dev 分支,则需要 revert 掉前面的 revert 提交, 然后再合并。

7 rebase 后撤销

Git rebase 过程中可以使用 git –abort/-continue 来进行操作。那 rebase 成功后怎么撤销了。

首先使用 git reflog 查看本地记录。

找到 rebase 之前的 commit id。

因为我这里使用的是 pull -r 操作,是先 pull 然后 rebase 的,所以在 rebase 前面有几个 pull 操作,如果是直接 rebase 的就没有。所以这里最近的 commit id 是 00759b3 HEAD{11}: commit: feat: temp

所以执行

git reset --hard 00759b3