在 Git 中,有三个命令可以用来撤销操作,分别是 git reset
、git revert
、git checkout
。
Git 仓库由三个部分组成,工作区、暂存区和 Commit 历史。
我们在工作区进行开发,然后通过 git add
将文件修改添加到暂存区,然后 git commit
提交更改,就把暂存区的所有内容提交到了当前分支的 Commit 历史中去了。
该操作只能作用于 Commit,而不能作用于文件。同时,该操作会创建一个新的 Commit 来撤销之前提交的更改,它不会去修改现有的历史记录。
换句话说,这个命令是安全的,它不会丢失 Commit 记录,只会新增。
这个命令相对来说就要复杂一点了,它能够同时作用于 Commit 和文件,用来撤销还没有提交到远程仓库的改动。
对于 Commit 来说,git reset
会移动 HEAD 的位置,并且还可以变更暂存区和工作区,该操作有三个选项:
是不是有点绕,没关系我们实战说话:
touch a git add a git commit 'feat: 添加 a 文件' touch b git add b git commit 'feat: 添加 b 文件' touch c git add c git commit 'feat: 添加 c 文件' 复制代码
现在,我们使用 git log
可以看到有三条 commit
记录,使用 git status
可以看到暂存区的状态为空。
接下来,我们使用 git reset HEAD~1
命令,然后我们再次使用 git log
和 git status
命令,可以看到 Commit 历史中,HEAD 的位置已经修改到了提交 b 的位置,同时在工作目录中我们还能找到 c 文件,并且 c 文件被移出了暂存区,这就是 mixed
。
接下来,我们再次将 c 文件提交回去恢复成初始状态,这次我们在命令后加上 --soft
,我们再来看,HEAD 的位置依然被修改了,并且工作区 c 文件依然存在,不同的是 c 依然在暂存区中。
最后我们加上 --hard
再来看一看,我们可以发现,HEAD 变了,暂存区和工作区的 c 文件都被移除了,这个参数比较危险,也就不建议大家在公共分支上进行操作了。
说完了 Commit,那文件是如何撤销的呢?对于文件来说,上面提到的三个参数是不起作用的,它会去更新暂存区的对应文件到指定 Commit 的时候的版本。
还是上面的例子,如果我使用命令 git reset HEAD~1 c
,会出现什么结果呢?大家可以想一想,答案是,它会将 c 文件更新到上一个 Commit 的时候的版本,也就是还没有被创建的状态,所以你执行 git status
可以发现暂存区中存在 delete: c
,这就是文件的撤销。
当你 checkout Commit 的时候,会将 HEAD 指向你指定的 Commit,并且这个没有分支指向这个 HEAD,所以 checkout 之后,会处于一个 detached HEAD 的分支,如果你要提交 Commit 到这个分支,你应该先 checkout 一个分支出来,然后再进行提交。
当你 checkout 文件的时候,checkout 命令和 reset 就有点类似,但是它不会更新暂存区,只会更新工作区,当你使用 git checkout <commit> <filename>
的时候,就会把工作区的对应文件更新到指定 Commit 版本的状态,当你使用 git checkout -- <filename>
的时候就会撤销掉在工作区这个文件的修改。
对于这些操作,大家一定要注意,不要乱用,把仓库搞乱了就不好了。
非常感谢您的阅读,欢迎关注、转发、分享支持我。