要先commit还是先pull?
场景一:本地分支之间的切换
1、不commit代码就切换分支
我们来看看,在本地多个分支时,不commit就切换分支会发生什么:
首先,创建一个maven工程,添加一个Java类:GitDemo,并添加如下代码:
package com.tencent;
/**
* GitDemo.java
*
* @Author: CZQ
* @CreateTime: 17:47-2021/3/21
* @Description:
*/
public class GitDemo {
public static void main(String[] args) {
}
}
然后,我们新建一个dev分支,并在dev的GitDemo类的main方法中,添加如下代码:
System.out.println("don not commit and checkout");
我们不commit,直接切换回master分支
发现代码也被带过来了,没有丢失。
我们在master分支中,把main方法里的代码删掉,再加一行
System.out.println("hello world");
然后切换回dev分支:
可以发现,dev分支的代码一直跟master保持一致。这似乎看不出什么问题,可是,我们的dev的原先的代码:
System.out.println("don not commit and checkout");
已经被覆盖了,也就是说,dev的代码已经丢失了一部分,这并不是一个好的提交方式。
2、commit后再切换分支
我们在现有的基础上,在dev分支加上一行代码:
System.out.println("commit and checkout");
先commit:
然后再切换回master分支:
我们发现,master分支默认打开的并不是GitDemo这个类,而且也找不到这个类,而是打开了pom文件,原因是一开始我们创建的GitDemo类之后,并没有进行commit,所以master分支并没有这个类。
我们在master分支创建一个GitTest类:
同样先commit:
再切换回dev分支:
我们发现dev分支中并没有这个类,说明dev分支和master分支并不一致,dev没有被覆盖。
3、不commit时有冲突会怎样?
我们刚才在master分支中新建了一个GitTest类:
同样的,我们在dev中也去新建一个GitTest类:
这次,我们加一个main方法,在里面添加一行代码,然后,我们切换到master分支:
出现master分支上的GitTest类将会被重写的提示,我们选择smart checkout,提示是否重写,我们选择cancel:
这样,本地maser分支上的代码就不会被dev覆盖掉了:
然后,我们切换回dev分支:
GitTest类就不见了!!!可以发现,代码已经丢失。
那如果我们刚才选择override之后,再切换呢?
我们在master分支上的GitTest类中新加一行代码
然后commit之后checkout到dev上,在dev上加上同名不同代码的GitTest类:
我们不commit直接再次切换:
这次选择override:
可以看到,master原有的代码已经被覆盖:
我们不commit,再次切回dev:
仍然选择smart checkout,这次提示需要rollback:
我们选择rollback:
rollback后GitTest这个类还是消失了,checkout到master分支,原有的被覆盖的代码又回来了:
这并不是我们想要的结果。
那如果我们选择force checkout,又会是怎样的结果?
我们再次在dev上新建GitTest类,这次我们跟master代码保持一致,同样不commit,然后直接checkout
选择force checkout,结果master分支无变化:
再次切换回dev分支:
发现GitTest文件不见了。
总结:
不同分支之间,不commit直接切换时,如果没有commit的分支上新增的内容是一个全新的文件,即和要切换过去的分支没有同名的文件时,该文件会被同步到要切换过去的分支,切换回来文件也不会丢失;
例如:场景一的第1种情况。不同分支之间,不commit直接切换时,如果没有commit的分支上新增的内容是一个已有文件的代码时,如果发生冲突时,选择force checkout,则两边都不会保存该新增的内容,代码丢失;如果发生冲突时,选择smart
checkout,则该段代码会被同步到要切换的分支,如果从该分支重新切回原分支(例如dev),会提示选择smart
checkout还是force checkout,选择force
checkout,则两边都不会保存该新增的内容,代码同样会丢失,选择smart checkout,则该段代码会在原分支上继续保留
例如:场景一的第2种情况不同分支之间,不commit直接切换时,如果没有commit的分支上新增的内容是一个和其他分支同名的文件,会提示选择smart checkout还是force checkout,如果选择force,则两个分支上都不会保留该文件的代码;如果选择smart
checkout,则切换后目标分支上会被override,如果在目标分支上不commit,直接切回原分支,会提示原有的类不存在,需要rollback,可是rollback后,原来新建的同名类仍会不见,切回目标分支,发现被override的代码重新rollback,造成dev代码丢失。
例如:场景一的第3种情况。先commit再切换,则不存在本地代码和文件被覆盖的问题,如果有冲突时,也不会提示。 例如:场景二的第2种情况。
场景二:本地分支和远程分支之间同时更新代码
我们将本地dev代码push到GitHub上,模拟一下真实的开发场景:
然后,我们在本地上对代码进行修改:
上图是原有的IGitDemo类,已删除main方法中的所有语句。
这时GitHub上的代码如下:
我们不commit的情况下,直接pull代码:
本地跟远程没有冲突,当然,也没有同步。
我们在本地上再添加一行代码:
System.out.println("I don not know why do not asyn");
再次pull代码:
还是没有冲突,而且本地代码跟远程还是没有保持同步:
那我们修改一下远程代码:
可以发现,在GitHub上是需要先commit再update代码,所以,我们先commit,然后我们再次在本地pull代码:
毫不意外地出现了冲突,我们合并代码即可。
总结:远程分支和本地分支不一致时,如果不是同一个文件的同一处进行修改,不commit的情况下,文件也不会冲突,也不会被覆盖。
场景三:本地和远程分支之间切换
在update到跟远程一样后:
我们本地的代码已经无需commit了,这时,我们在远程master分支上再添加一个Java文件:iteminfo.java
我们在本地dev也添加一个类:GitMini.class
然后,我们直接切换到远程的master分支:
跟本地一样,我们的dev中的文件已经同步到本地master了,那我们再次切回dev:
文件还在,所以这种场景跟场景一是相同的。
总结
1、当本地不同分支或者本地和远程不同分支之间进行切换时,一定要先commit,否则会有代码或者文件被覆盖的风险;
2、本地分支和远程相同分支之间,先commit还是先pull都不会有代码被覆盖的风险,但是如果有冲突的情况下,如果merge不当,代码也有可能被覆盖。如果仅仅为了规范,也可以先pull再commit;但安全起见,建议还是先commit之后再pull。