查找最初出现提交的分支 (git/Jenkins/CD)

Finding the branch where a commit originally appears (git/Jenkins/CD)

我正在设计一个 Jenkins 构建系统,它会在任何标签被推送到存储库时触发。从那里,我们想知道标签引用的提交被推送到哪个分支。从那里,我根据该分支名称启动其他 Jenkins 构建。除了找出标记了哪个分支之外,此管道中的所有内容都很简单。

基本上,我的团队制作并正在使用 productionstaging 分支 - 当开发人员将东西合并到 productionstaging 中并想要发布时,他们将标记一个版本号,并将其推出。然后,Jenkins 可以在生产分支上使用该标签更新生产服务器,以及使用标签登台到暂存分支。如果 master 被标记,那么我将启动 CI 构建和测试。

我一直在测试此博客 post 中的方法:http://johndstein-blog.logdown.com/posts/428667 提供以下内容:

export HASH=$(git rev-parse HEAD)
export BRANCH=$(basename $(git branch -r --contains ${HASH}))
export TAG=$(basename $(git describe --all --exact-match ${HASH}))

echo "HASH: $HASH"
echo "BRANCH: $BRANCH"
echo "TAG: $TAG"

但这在 100% 的时间都不起作用 - 对于某些回购协议,当 运行 第 2 行(抓取分支)时 - 我有多个分支,但它出错了。我是 git 的新手,但据我所知,这是因为提交是在一个分支中进行的,然后合并到另一个分支中。

那么我的问题是,如果我有标签,我能否可靠地找到提交最初被推送到的分支的名称?此外,这是一种明智的做法吗?

这在一般情况下是不可能的。如果不选择一些 "original" 并使其保留日志,"Was originally pushed to" 甚至没有明确定义。

这是一个例子。假设我创建分支 sneakgotcha:

     C   <-- sneak
    /
A--B     <-- master
    \
     D   <-- gotcha

现在,如果我 git push 这些分支中的一个或两个,接收 Git 存储库将获得两个提交 CD 连同更新请求姓名 refs/heads/sneakrefs/heads/gotcha。到目前为止,一切似乎都很好。但是现在我这样做而不是推动,或者在推动之后非常快——速度快到你无法在两者之间看到看到我在做什么:

$ git push origin sneak:sneak gotcha:gotcha &&
> git checkout master &&
> git merge sneak gotcha &&
> git push origin master:master :sneak :gotcha

git merge 进行了章鱼合并(当然我已经安排成功了,否则这需要很长时间才能愚弄你:-))。 push 步骤然后将提交 E 发送到服务器,连同更新 refs/heads/master 以指向它的请求,以及 delete refs/heads/sneakrefs/heads/gotcha。结果是:

     C
    / \
A--B---E   <-- master
    \ /
     D

CD 提交了哪些分支 and/or 推进?好吧,在我们覆盖并删除它之前,我们在服务器上保存了大约六毫秒的信息。

更糟的是,也许我推送的地方是推送镜像,真正的服务器更靠后。推送镜像可能已经有两三秒的信息了,有足够的时间去抓它......但是推送镜像和真实之间的link (端点)服务器出现问题,在那三秒钟内我覆盖了它,因此推送镜像最终将提交 CDE 发送到真实服务器,通过一个请求,更新 refs/heads/master 以指向提交 E.

现在,如果我们将"originally pushed to"定义为"sent to the push mirror"、我们让推送镜像保留一个日志,日志将显示我最初要求提交 C 进入 sneak 并提交 D 进入 gotcha。假设推送镜像和最终中央服务器之间出现 link-down 故障,该日志是 唯一 包含此信息的地方。你可以安排一个侧通道来检索这个,但是 none 是内置到 Git 中的(即使日志记录也有问题:你可以尝试使用 Git 的 reflogs 但它们可能不够细粒度,如果你关心每秒多次推送和真正严格的排序)。

裸存储库(和推送镜像)默认不启用引用日志,但您可以通过简单的 git config.

启用它们

综上所述...

主要担心的是提交可以在零个、一个或多个分支上。1诀窍是 不依赖于分支名称 除非你是控制这些名称的人。您可以短暂地控制 pre-receivepost-receive 挂钩中的分支名称,但使用起来很棘手。

你最好的选择是根本不依赖名称,而是需要一些单独的指示符,例如嵌入在提交消息本身中的字符串(你可以有一个预接收挂钩来检查它) .或者,您可以简单地要求您的标签 names 具有明确定义的格式:

production-v1.0.1
staging-v3.7

或其他什么。标记的名称告诉您该特定提交的目的是什么,并且完全独立于任何包含的分支。


1no 分支上的提交有些不寻常,但很容易创建:只需标记分支尖端提交,然后删除分支名称。您可以推送标签,并且提交会通过标签进入接收服务器,但没有分支。