目录

关于 git reset --hard 引发的代码故障(附故障原因及解决方案)

背景

在开发过程中,发生了一次严重的代码故障:

  1. 同事 A 上线了一个需求,但由于设计原因,代码存在严重的线上故障,需要紧急回滚。

  2. 除了部署回滚之外,同事 A 使用了 git reset --hard进行代码回滚,然后重新进行了部署发布。表面上看起来没有问题。

  3. 发布后不久,团队内的同事 B 也发布了需求代码,这时故障再次出现。

  4. 原因是同事 B 将同事 A 回滚的代码再次发布到了正式环境。

  5. 同事 B 在合并代码之前确实再次合并了线上的 master代码。

  6. 问题:为什么同事 A 已经 reset了代码,同事 B 还能将回滚的代码带到正式环境?

分析

分析后发现,git reset –hard 强制修改了 master 分支的历史提交记录,导致故障产生

完整操作如下

- commit 情况
- 线上 master 分支最新 log commit: “last commit” commit f655dcfb
last commit
同事 A 提交 commit “需求 1” 到 master 分支 commit f655dcfb1
需求1
commit f655dcfb
last commit
同事 B 从 master 分支切换了新的需求分支(此时带有 commit “需求 1” ) commit f655dcfb1
需求1
commit f655dcfb
last commit
同事 A 强制 git reset –hard 到 commit “需求 1” 之前的一个 commit,
也就是 “last commit”
并且执行了 git push -f
commit f655dcfb
last commit
同事 B 需求开发完成,提交 commit :“需求2 ”,合并了 master 分支的最新代码,
并且将新需求的代码合入了 master
commit f655dcfb2
需求2

commit f655dcfb1
需求1
commit f655dcfb
last commit

从操作上来看,虽然同事 A 线上 git reset –hard 了代码,但是如果其他同事本地仓库就有了这些代码,那么在合并的时候 git 无法识别哪些是被回滚的(因为没有历史记录,无法对比),只能认为这些新添加的

解决

在找到原因之后,解决方法也比较简单

关于 git 代码回滚的几种方案对比,请移步文章 Git 如何正确回滚代码?常见回滚操作对比,适用不同的场景

方法一

不用 git reset –hard,改为 revert

git revert 不同于 –hard,会产生一个新的 commit,这样子其他同事本地 pull 的时 git 就能正确识别合并代码

方法二

如果确实是需要使用 git reset –hard ,在使用之前需要提前和团队内其他成员进行沟通,确保其他成员本地仓库没有拉取你这些需要回滚的代码,才能确保最终代码正常

那么还有一个问题,已经使用了 git reset –hard,造成了代码故障了,也就是上述的情况,应该怎么处理解决?

这就需要团队其他成员检查本地分支是否已经合并了回滚的代码,使用

 # 重置本地 master 分支 或者直接删除重新 checkout
 git pull -f
 git reset --hard origin/master

 # 当前分支和 origin/master 进行对比,会展示差异
 git diff origin/master

这应该是所有使用 git 的开发者在合并代码时的一个必备操作,很明显同事 B 并没有这样做

通过和 master 进行 diff,就可以展示哪些变动不是你修改的,选择丢弃即可

常见问题

这里整理了一些日常开发中常见的一些 git 问题,希望对大家有所帮助

Q1. git reflog 找不到目标提交记录?

原因有两个:一是记录超过了默认 90 天的保留期;二是执行过 git gc(Git 垃圾回收)命令,清理了过期记录。

解决方案:

① 日常可通过 git config --global gc.reflogExpire "365 days" 延长保留期;

② 若已清理,可尝试从远程仓库拉取(如果之前推送到过远程),或用 git fsck --no-reflogs 查找悬空提交。

Q2. 恢复后发现分支结构混乱,和远程不一致?

这是因为本地用 git reset --hard 回退了,而远程分支还是旧版本,拉取时会冲突。

解决方案:

① 若要让远程分支和本地一致,执行 git push origin 分支名 --force-with-lease(比 --force 更安全,会检查远程是否有他人提交);

② 若要保留远程版本,执行 git pull origin 分支名 --rebase 合并远程代码。

Q3. 团队协作中,有人误推了 reset 后的分支到远程?

这种情况会影响整个团队,处理步骤:

① 立即通知团队成员不要拉取该分支。

② 由管理员用 git reflog 找到远程分支的正确提交哈希。

③ 执行 git push origin 正确哈希:分支名 --force-with-lease 恢复远程分支。

④ 其他成员执行 git fetch origingit reset --hard origin/分支名 同步正确版本。

总结

总结如下:

  • 团队协作中,尽可能不用 git reset –hard

  • 合并代码时,一定要先进行 diff 合入分支,确保所有变动代码都是你改的(必做操作)

Git 命令的强大之处在于灵活性,但也意味着风险。

但是只要摸清楚命令的底层逻辑,再配上简单的预防工具,就能放心使用,不用再怕代码丢失了。

如果还有其他故障场景,欢迎在评论区分享~

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/git-reset-hard-code-conflict/

备用原文链接: https://blog.fiveyoboy.com/articles/git-reset-hard-code-conflict/