如何用 Git 优雅回退代码,别搞错了!
脚本之家
你与百万开发者在一起
本文经由博客园作者 枕边书 授权转载
原文地址:www.cnblogs.com/zhenbianshu/p/12018714.html
基础试探
revert
首先肯定的是 revert,git revert commit_id
能产生一个 与 commit_id 完全相反的提交,即 commit_id 里是添加, revert 提交里就是删除。
但是使用 git log 查看了提交记录后,我就打消了这种想法,因为提交次数太多了,中途还有几次从其他分支的 merge 操作。
”利益于”我们不太干净的提交记录,要完成从 C 版本到 N 版本的 revert,我需要倒序执行 revert 操作几十次,如果其中顺序错了一次,最终结果可能就是不对的。
另外我们知道我们在进行代码 merge 时,也会把 merge 信息产生一次新的提交,而 revert 这次 merge commit 时需要指定 m 参数,以指定 mainline
这个 mainline 是主线,也是我们要保留代码的主分支,从 feature 分支往 develop 分支合并,或由 develop 分支合并到 master 的提交还好确定,但 feature 分支互相合并时,我哪知道哪个是主线啊。
所以 revert 的文案被废弃了。
Reset
然后就考虑 reset
了, reset 也能使代码回到某次提交,但跟 revert 不同的是, reset 是将提交的 HEAD 指针指到某次提交,之后的提交记录会消失,就像从没有过这么一次提交。
但由于我们都在 feature 分支开发,我在 feature 分支上将代码回退到某次提交后,将其合并到 develop 分支时却被提示报错。
这是因为 feature 分支回退了提交后,在 git 的 workflow 里,feature 分支是落后于 develop 分支的
而合并向 develop 分支,又需要和 develop 分支保持最新的同步,需要将 develop 分支的数据合并到 feature 分支上,而合并后,原来被 reset 的代码又回来了。
这个时候另一个可选项是在 master 分支上执行 reset,使用 --hard
选项完全抛弃这些旧代码,reset 后再强制推到远端。
master> git reset --hard commit_id
master> git push --force origin master
但是还是有问题,首先,我们的 master 分支在 gitlab 里是被保护的,不能使用 force push,毕竟风险挺大了,万一有人 reset 到最开始的提交再强制 push 的话,虽然可以使用 reflog
恢复,但也是一番折腾。
升级融合
rebase
只好用搜索引擎继续搜索,看到有人提出可以先使用 rebase
把多个提交合并成一个提交,再使用 revert 产生一次反提交,这种方法的思路非常清晰,把 revert 和 rebase 两个命令搭配得很好,相当于使用 revert 回退的升级版。
先说一下 rebase,rebase 是”变基”的意思,这里的”基”,在我理解是指[多次] commit 形成的 git workflow,使用 rebase,我们可以改变这些历史提交,修改 commit 信息,将多个 commit 进行组合。
介绍 rebase 的文档有很多,我们直接来说用它来进行代码回退的步骤。
1、首先,切出一个新分支 F,使用 git log 查询一下要回退到
的 commit 版本 N。
2、使用命令 git rebase -i N
, -i 指定交互模式后,会打开 git rebase 编辑界面,形如:
pick 6fa5869 commit1
pick 0b84ee7 commit2
pick 986c6c8 commit3
pick 91a0dcc commit4
pick(p)
最旧的 commit1,然后在后续的 commit_id 前添加 squash(s)
命令,将这些 commits 都合并到最旧的 commit1 上。git rebase --abort/--continue/--edit-todo
对之前的编辑进行撤销、继续编辑。older, commit1, commit2, commit3, commit4,
而 F 分支上的提交记录是 older, commit5
,由于 F 分支的祖先节点是 older,明显落后于主分支的 commit4,将 F 分支向主分支合并是不允许的。git merge master
将主分支向 F 分支合并,合并后 git 会发现 commit1 到 commit4 提交的内容和 F 分支上 commit5 的修改内容是完全相同的,会自动进行合并,内容不变,但多了一个 commit5。文件操作
从主分支上切出一个跟主分支完全相同的分支 F。 从文件管理系统复制项目文件夹为 bak,在 bak 内使用 git checkout N
将代码切到想要的历史提交,这时候 git 会将 bak 内的文件恢复到 N 状态。在从文件管理系统内,将 bak 文件夹下 除了 .git
文件夹下的所有内容复制粘贴到原项目目录下。git 会纯从文件级别识别到变更,然后更新工作区。在原项目目录下执行 add 和 commit
,完成反提交。
小结
revert 适合需要回退的历史提交不多,且无合并冲突的情景。 如果你可以向 master 强推代码,且想让 git log 里不再出现被回退代码的痕迹,可以使用 git reset --hard + git push --force
如果你有些 geek,追求用”正规而正统”的方式来回退代码,rebase + revert 满足你的需求。 如果你不在乎是否优雅,想用最简单,最直接的方式,文件操作正合适。
END
更多精彩
在公众号后台对话框输入以下关键词
查看更多优质内容!
女朋友 | 大数据 | 运维 | 书单 | 算法
大数据 | JavaScript | Python | 黑客
AI | 人工智能 | 5G | 区块链
机器学习 | 数学 | 送书