假设现在的 git 提交记录有4次,在第二次的时候发生了bug,也就是introduced a bug注释的地方。这个时候我们该如何处理呢?
417e4a9 commit 4
427d76b commit 3
1642475 introduced a bug
71d3ef7 commit 1
git revert
很重要的一点,revert 是对一次单一的 commit 的撤销,并不是真正意义上的回滚。它不是通过移除项目中一次 commit 后面的所有提交来“回滚”之前的状态。实际上那样的操作在 Git 上被叫做 reset,而不是 revert。
它解决的是如何撤销已提交的被引入的改动,并生成内容来追加一个新的提交,而不是从项目的历史中移除这个提交,这避免了丢失历史记录,这对于项目的每一次修改的历史记录的完整性来说非常重要,并这是服务于可靠的多人协作开发的。
git revert 1642475
这句命令会撤销这次 1642475 introduced a bug 所有被引入的改动,生成一个新的commit,并应用在当前分支上。
428e4a2 revert introduced a bug
417e4a9 commit 4
427d76b commit 3
1642475 introduced a bug
71d3ef7 commit 1
git reset
如果 git revert 是以一个"安全""的方式来撤销改动,那你可以认为 git reset 是一种 危险 的方式。当你使用 git reset 后,将没有办法恢复原样,它是一个永恒的撤销,因为那些 commits 不再被任何 ref 或 reflog 引用。在使用这个工具时请务必谨慎,因为它是 git 命令中唯一一个潜在的使你的努力付诸东流的命令。
git reset 1642475
这句命令会撤销 1642475 introduced a bug 之后所有被引入的改动,也就是撤销 commit 3 和 commit 4 的提交。
执行之后 commit 4 和 commit 3 提交改动的代码会从版本库回到工作区,你可以执行 add 或者 commit 再次提交即可。注意:如果此时 commit 4 和 commit 3 在其他分支还有记录,那么将无法再次合并了,因为 commit 4 和 commit 3 已经永远消失了。
1642475 introduced a bug
71d3ef7 commit 1
git checkout
切换分支是 git checkout 最常见的功能,不做介绍,这里主要介绍下它在撤销文件改动上的应用。
git checkout 1642475
如果通过 checkout 指定到 commit 的时候,我们可以把 commit 号当作一个零时分支,这个分支没有1642475 introduced a bug 之后的提交记录。在这里可以进行任意的修改,因为所有的改动与本地仓库的任一分支都无关,不会影响到其他的分支的状态。
相当于创建了只有 commit1 和 commit2 的零时分支。
1642475 introduced a bug
71d3ef7 commit 1
如果基于这个零时的分支去开发新的功能,那么需要通过下面的命令去创建一个属于我们自己的新分支。
git switch -c <new branch name>
新的分支可以提交到远程仓库中和其他分支合并,合并的时候如果远程仓库有 commit3 和 commit4 那么这个是不会被删除的。因为 checkout 命令不会影响到其他的分支的状态。
假设你正在进行一次疯狂的重构,但现在你不确定是否要继续下去。这时你想要看一下开始这次重构之前项目原来的样子。通过 checkout 切换到之前的版本ID上。你可以查看文件、编译项目、运行测试用例,甚至编辑文件,完全不用担心丢失项目“当前”的状态,你在这里做的所有修改都不会被保存到项目中。当你想要继续那次疯狂的重构时,你需要回到项目的“当前”状态。