14.Git 远程版本库

Git 作为分布式版本控制系统,每个人都可以在本地的版本库中随意创建分支和标签。如果多人协作时,问题就出现了。

思考以下几个问题

  1. 如何避免因用户把所有的本地分支都推送到共享版本库,从而造成共享版本库分支的混乱?

  2. 如何避免不同用户针对不同特性开发创建了相同名字的分支而造成分支名称的冲突?

  3. 如何避免用户随意在共享版本库中创建标签而导致标签名称上的混乱和冲突?

  4. 有没有办法在执行 fetch 和 push 操作时,不用输入长长的版本 URL ?

  5. 如果不带任何其他参数执行 git fetchgit pullgit push ,到底是和哪个远程版本库的哪个分支进行交互?

一、 远程分支介绍

之前介绍分支时,每个版本库只和一个远程共享版本库进行交互,实际上 Git 允许一个版本库和任意多的远程共享版本库进行交互。首先执行下面的命令,基于 hello-world.git 版本库再创建两个新的版本库。

origin1.png

现在共有三个共享版本库: hello-world.githello-user3.githello-user4.git ,先看看 hello-world 远程版本库中包含的分支有哪些:

origin2.png

共有三个分支,现在重新克隆一下该版本库到 user5/workspace 目录:

origin3.png

执行 git branch 命令查看一下本地分支:

origin4.png

发现只有一个 master 分支 ,远程版本库的其他分支在哪里呢?执行 git show-ref 命令可以看到全部的本地引用:

origin5.png

输出显示:有些引用以 refs/remotes/origin 为前缀,并且名称和远程版本库的分支名一一对应,这些引用实际上就是从远程版本库的分支复制过来的,称为远程分支。

通过 git branch 加上 -r 参数,能够查看远程分支,如果是 -a 参数,则能够查看本地和远程所有分支:

origin6.png

实际上,在从远程版本库中执行获取操作时,不是把远程版本库的分支原封不动地复制到本地版本库的分支中,而是复制到另外的命名空间 .git/refs/remotes/origin/ 下,这样从不同的远程版本库执行获取操作,因为命名空间的相互隔离,从而避免了分支在本地的相互覆盖。

至于为什么远程分支都有一个名为 origin/ 的前缀,原因就在于配置文件:

origin7.png

说明 :

  1. 第 1 行表示以 origin 为名注册了一个远程版本库。

  2. 第 2 行表示该远程版本库的地址。

  3. 第 3 行表示执行 git fetch orgin 操作时使用的默认引用表达式。该表达式以 + 号开头,含义是强制进行引用的替换,即使将进行的替换是非快进式的。引用表达式中使用了通配符,冒号左侧表示匹配通配符规则的所有远程版本库分支,右侧表示复制到本地的远程分支(refs/remotes/origin/)目录。

  4. 执行 git fetch origin 命令时,相当于执行了:git fetch origin +refs/heads/*:refs/remotes/origin/* ,将远程版本库所有的分支复制到本地的远程分支中。

注意:远程分支不是真正意义上的分支,是类似于标签一样的引用。如果针对远程分支执行 checkout 命令,会看到大段的警告,告诉我们处于分离头状态。实际上,除了以 refs/heads 为前缀的引用之外,检出任何其他引用,都将使工作区处于分离头状态。如果要对远程分支进行修改,就需要创建新的本地分支。

二、分支追踪

如果想在分支 helper/v1.x 上进行工作,那么需要基于该远程分支创建本地分支,远程分支可简写为: origin/helper/v1.x 。在 Git 较高版本(高于 1.6.6)时,可直接使用下面命令同时完成本地分支的创建和切换:git checkout helper/v1.x 。在低版本中或注册了多个远程版本库(可能存在多个同名的远程分支),就不能使用上面简洁的分支创建和切换命令了,需要通过如下命令来创建:

origin8.png

输出显示,已经切换到对应分支了,并且本地分支和远程分支建立跟踪了。此时的本地分支有下列特征:

  1. 检查工作区状态时,会显示本地分支和关联的远程分支提交之间的关系。

  2. 当执行 git pull 时,如果两者出现版本偏离的话,会和关联的远程分支进行合并(或者变基)。

  3. 当执行 git push 时,会推送到远程版本库的同名分支中。

下面进行操作演示:

  1. 先将本地 helper/v1.x 分支回退两个提交版本,再查看一下状态:
origin9.png

输出显示:本地分支落后于远程分支 origin/helper/v1.x 两个提交,并提示可以通过 git pull 来更新到最新的提交状态。

  1. 执行 git pull 命令,会自动与关联的远程分支进行合并,相当于找回了最新的两个提交:
origin10.png

三、基于本地分支创建另一个本地分支

基于本地分支创建另一个本地分支,是没有分支跟踪功能的,来演示一下:

  1. 从本地分支 helper/v1.x 创建新的本地分支 helper/v1.y
origin11.png

只有一行输出,看不到分支间建立跟踪的提示。

  1. helper/v1.y 分支回退两个版本,再查看一下状态:
origin12.png
  1. 执行 git pull 命令,会报错:
origin13.png

输出表示:当前分支并没有跟踪信息,需要指定要和哪个分支进行合并操作。可通过 git pull {remote} {branch} 的方式指定拉取远程的指定分支,或者通过 git branch --set-upstream-to=origin/{branch} helper/v1.y 命令进行远程分支的跟踪,再进行拉取操作。

  1. 再查看一下配置文件:
origin14.png

会发现 masterhelper/v1.x 都有配置信息,但是 helper/v1.y 并没有相关的配置。

四、基于本地分支创建另一个本地分支(具备跟踪)

如果希望在基于一个本地分支创建另一个本地分支时,建立分支间的跟踪功能,需要加上 --track 参数,具体演示一下:

  1. 先检出 helper/v1.x ,再删除之前的 helper/v1.y 分支。
origin15.png
  1. 通过 --track 参数重新创建分支。
origin16.png
  1. 查看一下配置文件,因为这里跟踪的是本地分支,所以 remote 中的远程版本库的名字为一个点。
origin17.png

五、注册新的版本库

名为 origin 的远程版本库是在克隆时就已经自动注册了,下面再注册一个新的远程版本库:

  1. e/git_study/repos/hello-user3.gitnew-remote 为名进行注册:git remote add new-remote file:///e/git_study/repos/hello-user3.git

  2. 查看一下配置文件:

origin18.png

可以看到配置的分支信息 , remote 默认都是 origin ,所以不加参数,直接运行 git fetch 命令,并不会从新注册的 new-remote 远程版本库中获取,需要指定远程版本库。

  1. 执行 git remote -v 命令,可以查看已经注册的远程版本库:
origin19.png
  1. new-remote 远程版本库进行获取,并查看一下远程分支:
origin20.png

可以看到在 new-remote 目录下的三个远程分支。

六、更改远程版本库的地址

如果远程版本库的地址改变了,怎么修改呢?第一种:直接打开 .git/config 文件修改。第二种:使用 git config 命令进行更改。第三种:用 git remote 命令:git remote set-url new-remote file:///e/git_study/repos/hello-user4.git

再观察一下远程版本库信息:

origin21.png

输出显示:每个远程版本库都有两个 URL 地址,分别是执行 git fetchgit push 命令时用到的,这就意味着两个地址是可以不一样的,通过加上 --push 参数可以单独设置推送地址,如下图:

origin22.png

当单独为远程推送设置 URL 后,配置文件的 remote 节点也会增加一条名为 pushurl 的配置,如下:

origin23.png

七、更改远程版本库的名称

将远程 new-remote 的名称修改为 user4

origin24.png

重命名之后,相应的远程分支的名称也会自动更改。

八、远程版本库更新

当注册了多个远程版本库并希望所有远程版本库一起更新时,可通过如下命令:git remote update 。

如果某个版本库不想通过 git remote update 自动更新,可以使用如下命令进行关闭:git config remote.user4.skipDefaultUpdate true

九、删除远程版本库

user4 远程版本库进行删除,命令为:git remote rm user4

origin25.png

十、push 和 pull 操作远程版本库

pushpull 操作的重点在于配置文件,配置文件指定了合并的远程版本库名称、远程推送和获取的地址、引用表达式、远程分支信息等等,根据如下的配置图,我们来分析一下执行过程:

origin23.png

不带参数执行 git push 命令的执行过程:

  1. 如果为当前分支设置了 {remote} ,则不带参数执行 git push 相当于执行了 git push {remote} 。如果没有为当前分支设置 {remote} ,则相当于执行了 git push origin

  2. 要推送的远程版本库的 URL{remote}.pushurl 指定,如果没有配置,则使用 {remote}.url 配置的 URL 地址。

  3. 如果为注册的远程版本库设置了 push 参数,即通过 {remote}.push 配置了一个引用表达式,则使用该引用表达式执行推送。否则,使用 ":" 作为引用表达式。该表达式的含义是同名分支推送,即对所有在远程版本库中有同名分支的本地分支执行推送。

总结:在一个本地新建分支中执行 git push 推送操作,是不会推送也不会报错的,因为远程分支不存在同名分支,所以根本就没有对该分支执行推送。如果需要在远程版本库中创建分支,可以执行 git push {remote} {new_branch} 。通过将本地分支推送到远程版本库的方式在远程版本库中创建分支。但是,不能通过 git pull(不带参数)将远程版本库中其他人推送的提交获取到本地,因为没有建立本地分支和远程分支的追踪。

不带参数执行 git pull 命令的执行过程:

  1. git push 一样,如果配置了 {remote} ,则使用配置的 {remote} 名称,否则使用 origin ,即不带参数的 git pull 相当于执行了 git pull origin

  2. 要获取的远程版本库的 URL 由地址 {remote}.url 指定。

  3. 如果为注册的远程版本库设置了 fetch 参数,即通过 {remote}.fetch 配置了一个引用表达式,则使用该引用表达式执行获取操作。

  4. 如果配置了 branch.merge ,则对其设定的分支执行合并操作,否则报错。

总结:在执行 git pull 操作时,可以通过使用参数 --rebase 设置使用变基而非合并操作。可通过使用: git config branch.{branchname}.rebase true 命令设置使用变基操作,而不是默认的合并操作。

十一、标签和远程版本库

远程版本库中的 tag 同步到本地版本库时,会使用相同的名称,不会像分支那样复制到另外的命令空间(远程分支)中,这可能会给本地版本库的标签带来混乱,特别是和多个远程版本库交互时。

之前讲过,执行 git fetch 命令时,如果有新建的 tag ,这些 tag 会被获取到本地版本库中。当删除远程版本库时,远程分支会被删除,但是已经引入到本地的 tag 并不会被删除(删除远程不影响本地),这也使本地版本库中的 tag 变得混乱。如果不想管理 tag ,可以进行如下操作:

  1. 在执行 git fetch 命令时,可以加上 -n--no-tags 参数不获取 tag 而只获取分支和提交。

  2. 在注册远程版本库的时候,也可以使用 --no-tags 参数,避免将远程版本库的 tag 引入到本地版本库。

实际上 Git 版本库本身也提供了一些安全机制避免对版本库的破坏:

  1. reflog 对分支的操作历史进行记录。

默认创建的带工作区的版本库都会包含 corelogallrefupdatestrue 的配置,这样在版本库中建立的每个分支都会创建对应的 reflog 。但是创建的裸版本库默认不包含这个设置,也就不会为每个分支设置 reflog 。如果团队的规模较小,可能因为分支误操作导致数据丢失,可以考虑为裸版本库添加corelogallrefupdates 的相关配置。

  1. 关闭非快进式推送。

如果将配置 receivedenyNonFastForwards 设置为 true ,则禁止一切非快进式推送。但这个配置有些矫枉过正,更好的方法是搭建基于 SSH 协议的 Git 服务器,通过钩子脚本更灵活地进行配置。允许来自某些用户的强制提交,而其他用户不能执行非快进式推送。

  1. 关闭分支删除功能。

如果将配置 receivedenyDeletes 设置为 true ,则禁止删除分支。同样更好的方法是通过架设基于 SSH 协议的 Git 服务器,配置分支删除的用户权限。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359

推荐阅读更多精彩内容