git学习笔记(二):分支和远程仓库
前一篇文章介绍了了git的一些基本概念和常用命令,本篇就更深入地聊一下git的分支。
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
>>>>>>> B表示分支B下:do some out modify love & 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
总结:本篇文章在上一篇的基础上通过情景再现更深刻地认识了实际工作中git的使用,希望能够对自己今后git的使用有一个更为清楚的认知~