问题概括
在pull代码时,拉取到我曾经删除半成品frontend
目录的commit,由于某些原因,此commit重新执行了一次,导致frontend目录下某些文件被删除,未及时发现,并通过PR提交到远程仓库。
修复的困难:由于使用了git merge --ff-only
,仓库和本地分支中含有所有的commit记录。使用残缺分支merge完成分支操作无效,使用完整分支提交PR到github的dev分支也无效。最后通过git push –force实现,清除了commit历史记录。
修复导致的代价是dev分支此前的merge记录被清空。
由于拉取代码不当导致的代码丢失问题
我有两个分支: dev-auth 提交分支 dev-auth-local 本地开发分支
此次提交中,我先采用了git merge --ff-only
操作,将local分支的commit保留到dev-auth分支上。
随后使用git pull team dev
(team是团队仓库的远程名称)准备处理冲突随后提交。
然后我准备将dev-auth-local
开发好的代码merge到dev-auth
上
但是在解决冲突后,发现部分文件丢失。
通过重置分支,发现 问题发生在:aa542ab8 这次commit上
也就是,从本地分支,合并 远程分支的过程中出现了文件的删除。
通过查看,发现是 之前的一次提交,我为了提交最小改动从而在本地删除了frontend文件夹,这个操作本身没有问题,但是当他再次执行一遍的时候,就造成了当前文件被删除。
为什么commit会再次执行一遍?
理论上来说,同样的commit不会再执行,但是检查哈希值发现,两次commit的哈希值并不一致。
同样,查看协作者的pr,他的commit哈希与我pull下来应用的commit的哈希也不一致
看到上一次的commit和这一次commit并不在同一条分支记录上
最左侧蓝色是dev-auth-local分支,粉红色是dev-auth(backup)分支 ,
第一次commit:当我切换到dev-auth分支时,我进行了删除半成品frontend的操作,仅提交必要部分。
第二次commit:从dev-auth-lcoal新建了分支dev,用来拉取远程仓库的dev分支(错误操作,应当在dev-auth上拉取),冲突解决好后merge到dev-auth上。但是因为此次commit哈希码变化,导致merge时对dev-auth重新生效,所以导致删除操作又执行一次。
由于使用Fast-forward的merge导致的解决问题困难
Fast-forward合并是一种合并方式,它可以在合并两个分支时保留提交历史。当我们使用Fast-forward合并时,Git会将源分支的提交直接合并到目标分支上,而不会创建一个新的合并提交。
需要注意,此操作需要多次保留或修改其中commit,会造成未知影响,同时,由于commit记录保留,再次merge操作时会忽略代码
git checkout master
git merge --ff-only feature
结果:feature分支记录保持不变,master分支加入了feature的commit记录
问题
使用–ff-only的本意是希望commit记录能保留,操作本身没什么问题。 现在的问题是,残缺的代码分别在dev-auth,remote/dev 分支上,完整代码在dev-auth-local上,分别都存在相同的commit记录,如何修复残缺代码?
解决步骤
1.在dev-auth上merge来dev-auth-local,从而push 由于存在相同的commit记录,merge会显示alread up to date,哪怕他们的代码不一样。
2.使用git reset --hard dev-auth-local
强制覆盖。
得到完好的dev-auth分支
3.在远程仓库回滚上次PR,使用完好的dev-auth分支提交PR。 失败,由于commit记录存在,回滚后代码消失,commit记录没消失,导致无法识别到全部需要修改的代码。
4.删除所有相关文件,再添加所有相关文件。产生新的commit记录。 失败,仍然只能识别到部分需要修改的代码。
5.使用git push origin dev-auth:dev --force
强制覆盖远程dev分支。
没办法的办法,丢失了此前三次merge记录。
但是同时commit记录也清爽了。
两分支存在差异,但merge提示alread up to date
git merge操作的本质是应用commit。因为merge只应用commit记录更改代码,包含了commit就不更改了,不看具体代码一不一致。
解决方案
创建一个备份分支
git branch backup-dev-auth
强制覆盖(谨慎使用)
如果你确定 dev-auth-local
的内容应该完全覆盖 dev-auth
,可以使用以下命令强制覆盖:
git reset --hard dev-auth-local
效果为,分支完全变为 dev-auth-local,包括commit记录
经验教训
- 使用git命令时,你最好知道自己正在做什么。即便你表面上知道自己在做什么,也可能因为概念理解不清晰导致意外错误。(但不能害怕错误)
- 外加参数使用要谨慎,普遍使用merge不加参数是有原因的。
- 无论如何,通过commit保存好自己的代码,恢复只是操作和时间问题。
- 养成良好的分支管理习惯,避免不必要分支。