此次回顾是针对之前在上海开发过程中,吕鹏提交的代码被我覆盖掉的事故。希望通过学习了解事故发生的原因,避免以后在工作中重蹈覆辙。
以下是我自己的理解,可能会有错误,大家及时指正。
a) 事件回顾:为了简便描述,S代表我,L代表吕鹏。
i. L进行了数次提交。
ii. S使用pull -merge进行拉取,出现了合并冲突。
iii. S在解决合并冲突的过程中,发现L提交的修改出现了自己的待提交区,S以为这些代码不需要重复提交,就对这些修改进行了discard,然后进行了push。
iv. L在使用pull -rebase拉取代码以后,发现自己的修改被覆盖掉了。
b) 原因分析:
i. Git主要有三个区域,工作区,暂存区,本地仓库。三者的关系就不详细说了。
ii. Git merge 和 rebase的区别。merge是git将本地的修改和远程仓库的修改做了一个合并,更新到本地仓库,是基于本地树;rebase是先将本地的提交删除,以远程仓库的修改作为基础,将本地修改作用在上面,是基于远程树。
iii. Git pull 和 git fetch的区别。在本地存在着每一个分支对应远程仓库的指针(以T指代),里面存储了最后一次的commit id。这个指针可以理解为远程仓库的镜像。本地仓库(L)和远程仓库(R)在技术实现上是没有交集的,两者是通过T这个桥梁实现的。在L上执行了git fetch命令后,Git会把R上的改动下载到本地更新到T上,如果此后不执行git merge的话,那么你的L和T就会存在差异,只有执行了git merge命令后才会把T中的内容合并到L中。所以如果我们的L有了改动,执行git push的话,Git会先把改动更新到T中,然后再将T的改动推向远程的R中。虽然从结果上看,git pull = git fetch + git merge,实际上,git pull会将本地库L更新至远程库R的最新状态,而L中的commit id并没有发生变化。
iv. 在S使用了默认的pull merge以后,由于合并冲突,实际上合并中断了,此时工作区和本地仓库的树是存在差异的。S将L提交的修改在本地discard以后,push到T的树就忽略了这些修改,在push到远程仓库R中时,git就认为这些类是被删掉了,因此之前的修改就被覆盖掉了。
c) 通过这次回顾和学习,大致了解了git的内部工作原理。建议以后的工作,尽量使用git bash进行操作,先执行git fetch查看有哪些修改,再执行git rebase。如果使用smartGit的话,将git pull的模式改为 默认 rebase。避免同样的事故再次发生。