77

我一直在按照本指南配置 GitLab 与 Jenkins 的持续集成。

作为该过程的一部分,有必要按如下方式设置 refspec:+refs/heads/*:refs/remotes/origin/* +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*

为什么这是必要的,帖子中没有解释,所以我开始在网上寻找解释,并查看了官方文档以及一些相关的 StackOverflow 问题,例如this one

尽管如此,我仍然感到困惑:

refspec 到底是什么?为什么上述 refspec 是必要的——它有什么作用?

4

2 回答 2

97

refspec 告诉 git 如何将引用从远程映射到本地存储库。

您列出的值是+refs/heads/*:refs/remotes/origin/* +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*;所以让我们分解一下。

你有两个模式,它们之间有一个空格;这只是意味着您要给出多个规则。(专业 git 书将此称为两个 refspecs;这在技术上可能更正确。但是,如果需要,您几乎总是能够列出多个 refspecs,因此在日常生活中它可能没什么区别。)

那么,第一个模式+refs/heads/*:refs/remotes/origin/*包含三个部分:

  1. +即使这样做会以非快进方式移动目标 ref,也不会失败地应用规则的方法。我会回到那个。
  2. 之前的部分:(但+如果有的话)是“源”模式。也就是说refs/heads/*,这意味着该规则适用于refs/heads(含义,分支)下的任何远程引用。
  3. 之后的部分:是“目标”模式。那就是refs/remotes/origin/*

因此,如果源有一个分支master,表示为refs/heads/master,这将创建一个origin/master表示为的远程分支引用refs/remotes/origin/master。对于任何分支名称 ( *),依此类推。

所以回到那个+......假设起源有

A --- B <--(master)

你获取并应用你得到的 refspec

A --- B <--(origin/master)

(如果你应用了典型的跟踪规则并做了一个pull你也master指出了B。)

A --- B <--(origin/master)(master)

现在有些事情发生在遥控器上。可能有人做了一个reset删除B,然后提交C,然后强制推动。所以遥控器说

A --- C <--(master)

当你获取时,你得到

A --- B
 \
  C

并且 git 必须决定是否允许origin/masterfromB到的移动C。默认情况下,它不允许这样做,因为它不是快进(它会告诉你它拒绝了对该 ref 的拉取),但因为规则以它开头,+它会接受它。

A --- B <--(master)
 \
  C <--(origin/master)

(在这种情况下,拉取将导致合并提交。)

第二种模式类似,但对于merge-requestsrefs (我认为这与您的服务器的 PR 实现有关;我不熟悉它)。

有关参考规范的更多信息: https ://git-scm.com/book/en/v2/Git-Internals-The-Refspec

于 2017-06-02T16:44:59.360 回答
1

refspec 告诉 git 如何将引用从远程映射到本地存储库。

使用 Git 2.29(2020 年第四季度),refspec 还可以告诉 Git 要排除哪些引用。
" git fetch" 和 " git push" 支持负 refspecs。

因此,您不仅可以fetch有选择地:

# Do not fetch any remote branch starting with 'm'
git fetch origin refs/heads/*:refs/remotes/origin/* ^refs/heads/m*

但您甚至可以pushpush --prune有选择地:

# If I delete local branches, included b, 
# those same branches will be deleted in the remote 'origin' repo.
# ... except for the remote branch b!
git push --prune origin refs/heads/* ^refs/heads/b

请参阅Jacob Keller ( ) 的提交 c0192df(2020 年 9 月 30 日(由Junio C Hamano 合并——提交 8e3ec76中,2020 年 10 月 5 日)jacob-keller
gitster

refspec: 添加对负引用规范的支持

签字人:雅各布·凯勒

两者都fetch支持push模式引用规范,允许获取或推送与特定模式匹配的引用。
因为这些模式是全局的,所以它们表达更复杂情况的能力有限。

例如,假设您希望从远程获取除特定分支之外的所有分支。为此,您必须设置一组仅匹配您想要的分支的 refspec。
因为 refspecs 要么是明确的名称匹配,要么是简单的 glob,因此许多模式无法表达。

添加对一种新类型的 refspec 的支持,称为“负”refspecs

它们以' ^'为前缀,意思是“ exclude any ref matching this refspec”。
他们只能有一个总是指源头的“侧面”。

  • 在获取期间,这指的是远程上的 ref 的名称。
  • 在推送期间,this 指的是本地端的 ref 名称。

使用负参考规范,用户可以表达更复杂的模式。例如:

git fetch origin refs/heads/*:refs/remotes/origin/* ^refs/heads/dontwant

会将所有分支提取originremotes/origin中,但不包括提取名为 的分支dontwant

今天的 Refspecs 是可交换的,这意味着顺序并不重要。
而不是强制一个隐含的顺序,否定的 refspecs 将总是最后应用。
也就是说,为了匹配,一个 ref 必须匹配至少一个正 refspec,并且不匹配任何负 refspec。
这类似于负路径规范的工作方式。


该文档现在包括:

A<refspec>中可能包含 a*<src>指示简单的模式匹配。
这样的 refspec 的功能类似于匹配任何具有相同前缀的 ref 的 glob。一个模式<refspec>必须*<src>和 中都有一个<dst>。它将通过将 refs 替换为*与源匹配的内容来将 refs 映射到目标。

如果一个 refspec 以 为前缀^,它将被解释为一个否定的 refspec
这样的 refspec 将改为指定要排除的 refs,而不是指定要获取哪些 refs 或要更新哪些本地 refs。
如果一个 ref 匹配至少一个正 refspec,并且不匹配任何负 refspec,则该 ref 将被视为匹配。

负引用规范可用于限制模式引用规范的范围,使其不包含特定引用。
负引用规范本身可以是模式引用规范。但是,它们可能只包含 a<src>并且不指定 a <dst>
也不支持完全拼写的十六进制对象名称。

查看t5582-fetch-negative-refspec.sh更多示例

于 2020-10-09T21:02:14.017 回答