Git撤消概括

谁还没有一颗想改变历史的心呢?

I.Git撤消之谜

Stackoverflow按投票(votes)排序搜索git,前15+的问题全部都是一个主题:求解各式各样的撤消。Github也早在2015年就贴心地把git常见撤消分类总结成简单易懂的情景再现:How to undo(almost) anything with git。可见初学者对git撤消是有很多疑惑点。不过,不论是Stackoverflow还是Github都侧重针对具体问题/场景提出纠正流程,虽然受益良多,但是总感觉太零碎,没能连成系统,于是就有了这篇总结。

II.Git工作区/暂存区/版本库

git-work

所以:不要将上图中表示的4个磁盘视为repo文件的单独副本。

从上图的流程可以看出,撤消无非就是分成四大类:

III.HEAD~和HEAD^区别

HEAD表明Repo目前指向的是那个位置。大多数情况下,HEAD指向当前分支中的最新提交。比如,你刚使用checkout 切换到新分支时,它就指向着新分支的最新提交。但是你可以任意改变HEAD的指向:

git branch -f Branch <SHA>

head

还想了解HEAD,Branch更多的内容。推荐玩一下游戏:LearnGitBranching,通关后,你将对它们有一个非常直观深刻的认识。

本文中的所有SHA都可以用HEAD^HEAD~来代表相对的位置的SHA。

IV.撤消工作区改动

工作区存放的是还未使用git add添加到暂存区的改动:

git checkout <bad filename>

警告:这会让文件的修改完全消失掉,恢复成git能记录的最新状态。所以你必须非常确信是不是有必要这样做。可以使用git diff 先比较下改动的内容是不是真的不需要了。

V.撤消暂存区改动

暂存区存放的是使用了git add 过,但未使用git commit -m 的改动:

git reset <FileName> 
git reset --hard <FileName>

如果reset后面是一个文件名,那么了就把这个文件从暂存区移到工作区,如果加了”–hard”,则会把这个文件的改动直接移除掉,就像改动从来没有发生过一样。

VI.撤消本地版本库改动

本地版本库存放的是使用了git commit 过,但未使用git push到远端的改动:

git reset <last good SHA> 
git reset --hard <last good SHA>

如果reset后面是指定的SHA。 默认情况,它会在还原时把改动都放到工作区—-commit消失了,但是改动还在硬盘上。如果你非常确信已不需要这部分改动。可以加上“–hard”选项。它会直接把改动丢弃掉。总之:默认会把改动移到工作区,加入“-hard”会把改动直接移除掉。

👉 SHA可以使用HEAD^~来指定相对位置或使用以下命令查看:

git log --oneline

还有一种常见的情况:重新编辑最近一次的commit改动。

已使用git commit -m "Fixes bug #123"但是还没git push到远端。这里你意识到日志写错了,应该是Fixes bug #1234

git commit --amend
git commit --amend -m "Fiexd bug #1234"

—amend会把上一次的commit和在暂存区(使用git add过的文件)组合在成一条新的commit。如果暂存区里没有改动。它就相当于重新写一下上一条的commit日志。

VII.撤消远程版本库改动

远程版本库存放的是已使用git push到远端的改动:

git revert <SHA>

revert会创建一条与给定SHA相反(逆向)的提交改动。所有在旧commit里新增改动都会在新commit里移除,所有在旧commit里面移除的部分都会在新commit中找回来。它不会改变git的历史日志,是git最安全的撤回方式。这样你就不需要使用git push -f操作,避免覆盖掉别人的修改。

VIII.撤消其它常见的误操作

IX.Rebase

Rebase是一个功能非常复杂的命令,本文只讲如何利用它来改变历史!

 git rebase --interactive HEAD~7

用编辑器打开前7条的commit,根据提示进行整理。一共有6个选项。

X.拓展阅读