在真实的项目开发中,项目版本库放在一个Git服务器上(如:Github,Gitlab,或者自己搭建Git服务器),然后项目的开发人员在本地clone服务器上的代码到本地版本库。那么服务器上的版本库就叫远程版本库。
在Git中本地版本库可以与多个远程版本库进行交互,也就是说本库版本库可以使用git remote add
命令添加多个远程版本库,然后可以使用push pull
命令可以推送或者拉取你指定远程版本库中的代码。那么当你push或者pull的时候Git是怎么区分你是要操作的时候哪个远程版本库的呢?
首先clone一个远程版本库到本地,然后使用git branch
查看本地分支会发现只有一个master分支
在使用git show-ref
查看本地的所有的引用,在使用git branch -r
查看远程分支。
在clone远程版本库的时候会将远程分支复制到.git/refs/remotes/origin/
目录下,如果使用的是 git remote add demo 远程版本库地址
关联另一个远程版本库,那么这个远程版本库的分支将复制在.git/refs/remotes/demo/
目录下。这样就可以针对不同的远程版本库进行操作。
在查看远程分支的时候发是分支名称前面为什么还有个”origin/”前缀呢?,原因就在.git/config
文件中。
图中的[remote “origin”]小节以origin为名注册了一个远程版本库,该版本库的地址是这个小节的url属性对应的值,也就是一开始我们clone远程版本库所填写的地址,而fetch属性对应的值设置了git fetch origin
操作时所使用的默认引用表达式。
1.该表达式以加号(+)开头,含义是强制进行引用替换,即使即将进行的替换是非快进式的。(本人没懂是什么意思- -.)
2.引用表达式中的冒号(:)前面指的是远程版本库所以的分支,因为使用了通配符星号(*),冒号后面意思是复制到本地的.git/refs/remotes/origin/*
目录下。
正是因为clone的时候Git自动为我们在.git/config为我们自动配置了[remote “origin”]小节,所以当执行git fetch origin
操作时,就相当于执行了下面的命令,将远程版本库里面的所以分支复制为本地分支。
git fetch +refs/heads/:refs/remotes/origin/*
而图中的[branch “master”] 小节则是设置本地的master自动跟踪远程版本库的master分支(也是clone的时候自动设置的),这也就是为什么我们一clone就可以使用push和pull命令就可以直接推送到master分支上而不需要加上 origin master参数。反过来说就是本地分支要是没有跟踪远程分支的情况下使用push和pull命令会报错!下面讲下如何跟踪远程分支。
如果你的Git版本是1.66或者以上的并且你只添加了一个远程版本库就可以使用下面的命令。
git checkout 分支名
执行这个命令之后会显示下面提示信息。
Branch 分支名 set up to track remote branch 分支名from origin.
Switched to a new branch '分支名'
如果添加了多个远程版本库就不能使用上面的命令,因为不同的远程版本库可能存在相同名称的分支!那么下面这个命令可以解决这个问题
git checkout -b 本地分支名称 远程版本库名称/远程版本库分支名
本地分支和远程分支建立跟踪之后,本地分支就具有如下特征:
- 使用
git status
查看工作区状态后会显示本地分支和远程分支提交之间的关系,比如在本地提交一个commit然后查看工作区状态会显示如下信息。
$ git status
On branch dev
Your branch is ahead of 'origin/dev' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working directory clean
这些消息表示你本地的提交已经领先远程分支一个提交。
当执行pull命令时,本地分支的提交是远程分支的提交的父提交时,则会是一次快进式合并,如果不是则会是把本地分支的提交和远程分支的提交合并为一个提交!合并完成后才能会产生冲突,此时,需要解决冲突然后在提交。
使用push命令时,会把本地分支推送到远程分支。一般情况下远程版本库会设置不允许非快进式的提交,这时,当远程分支不是本地分支的父提交时则需要先使用
git pull
命令同步提交。然后才可以push!
参考
《Git权威指南》