Git - 什么是 "Refspec"

Git - What is "Refspec"

我一直在关注 this guide 配置 GitLab 与 Jenkins 的持续集成。

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

post 中没有解释为什么这是必要的,所以我开始在网上寻找解释并查看了 official documentation as well as some related Whosebug questions like this one

尽管如此,我还是一头雾水:

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

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

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

您有两个模式,它们之间有 space;这只是意味着你给出了多个规则。 (pro git 书中将此称为两个 refspecs;这在技术上可能更正确。但是,如果需要,您几乎总是可以列出多个 refspecs,因此在日常生活中它可能使差别不大。)

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

  1. + 意味着应用规则而不会失败,即使这样做会以非快进方式移动目标引用。我会回到那个。
  2. : 之前的部分(如果有 + 之后)是 "source" 模式。那是 refs/heads/*,这意味着此规则适用于 refs/heads(意思是分支)下的任何远程引用。
  3. : 之后的部分是 "destination" 模式。那是 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/masterB移动到C。默认情况下它不允许这样做,因为它不是快进(它会告诉你它拒绝了那个 ref 的拉动),但是因为规则以 + 开头它会接受它。

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

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

第二个模式类似,但用于 merge-requests refs(我认为这与您的服务器对 PR 的实现有关;我对此并不熟悉)。

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

A refspec tells git how to map references from a remote to the local repo.

使用 Git 2.29(2020 年第 4 季度),refspec 还可以告诉 Git 对 exclude.
的引用 “git fetch”和“git push”支持负引用规范。

因此,您不仅可以 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

参见 commit c0192df (30 Sep 2020) by Jacob Keller (jacob-keller)
(由 Junio C Hamano -- gitster -- in commit 8e3ec76 合并,2020 年 10 月 5 日)

refspec: add support for negative refspecs

Signed-off-by: Jacob Keller

Both fetch and push support pattern refspecs which allow fetching or pushing references that match a specific pattern.
Because these patterns are globs, they have somewhat limited ability to express more complex situations.

For example, suppose you wish to fetch all branches from a remote except for a specific one. To allow this, you must setup a set of refspecs which match only the branches you want.
Because refspecs are either explicit name matches, or simple globs, many patterns cannot be expressed.

Add support for a new type of refspec, referred to as "negative" refspecs.

These are prefixed with a '^' and mean "exclude any ref matching this refspec".
They can only have one "side" which always refers to the source.

  • During a fetch, this refers to the name of the ref on the remote.
  • During a push, this refers to the name of the ref on the local side.

With negative refspecs, users can express more complex patterns. For example:

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

will fetch all branches on origin into remotes/origin, but will exclude fetching the branch named dontwant.

Refspecs today are commutative, meaning that order doesn't expressly matter.
Rather than forcing an implied order, negative refspecs will always be applied last.
That is, in order to match, a ref must match at least one positive refspec, and match none of the negative refspecs.
This is similar to how negative pathspecs work.


The documentation 现在包括:

A <refspec> may contain a * in its <src> to indicate a simple pattern match.
Such a refspec functions like a glob that matches any ref with the same prefix. A pattern <refspec> must have a * in both the <src> and <dst>. It will map refs to the destination by replacing the * with the contents matched from the source.

If a refspec is prefixed by ^, it will be interpreted as a negative refspec.
Rather than specifying which refs to fetch or which local refs to update, such a refspec will instead specify refs to exclude.
A ref will be considered to match if it matches at least one positive refspec, and does not match any negative refspec.

Negative refspecs can be useful to restrict the scope of a pattern refspec so that it will not include specific refs.
Negative refspecs can themselves be pattern refspecs. However, they may only contain a <src> and do not specify a <dst>.
Fully spelled out hex object names are also not supported.

有关更多示例,请参阅 t5582-fetch-negative-refspec.sh