git fetch/merge/push 与引用规格(refspec)

git fetch/merge/push 与引用规格(refspec)

参考链接:https://blog.csdn.net/longintchar/article/details/84480862

本文想讨论 fetchmerge 以及 push 命令的细节。

拉取 Refspec

假设我们用命令添加了一个远程版本库:

$ git remote add origin [email protected]:schacon/simplegit-progit.git

上述命令会在 .git/config 文件中添加几行,并在其中指定远程版本库名称( origin)、URL 和一个用于获取(fetch)操作的引用规格(refspec):

[remote "origin"]
    url = [email protected]:schacon/simplegit-progit.git
    fetch = +refs/heads/*:refs/remotes/origin/*

第1行:表示远程仓库的简称是 origin

第2行:指明远程仓库的 URL;

第3行:引用规格的格式由一个可选的 + 号和紧随其后的 : 组成。其中

  • 是一个模式(pattern),代表远程版本库中的引用;
  • 是远程版本库的引用在本地所对应的位置;
  • 开头的 + 号是可选的,告诉 Git 即使在不能快进的情况下也要(强制)更新引用。一般情况下都是加上+号的,先把文件拉取到本地,不是Fast Forward方式就手动合并;

默认情况下,引用规格由 git remote add 命令自动生成, Git 会获取服务器中 refs/heads/ 下面的 所有引用,并将它写入到本地的 refs/remotes/origin/ 中。

如果运行 git fetch 命令,示意图如下(命令中的灰色部分是默认参数):

git fetch/merge/push 与引用规格(refspec)_第1张图片

所以,如果服务器上有一个 master 分支,我们可以在本地通过下面这种方式来访问该分支上的提交记录:

$ git log origin/master
$ git log remotes/origin/master
$ git log refs/remotes/origin/master

上面的三个命令作用相同,因为 Git 会把它们都扩展成 refs/remotes/origin/master

如果想让 Git 每次只拉取远程的 master 分支,而不是所有分支,可以把上文引用规格的第 3 行修改为:

fetch = +refs/heads/master:refs/remotes/origin/master

这也是针对远程版本库 origingit fetch 操作的 默认引用规格。

对于那些只执行一次的 fetch 操作,我们可以在命令行指定引用规格。 比如,只想将远程的 master 分支抓取到本地的 origin/master 分支,可以运行:

$ git fetch origin master:refs/remotes/origin/master

也可以在命令行中按照如下的方式抓取多个分支:

$ git fetch origin master:refs/remotes/origin/master \
	 topic:refs/remotes/origin/topic
From [email protected]:schacon/simplegit
 ! [rejected]        master     -> origin/master  (non fast forward)
 * [new branch]      topic      -> origin/topic

在这个例子中,对 master 分支的抓取操作被拒绝,因为它不是一个可快进的引用。 可以在引用规格之前指定 + 号来强制抓取。例如:

$ git fetch origin +master:refs/remotes/origin/master \
	 topic:refs/remotes/origin/topic

上面的命令表示,对于远程仓库的 master 分支,会强制抓取到本地,但是对于 topic 分支仅允许快进式抓取。

你也可以在配置文件中指定多个用于 fetch 操作的引用规格refspec。 如果想在每次抓取时都包括 masterexperiment 分支,可以这样写:

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/master:refs/remotes/origin/master
	fetch = +refs/heads/experiment:refs/remotes/origin/experiment

合并 Refspec

我们在 .git/config 文件中可以看到跟踪的远程分支:

[branch "master"]
    remote = origin
    merge = refs/heads/master  #这里指远端服务器上的refs/heads/master

merge是由所在branch定义的,[branch “master”]的配置指定当前master分支的merge策略是使用 服务器端的refs/heads/master来合并到当前分支。这样就可以顺利的git pull origin了。

推送 Refspec

当前已有跟踪分支,开始推送代码

$ git push origin

上面过程的本质是提交当前分支头指针到origin,相当于拷贝本地refs/head/xxx到远程引用refs/remotes/master/下并提交。git push origin会被展开成git push origin :

$ git push origin master
$ git push origin master:master
$ git push origin master:refs/heads/master
$ git push origin refs/heads/master:refs/heads/master

上面的命令作用相同,因为 Git 会把它们都扩展成 refs/heads/master

注意,区分本地的 refs/heads/master 和远程仓库的 refs/heads/master

拓展

  • update
    • fetch操作的本质是更新远程仓库所指定远程分支的头指针(即origin->refs/remotes/xxx/)
    • merge操作的本质是合并当前分支和指定的头指针(refs/remotes/xxx->refs/heads)
    • pull操作的本质是fetch + merge
  • commit
    • commit的本质是修改了当前分支的头指针(refs/heads)
    • push操作本质是提交当前分支头指针到origin,顺便也修改了本地存储的origin头指针(refs/remotes/xxx)
  • checkout
    • 复制本地分支的本质是拷贝了refs/heads/下的一个头指针
    • push本地分支到origin的本质是把这个头指针上传服务器,顺便拷贝了本地存储的origin头指针(refs/remotes/xxx)
    • tracking远程分支的本质是把refs/remotes/下的指针拷贝到了refs/heads

你可能感兴趣的:(Git,git)