1、分支
git每次提交时,都会把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。
HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长:
分支相当于开辟了一个平行空间,平行空间之间通常不会有任何交集,除非进行了合并。
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
注:被标星号的分支表明当前所在的分支。
当我们创建一个新的分支时,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上,HEAD也指向dev。从切换到dev分支开始,对工作区的修改和提交就是针对dev分支,新提交一次,dev分支的指针向前移动一步但是master分支的指针维持不变,相当于dev分支最开始在被创建的时候有了一个和默认master分支相同的文件副本。
1)如最开始master分支上,hello.txt文件的内容为:
2)切换至dev分支上:git checkout dev
3)修改hello.txt文件:
4)在当前分支上提交:
5)切换至master分支,再查看hello.txt的内容:
以上实验验证了不同分支的提交是不会相互影响的~
当我们在dev上的工作完成了,就可以把dev合并到master分支上,此时会直接把master分支指向dev的当前提交,HEAD在master上。
合并某分支到当前分支:git merge <name> (相当于一次commit,可以在merge的时候加上注释:git merge -m "注释" <name>)
验证:在master上合并dev分支:
然后再看此时master分支上hello.txt文件的内容:
可以看到master上的hello.txt文本的内容再合并dev分支的提交后,内容也变得和dev分支上hello.txt的内容一样了~
合并完成后,就可以删除dev分支了:
删除分支:git branch -d <name>
注:git的分支必须指向一个commit,没有任何commit就没有任何分支,提交第一个commit后git自动创建master分支。
合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
注意--no-ff参数,表示禁用Fast forward:git merge --no-ff -m "注释" <name>
以上情境很常见,比如你的小组接到一个新的功能模块的开发,常常是另开一个branch。。
2、分支冲突
小组开发的合理模式常见有以下几种:
1)针对一个新的功能开发模块,另开一个新的分支如dev,大家都在这个分支上开发;
2)大家都有自己的分支,只是把功能合并的时候merge到dev分支上。
无论哪种,master分支是直接跟版本库打交道的分支,是比较稳定的分支,我们不应该在maser分支上做开发,它仅仅是用来版本发布的~ 最终开发的分支必须被merge至此。
为了模拟分支冲突情况,因为此时我只有一个用户,那就用模式2)来模拟(其实等效于小组多个开发成员修改同一个Java类啦)。
最开始dev的hello.txt内容如下:
1)假如小组成员A使用分支A,修改了hello.txt的最后一行内容如下:
2)而小组成员B使用分支B,也修改了最后一行(简单模拟冲突):
3)现在A尝试去合并B的提交,发现有冲突:
直接在A分支上查看此时hello.txt文件的内容,可以看到:
仔细看冲突的部分:
<<<<<<< HEAD表示当前版本下:do some out modify love and beauty
在当前版本HEAD下尝试合并:
然后add再commit:
会看到both modified的字样。
分支冲突时:当git无法自动合并分支时,必须先解决冲突,然后再用git log --graph --pretty=oneline --abbrev-commit查看分支合并图:
解决冲突并合并完毕。
3.clone远程仓库和同步本地仓库
可在github上搭建一个远程仓库,模拟公司的私服。
具体教程参照「廖雪峰大神」写的:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013752340242354807e192f02a44359908df8a5643103a000
1)克隆远程仓库,例如在F盘下,克隆github上的HelloGit仓库:
git clone git:@<ip>:<project/github账户名>/remote-repo-name.git
如:git clone git:@github.com:CommyChang/HelloGit.git
这样,在本地的F盘就会有一个和远程仓库一样的本地库了。
2)将本地仓库关联到远程服务器
要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git;
关联后,使用命令git push -u origin master第一次推送master分支的所有内容;
如:git remote add origin git@github:CommyChang/learngit.git;
git push -u origin master(第一次加u以后就不用加了)
3.git pull和git push
现在本地仓库的HelloGit和远程仓库同名的HelloGit关联起来了。现在假设已经有同事B在master分支上对README.txt文件做了修改并push到远程仓库了,此时远程仓库README.txt的内容由原来的aaaaaaa变为:
这是,同事A也对README.txt做了修改并提交到本地库了:
用git status查看此时状态:
会提示此时和本地仓库版本一致,但是比origin/master(远程仓库默认名为origin)提前了8个commits~,并且建议push;
然后他也尝试把本地版本库的内容push到远程,发现:
会发现push被拒绝,并且git还建议我们先pull.
git pull表示先从远程版本库拉版本库的版本,
红色部分可以看出,在pull的过程(也就是把远程仓库的版本跟本地merge的过程)中,对README.txt文件发生了冲突,此时本地README.txt的内容如下:
修改之,再提交到本地仓库:
此时,可以看到远程仓库的文件README.txt是merge之后的:
同时,也多了之前没有的由A提交的文件a.txt:
以上模拟实验很好地再现了实际开发工作中的情况,所以再跟远程仓库的分支打交道时,一定记住先git pull再git push。。
4、标签管理
在git中,每个版本发布最好是有相应的版本编号。这时候就需要用到标签了。
1)在当前分支上,默认针对最新一次的commit打标签,同时用git tag可查看所有的标签即版本信息:
2)为某次commit打标签并查看某个标签对应的提交信息: 先找到你要打标签的提交:
用命令git show <tagname>可以看到说明文字;
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
接下来大概讲下标签的操作:
删除标签:git tag -d tagname
推送到远程:git push origin tagname
一次性推送到远程:git push origin --tags
删除远程标签:先删除本地标签git tag -d tagname,再删除远程git push origin :refs/tags/tagname