前情提要:Git应用详解第五讲:远程仓库Github与Git图形化界面html
git
除了能够很好地管理我的项目外,最大的一个用处就是实现团队协做开发。何况,linus
大神开发git
的初衷就是为了维护Linux
内核这一开源项目。因此,熟悉使用git
进行多人协做开发的通常步骤和方法具备十分重要的意义。这一讲将会为你介绍使用git
进行团队协做开发的通常方式以及git pull
操做常见问题的解决方法。git
git
协做方式Gitflow
:简单来讲,就是多种开发模式的总称。例如:使用多少分支,何时合并分支等等。这方面篇幅较长,内容较多,以后会进行详细讲解;vim
基于Git
分支的开发模型:通常最少有三个分支:svn
develop
分支:频繁变化的分支,供开发人员之间进行协做开发,文件推送与合并;test
分支:供测试人员与产品等人员使用的一个分支,变化不是特别频繁;master
分支:生产发布分支,变化很是不频繁的一个分支(通常有权限设置,由于直接与生产有关);bugfix(hotfix)
分支:用于紧急修复的分支;当出现紧急bug
时,在常规的develop
分支上修复已经赶不上了。此时能够直接将master
分支的代码拉取到bugfix
分支上,进行bug
修复,修复完以后,再将它合并到master
分支上发布;合并方向为:develop
-> test
-> master
学习
SVN
方式(典型模型)首先有两位用户A
与B
,A
的本地仓库不为空,B
的仓库为空,还有一个远程仓库C
。测试
A
首先将本地仓库的代码推送(push
)到C
中,此时A
和C
两个仓库的文件一致,如图中1
所示;B
将C
的代码拉取(pull
)下来,如图中2
所示,此时A
,B
,C
三个仓库中的文件一致;随后A
,B
继续在本地进行开发,并向各自的本地仓库进行了数次提交;A
先向C
推送修改事后的本地仓库文件,因为这是远程仓库C
的首次修改,C
中的文件A
中都有,因此能够直接推送,不用先执行git pull
,如图中3
所示;B
将修改过的本地仓库文件推送到C
的过程当中会出现错误。缘由在于:此时的C
中有A
作出的修改,不能让B
进行覆盖,此时B
要想成功推送,应该先将C
中的文件拉取(pull
)到本地;如图中4
所示,拉取时有两种状况:
A
与B
修改的不是同一个文件,采用Fast-forward
方式自动合并;A
与B
修改了同一个文件,须要手动解决冲突并合并;B
成功将C
中的文件拉取到本地合并后,就能将B
对本地仓库所作的修改推送(push
)到远程仓库C
了,如图中的5
所示;在整个过程当中,能够发现远程仓库C
仅仅是起到代码第三方托管的做用;fetch
为了模拟多用户协做,可使用--local
来设置每一个仓库的用户信息:命令行
git config --local user.name '张三'
--local
是一个配置做用域的参数,其余的还有:3d
--global
:做用域为每一个计算机用户,优先度第二,实际上经常使用这个参数进行配置;--system
:做用域为整个系统,优先级最低;可使用:git clone
将远程仓库的代码下载到本地某文件夹中,下面使用的是SSH
的方式:code
还能够经过在连接后面加上一个字符串,从新命名下载到本地的远程仓库文件的名字:
git clone git@gitee.com:ahuntsun/MY.git mygit2
远程仓库一般有多个分支,而在本地仓库进行一次推送时并非将本地仓库的全部分支都推送到远程仓库,而是选择本地仓库中的一个分支,将其推送到远程仓库的其中一个分支上:
好比本地的master
分支,如上图所示,能够选择远程仓库的master、dev、test
其中一条分支进行推送。假如想要推送到远程仓库的master
分支,若是一开始两个分支没有任何联系,天然要:
master
分支与远程master
分支的关联(至于如何创建关联,下一节将会详细讲解);master
分支与远程master
分支的合并,使两条分支的内容第一次达到同步;master
分支上进行修改,而后将修改推送到对应的远程master
分支上。此时,两分支的内容第二次达到同步;git pull
在实际开发中,在推送代码前,每每都要先执行一次git pull
将远程仓库的代码拉取到本地并进行合并;从前面的学习中咱们知道:git pull = git fetch + git merge
:
git fetch
:表示将远程仓库的全部文件拉取到本地版本库;git merge
:将远程仓库中的文件与本地仓库中的文件进行合并;可是,在执行git pull
命令时,因为本地仓库与远程仓库历史提交记录的不一样,每每会出现各类各样的合并错误;在分析这些错误以前,首先搭建测试环境:
分别建立两个本地仓库mygit
和mygit2
,而且这两个本地仓库与同一个远程仓库创建联系,以下图所示:
在本地仓库mygit2
中使用--local
参数配置新的用户lisi
模拟多人协做,随后经过lisi
给远程仓库推送一个新的文件。回到mygit
后执行git remote show origin
指令,会显示以下信息:
表示,本地仓库mygit
相对于远程仓库而言已通过时了,即远程仓库中有mygit2
推送的,mygit
中没有的文件;此时能够在mygit
中执行git pull
,将远程仓库中的文件拉取到本地仓库mygit
中进行合并:
上图中的第二个箭头表示,在pull
操做的过程当中mygit
中的master
分支与远程仓库中的master
分支采用Fast-forward
方式进行了合并,并达到了同步。
这里的本地远程分支
origin/master
表明着远程master
分支,关于本地远程分支将会在下一节进行详细讲解;
关于Fast-forward
方式以前已经介绍过了,在上述合并过程当中origin/master
分支直接指向了最新提交,中间没有其余分支,也就不会出现合并冲突,这种合并方式称为快进。以下图所示:
这是一个理想的状况,不少状况下执行git pull
操做时,都会出现合并冲突,须要解决冲突,再进行手动合并;
git pull
同源合并冲突所谓同源,指的是本地仓库与远程仓库中的分支从根提交节点开始,有共同的提交历史;简而言之,有共同的根提交节点的两个分支称为同源;以下图所示,两仓库中的master
分支有共同的根提交节点A
,因此这两个仓库的master
分支是同源的:
这种状况下git pull
出现的错误为自动合并失败,好比都同时修改了develop.txt
文件,错误信息以下:
Auto-merging develop.txt CONFLICT (content): Merge conflict in develop.txt Automatic merge failed; fix conflicts and then commit the result.
具体状况模拟以下:
在mygit
中修改hello.txt
文件的第二行为1
,在mygit2
中修改hello.txt
文件的第二行为2
,即对同一文件的同一处进行了修改。
此时取决于谁先进行git push
操做,若mygit
先将修改后的hello.txt
推送到远程仓库。那么当mygit2
再进行推送时会出现以下错误:
提示信息代表:远程仓库中有一些文件是你没有的,没法更新远程仓库;这是由于,mygit
先把修改的hello.txt
推送到了远程仓库;此时mygit2
想要成功进行推送,须要先将远程仓库中通过mygit
修改的hello.txt
与本地仓库的hello.txt
进行合并。
可使用git pull
来解决这一问题,那么咱们首先执行一次git pull
操做:
能够发现git pull
指令在进行自动合并时发生了错误,这是由于mygit
和mygit2
都对hello.txt
的同一个地方作了修改,git
不知道以谁为准,因此会致使自动合并失败,此时须要经过解决冲突三步曲来手动合并:
第一步:
打开冲突文件hello.txt
能够看到典型的冲突文件显示方式:
箭头<<<
与>>>
范围内表示的是发生冲突的位置。2
是mygit2
对hello.txt
的修改,1
为远程仓库中hello.txt
的内容;
通过协商后,留下第3
行,其他删除:
由此手动合并了对文件hello.txt
的修改,解决了冲突。
vim
指令补充:经过esc
进入命令行模式后,经过上下方向键选中某一行,再双击d
就能够删除光标所在的行;删除多行时,在命令行中输入:2,4d
表示删除第2~4
行;
第二步:
再次查看状态:
发现hello.txt
处于工做区,git
提示咱们要经过git add
指令将解决冲突时对hello.txt
所作的修改归入暂存区。
第三步:
执行完git add
以后,再进行提交git commit
:
由此,解决了冲突;
从上图中箭头所指内容能够看出:本地仓库mygit2
中的master
分支已经比本地远程分支origin/master
分支多了两次提交。因为origin/master
分支表明着远程仓库的master
分支,也就是说本地仓库mygit2
中的master
分支比远程仓库的master
分支领先了两次提交;过程以下图所示:
首先mygit
在提交1st
的基础上进行了第2
次提交(修改hello.txt
),以后mygit
将本地仓库推送(push
)到远程仓库;
此时mygit2
一样在本地仓库中进行了一次提交3rd
(修改hello.txt
),此时推送到远程仓库会出现错误,须要进行pull
操做;
当mygit2
执行pull
操做,将远程仓库拉取到本地后,因为发生冲突,因此暂时不会将origin/master
的指向更新到最新提交;随后,在mygit2
中手动解除冲突并进行合并后,mygit2
的状态为:
能够看到解决冲突,手动合并后,mygit2
已经往前更新了两次提交,而此时origin/master
仍然指向提交1st
。
因此解决冲突后,mygit2
中的master
分支会比origin/master
分支领先两次提交;再次执行git push
后,origin/master
分支就会指向最新的提交点4th
了,此时三个仓库的状态为:
在实际开发当中,不免会出现多我的修改了同一个文件的状况,在进行手动合并的过程当中必定要与对方协商应该如何合并,而不是直接覆盖;
git pull
不一样源合并冲突所谓不一样源,指的是两个仓库中的分支,根提交节点不一样,以下图所示:
假如本地master
分支要将内容推送到远程master
分支。因为本地master
分支根提交节点为1st
,远程master
分支根提交节点为A
,两个分支没有公共的父提交节点。因此,没法进行合并。这种状况下执行git pull
会出现如下错误:
There is no tracking information for the current branch. Please specify which branch you want to merge with.
特殊状况:假如本地仓库
mygit
是空的,也会发生不一样源合并冲突。
简单来讲git pull
失败的缘由有两点:
master
分支因为根提交节点不一样,没有共同的提交历史。因此,会致使采用三方合并原则合并分支时,找不到公共提交节点而没法合并:master
分支没有与远程仓库中的任一分支创建关联。所以,本地master
分支不知道将文件推送给谁,这样天然会失败;知道了git pull
失败的两点缘由,解决方案就很清晰了,一样分为三步:
第一步:执行一次git pull
将远程仓库的分支拉取到本地:
这里的本地远程分支origin/master
和origin/dev
是远程分支master
和dev
的本地形式,表明着它们,内容上与它们一致。虽然git pull
失败了,可是咱们得到了远程分支的信息,方便进行第二步的合并操做;
第二步:建立两分支的公共提交历史。此时两分支没有公共父节点,不能采用merge
方式合并。应该采用rebase
变基的方式,将本地master
分支追加到远程master
分支后面。因为本地远程分支origin/master
与远程master
分支有这相同的提交历史,因此能够这样写:
git rebase origin/master
此时,本地master
分支的提交历史变为:A <- B <- 1st <- 2nd
。这样本地master
分支与远程master
分支就有了公共的提交历史,即转换为了同源分支:
简写:能够将第一步和第二步经过参数的形式合并为一步操做:
git pull --rebase origin master
第三步:创建本地master
分支与远程master
分支的关联。经常使用的有如下三种方式:
//格式 git branch --set-upstream-to=origin/<branch> master //用在这里具体为 git branch --set-upstream-to=origin/master master
该指令做用为,将本地master
分支相关联的远程分支设置为远程master
分支,执行该指令后,经过git branch -vv
查看分支的关联状况,可见已顺利创建关联:
以后就能够进行推送了:
git push -u origin master
该指令做用为:创建本地master
分支与远程master
分支的联系,并进行推送:
git push --set-upstream origin master
做用为:创建本地master
分支与远程master
分支的联系,并进行推送:
mygitA
和mygitB
,首先在mygitA
中的master
分支上添加A.txt
,提交信息记为A
:mygitA
中建立并切换到dev
分支,添加文件C.txt
,并进行提交,提交信息记为C
:mygitA
的master
分支,添加文件B.txt
,并进行提交,提交信息为B
: 此时mygitA
中两分支的状态以下:
随后,创建本地仓库mygitA
与远程仓库的关联:
设置并推送mygitA
的master
分支和dev
分支,到远程仓库的master
分支和dev
分支上:
回到mygitB
,添加文件1st.txt
和2st.txt
并进行两次提交1st
和2nd
:
此时三个仓库的状态为:
若想将mygitB
的master
分支推送到远程仓库的master
分支上,按照上文的讨论,采用简写形式,可经过如下两步进行实现:
rebase
合并本地master
分支与远程master
分支:git pull --rebase origin master
执行完上述指令后,mygitB
的状态为:
master
分支与远程master
分支的联系,并进行推送:git push -u origin master
如图所示,与远程分支创建了联系,并完成了推送;由此解决了因为不一样源形成的pull
操做冲突。
以上就是本节的所有内容,细心的你确定发现了,在这一节中偶尔会提到本地远程分支
origin/master
,它究竟是什么呢?有什么做用?其实它是git
进行本地仓库与远程仓库交流的一个重要桥梁。在下一节中将会为你详细介绍本地远程分支的由来和做用,以及最重要的:如何创建本地仓库与远程仓库的分支对应关系?咱们下一节再见!