如果开发人员正在develop
分支机构工作,那就是新项目
git clone <git_url>
应该能够在不使用develop
选项的情况下在本地自动克隆-b
分支,这样
$ git branch -a # after clone should give
* develop
remotes/origin/HEAD -> origin/develop
remotes/origin/develop
当开发人员使用命令develop
将本地分支(origin/develop
)更改推送到远程存储库(git push origin develop
)时,我的理解是,如果origin/master
指向remotes/origin/HEAD
,则更改被推送到origin/master
,与此comment中提到的不同
题:
1)在执行上述两项任务之前,是否建议运行git remote set-head origin develop
并在远程存储库中设置HEAD
指针?由任何开发人员
2)git push origin develop
是否推动改变origin/develop
而不考虑远程存储库中的remotes/origin/HEAD
值?
3)我们在GitLab和Jenkins之间使用webhook。 Qazxswpoi提供的env.gitlabSourceBranch
是否给出了GitLab plugin指向的分支名称?如果是,如何获取推送事件发生的分支名称?通过webhook。
下面是在GitLab中完成的设置,用于检索发生新提交的分支名称:
remotes/origin/HEAD
以下是Jenkins中的代码:
是否建议在远程存储库中运行
node('worker_node'){ stage('stage1'){ def repoName = env.gitlabSourceRepoName println "Repository Name: " + repoName // gives correct repo name def branchName = env.gitlabSourceBranch println "Branch name: " + branchName // gives always 'master' as value } }
并设置git remote set-head origin develop
指针...
这可能是一个语言问题,但值得指出的是,这并没有在远程存储库中设置HEAD
。它对任何其他人的HEAD
命令都没有影响。
Git的术语非常令人困惑。让我们分解一下:
git clone
是一个遥控器:它代表一些URL。如果你的Git拨打该URL,其他一些Git会回答这个“电话”。请注意,这里的单词remote是一个名词:它本身就是一个东西。origin
)我更喜欢使用短语分支名称,其中分支是形容词修改名称,远程跟踪名称(Git称之为远程跟踪分支名称),其具有修改单词名称的整个形容词短语,分别指What exactly do we mean by "branch"?和master
之类的东西。
分支这个词也意味着一系列含糊不清的提交。在这个特殊情况下 - 我们使用origin/master
将Git存储库从某个URL复制到我们自己的机器,或者git clone
将我们机器上的Git存储库中的提交发送到其他地方的某个其他Git存储库(可能在另一台机器上) - 我们不需要这个意思。但请注意它存在!我们还需要一两个或更多的Git术语:
git push
开头的完整拼写。
通常紧接着是它的分类:例如,所有分支名称都以refs/
开头。事实上,这就是Git知道refs/heads/
是一个分支。所有标签名称都以refs/heads/master
开头,这就是Git知道refs/tags/
是一个标签的方式,所有远程跟踪名称都以refs/tags/v1.2
开头。
在大多数情况下,您可以删除参考的refs/remotes/
或refs/heads/
或refs/tags/
部分。例如,如果您只是说refs/remotes/
,Git将搜索您的所有参考文献。如果你有一个master
而没有refs/heads/master
,那么名字refs/tags/master
必须是那个分支名称,所以Git会把它当作一个分支来对待它。同样地,如果你只是说master
,并且Git搜索并找到一个名为v2.1
但没有别的标签,那么refs/tags/v2.1
必须是那个标签名称,所以Git会将其视为标签。
Git用来记住Git的所有远程跟踪名称你的Git调用v2.1
从origin
开始。也就是说,你的Git记得他们的refs/remotes/origin/
是你的master
。这是如此,如果你有另一个遥控器,你的意思是其他origin/master
并不含糊。例如,假设您添加了第二个远程 - 第三个Git存储库 - 您可以简称为master
。如果您调用upstream
的URL上的Git有一个upstream
分支,那么你的Git会调用master
,并且很容易将这个区别于你的Git称之为upstream/master
的东西。origin/master
卡在它们之间的引用。因此,:
是一个refspec,例如。 master:master
也是如此。冒号左边的东西是源,冒号右边的东西是目的地。refs/heads/master:refs/remotes/origin/master
和git fetch
命令使用refspecs,我们将在稍后看到。当你问git push
而不是git clone
时,git fetch
的一个重要部分是运行git clone
。
考虑到所有这些,接下来让我们看看Git如何解析一个符号名称,以及当Git解析一个符号名称时。这部分有点棘手,因为git fetch
和git fetch
使用位置参数。
删除了很多细节(例如标志参数),git push
和git push
的参数在文档中以这种方式拼写出来:
git fetch
[git fetch
] [repository
[refspec
...]
refspec
[git push
] [repository
[refspec
...]
也就是说,在refspec
或push
子命令之后,根据定义,下一个项目是fetch
。根据定义,repository
参数之后的任何项目都是repository
参数。您可以将原始URL放入存储库部分,但通常,您应该使用远程名称,原因有两个:
要输入任何refspec
参数,你必须插入一个refspec
参数,因为没有一个,Git只会认为你输入的是repository
参数。也就是说,如果你不小心运行repository
,Git就不会发现你打算输入git push master
。它只会尝试将git push origin master
视为远程,或者将其视为URL。可能它不会以任何方式工作,你会得到这个令人费解的输出:
master
所以使用$ git push master
fatal: 'master' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
,您可以选择以下选项:
git push
当你把东西留下来时,就像在前两个例子中一样,Git为你挑选远程和refspec(第一个例子),或为你选择refspec(第二个例子)。当您包含refspec(第三个示例)或多个refspecs(第四个示例)时,您可以控制所有部件。
在我们回到第一个问题之前,让我们继续你的第二个问题:
git push git push origin git push origin somebranch git push origin branch1:branch1 branch2:branch2 branch3 tag1:tag1
是否会推动更改git push origin develop
而不管远程存储库中的origin/develop
值?
这包含多个术语错误(同样可能只是语言问题)。我认为,总的想法很清楚,答案是肯定的:这完全无视remotes/origin/HEAD
。
明确一点,这个:
remotes/origin/HEAD
指定为遥控器,并且origin
作为refspec。请记住,我们说第二种最简单的refspec形式是一对带有冒号的名称。这使用最简单的形式,省略了第二个名称。省略第二个名字的行为在develop
和push
中有所不同。我们在这里只担心fetch
。
对于push
,省略refspec的第二部分意味着第一部分和第二部分是相同的。也就是说,git push
意味着develop
。名字develop:develop
本身很短 - 它不是以develop
开头 - 但是你的Git和他们的Git可能都有一个名为refs/
的分支而且没有名为develop
的标签。所以develop
实际上是develop
的缩写。
请记住,他们的Git存储库是一个Git存储库。因此它有自己的refs/heads/develop:refs/heads/develop
-它自己的分支名称拼写refs/heads/develop
。您的develop
标识了您的存储库中的一些提交。他们的refs/heads/develop
在他们的存储库中识别出一些提交。
当你运行refs/heads/develop
时,你告诉你的Git:连接到其他一些Git。然后确保他们有足够的提交和其他内部Git对象来实现最后一部分,通过给予他们任何他们不需要的提交。最后,你已经完成了,要求他们 - 或命令他们 - 设置他们的一些分支和/或标记名称以指向某些特定的提交或其他适当的Git对象。
您要求他们设置的分支和/或标记名称来自refspec的目标部分。因此,如果你说git push
,分支或标签名称你将让你的Git要求他们的Git改变是git push ... develop:develop
。您要求他们设置为develop
的提交是源名称标识的提示 - 右侧的提交。因此,您将要求他们设置他们的develop
以识别您的develop
识别的相同提交。
1如果你有一个分支develop
和一个标签refs/heads/develop
,一些不太好的事情发生。 Git有这方面的规则,但Git的规则有点奇怪和令人不安。最好的办法是完全避免这种情况:永远不要为标签和分支使用相同的短名称。
如果他们对此请求说“是”,那么您的Git现在知道他们的refs/tags/develop
代表该提交。你的Git通过更新你自己的develop
记得他们的develop
。因此,您的Git会更新您的origin/develop
- 您的origin/develop
,使用其全名 - 来保存该提交哈希ID。
请注意,在这个过程中没有任何地方让你的Git看看你自己的refs/remotes/origin/develop
。你没有把refs/remotes/origin/HEAD
放在refspec的左侧。如果你愿意,你可以这样做。例如,你可以写:
refs/remotes/origin/HEAD
这将让你的Git将你的git push origin refs/remotes/origin/HEAD:refs/heads/develop
解析为提交哈希ID,在refs/remotes/origin/HEAD
调用Git,并要求Git将他们的origin
设置为该提交哈希ID。它可能已经设置为该ID,因此这可能只是浪费时间,但如果您愿意,它可以运行。
你也可以运行:
refs/heads/develop
它将你的git push origin HEAD:refs/heads/develop
解析为一个提交哈希ID,在HEAD
调用Git,并要求他们根据它设置他们的分支origin
;你可以运行:
develop
如果git push origin a123456:refs/heads/develop
是您的存储库中的一些有效提交。这些形式中的大多数需要两部分refspec,其中包含冒号,因为冒号左侧的东西根本不一定是分支名称,并且您将要求他们的Git设置一个他们的分支名称。
但是,一般情况下,当使用a123456
时,您将从您自己的分支名称(如git push
和/或develop
)开始,并且要求他们将相同名称的分支名称设置为相同的提交哈希ID。偶尔 - 例如在您刚制作新标签名称后 - 您将希望让Git调用他们的Git并要求他们将相同名称的新标签设置为相同的哈希ID。因此,master
将一个名称镜像为两个的默认值很适合你,因为你可以写:
git push
从而要求他们设置两个分支,并一次创建一个新标签。
如果他们拒绝,他们可以零碎地做。假设你要求他们设置所有这三个名字,并且他们接受你更新他们的git push origin master develop v1.3
并创建一个新的develop
的请求,但拒绝你更新他们的v1.3
的请求。你将获得两次成功,一次失败,你的Git将更新你的master
以记住分支成功,但不更新你的refs/remotes/origin/develop
,因为分支失败意味着你不知道他们的refs/remotes/origin/master
究竟是什么。 (没有远程标记这样的东西,因此要求他们创建master
的成功或失败对存储库中的任何名称都没有影响。)
v1.3
: what is it and what good is it?简而言之(也许有点过于激进),origin/HEAD
毫无用处。
它是Git的象征性参考。你可以随时使用refs/remotes/origin/HEAD
设置它。它最初是在git remote set-head origin
期间创建的。但据我所知,它没有任何实际目的。
我在上面提到你可以缩短参考文献:你可以说git clone
意思是master
和refs/heads/master
意思是v2.1
。在你自己的Git存储库中尝试这种事情:运行refs/tags/v2.1
并为分支和标签指定短名称和长名称。 (使用git rev-parse
列出你的分支,并使用git branch
列出你的标签。)你会看到这样的事情:
git tag
rev-parse命令从符号名称(如$ git rev-parse master
b5101f929789889c2e536d915698f58d5c5c6b7a
$ git rev-parse v2.1.0
7452b4b5786778d5d87f5c90a94fab8936502e20
)转换为哈希ID,如master
。 (它也可以从短哈希ID转换为完整哈希ID,或者执行许多其他技巧,但这是其主要工作之一:将名称转换为哈希ID。)
一般来说,当你给Git一个简短的名字时,Git会搜索你所有的引用,以找出长的名字。 b5101f929789889c2e536d915698f58d5c5c6b7a
命令执行此操作,然后吐出哈希ID。大多数其他Git命令也这样做,但接着以某种方式继续使用哈希ID。然而,在几乎所有情况下,这个搜索过程都在git rev-parse
中概述,值得仔细研究。但现在快速浏览一下,然后向下滚动一下,找到一个六步列表。
这里的六步列表是Git如何将一个简短的名称变成一个长名称。请注意,第3步尝试将the gitrevisions documentation作为标记名称:如果v2.1
存在,则refs/tags/v2.1
是标记名称,这就是v2.1
知道并找到其哈希ID的方式。这是第4步,它将git rev-parse
作为分支名称:如果master
存在,那么refs/heads/master
是一个分支名称,这就是master
所知道的。
在六步列表的底部,有一个步骤6.最后一步采用你输入的任何字符串 - 例如git rev-parse
,并将其作为origin
。如果存在,那一定是你的意思。所以虽然refs/remotes/string/HEAD
通常是一个遥远的 - 你输入的是origin
和repository
的git fetch
参数 - 它也是一个有效的提交短名称,如果你把它放在某个Git命令,如git push
,将使用它的地方作为提交。
有可能删除git rev-parse
和refs/remotes/origin/HEAD
就是这样做的。如果你已经删除它,git remote origin set-head -d
将不匹配第6步,origin
将失败。可以使用git rev-parse origin
将存储在git remote origin set-head
中的名称更改为任何其他refs/remotes/origin/HEAD
分支名称,以便步骤6成功但使用其他名称。在origin/*
,这一切都没有回到另一个Git!
2我在这里掩饰了象征性的参考。当像origin
这样的名称包含另一个名称而不是某个Git对象的哈希ID时,会出现符号引用。 Git使用的机制是一般性的,但充满了奇怪的怪癖和缺陷,实际上只适用于HEAD
,并且 - 在较小程度上 - 与这些远程跟踪HEAD
样式名称。
例如,您可以在分支名称空间中创建自己的符号引用。使用origin/HEAD
创建名称git symbolic-ref refs/heads/INDIR refs/heads/master
作为符号引用分支。不幸的是,如果你这样做然后尝试删除名称INDIR
,Git会删除名称INDIR
!整个事情还没有真正为这种用途做好准备(滥用?)。不要这样做!
3我说几乎所有的情况都是因为某些Git命令知道他们的名字参数是分支或标签名称,而其他人则怀疑它。例如,master
知道你将给它一个分支名称,而不是标签名称,作为下一个参数。因此,它不使用六步解析过程,事实上,它要求您在创建新分支时不要使用完整的git branch
表单拼写分支名称。
refs/heads/
命令是最奇怪的,因为git checkout
(和任何标志)之后的位置参数被允许是分支名称,标记名称或解析为有效提交的任何内容。所以它似乎应该使用六步过程。如果您创建一个名为checkout
的分支和标记,但指向两个不同的提交,您可能希望X
检查标记的git checkout X
。实际上,它会检查分支。因此,虽然X
将尝试所有六个步骤,但它会比步骤3更早地尝试第4步。
(从技术上讲,当它尝试将名称作为分支名称时,它不会经历六步过程。相反,它只是首先尝试将其作为分支名称。如果可行,git checkout
会将您放在分支上并完成。如果它失败了,那么代码会调用六步名称到ID解析器,只要提交哈希值回来,git checkout
就会在你提交的时候把你放在一个独立的HEAD上。所以它实际上尝试了两次步骤4,如同它是 - 但如果它第一次失败,它也很可能第二次失败。)
git checkout
works当你运行git clone
时,你有Git:
git clone url
以创建一个空的Git存储库。git init
来创建一个遥控器。这个遥控器的名字是你用git remote add
旗帜选择的任何东西,但是如果你没有选择它,那就是-o
。此新遥控器的URL是您为origin
提供的URL。git clone
设置一些默认的refspecs。实际的refspecs取决于命令行标志,但典型的标准是git fetch
。请注意这与我们用于+refs/heads/*:refs/remotes/origin/*
的refspec类似。配置此远程的符号HEAD,就像git push
一样。运行由其他命令行标志指定的任何其他git remote set-head
命令。git config
。这使用在步骤3中创建的远程和在步骤4中设置的refspec。git fetch
。此步骤的name参数取决于命令行标志和从其他Git获取的信息。请参阅下文了解详情。第6步将你的新克隆放在git checkout name
上,或者也许放在master
上,如果你在这里选择像develop
这样的话,甚至根本就没有分支。如果第6步让你进入你的v2.1
分支,这就是创建你的master
分支的原因。如果第6步让你拥有你的master
分支,这就是创建你的develop
分支的原因。如果第6步让你有一个独立的HEAD,你的Git不会创建任何分支!
如果您愿意,可以使用develop
指定最后一个克隆步骤应使用的名称。如果你这样做,其他Git说什么都不重要,当然除了git clone -b name
必须匹配其中一个名字。但是如果你不使用name
论证,那么 - 只有那时 - 其他Git说的很重要。
另一个Git存储库是一个Git存储库。这意味着其他Git存储库 - 为了简单起见,我们将其称为服务器存储库 - 具有-b
。服务器存储库中的HEAD
告诉在服务器存储库中检出哪个分支。如果服务器存储库是HEAD
存储库,它没有工作树,所以它的--bare
有点无关紧要。但它仍然有一个,这意味着服务器仍处于打开状态,除非服务器的Git处于分离的HEAD模式(这是可能的)。
当你的Git调用服务器Git时,你的Git可以向服务器询问的一件事是:你在哪个分支?也就是说,你的Git可以向服务器询问服务器的HEAD
。如果你在HEAD
期间未能为-b
指定一个选定的分支,那么这就是你的Git将用于你的git clone
的名称。
这也是你的Git将用于你的git checkout
的名字,以及你的git remote set-head origin --auto
将自动设置为你的git clone
的名称。因此,服务器的origin/HEAD
设置是HEAD
时间origin/HEAD
副本的默认设置,也是最后一步克隆git clone
命令的默认设置。
这就是它真正的好处。如果你在git checkout
时用-b
覆盖它,那意义无关紧要,因为git clone
无论如何都是无用的,这个意义也无所谓。
不要担心origin/HEAD
。这毫无用处。它对你没有任何好处。
不要担心服务器存储库中的origin/HEAD
。它确实会影响新的克隆,但前提是克隆的人不会选择分支。如果你想设置它,你可以这样做,但服务器允许。 (不同的Web服务有不同的方法来设置或更改它。)
最后,关于这个问题:
我们在GitHub和Jenkins之间使用webhook
我对您使用的特定插件一无所知。詹金斯的文档有所不同:其中一些有点用处,大部分都似乎缺失了,其中一些似乎是完全错误的。一般来说,Jenkins从您使用的任何托管服务器获取通知,发生了某些事情,然后您编写了解码发生的事件的代码。但是这部分:
如何获取推送事件发生的分支名称
这是一个根本不好的问题,因为没有必要的分支名称 - 例如我们可能只将HEAD
添加到标记中 - 如果有分支名称,可能会有许多分支名称,并且它们可能已经更改了哈希ID,或不。要问的正确问题是让Jenkins启动一些管道是否合适。我无法回答这个问题,但这是您提出正确问题的指南。