这两个git fetch命令有什么区别?

时间:2017-02-26 10:43:48

标签: git github

命令1:git fetch origin refs/pull/ID/merge:BRANCHNAME

命令2:git fetch origin pull/ID/head:BRANCHNAME

两者都用于将PR签出为本地分支。

我正在使用持续集成工具,该工具在内部使用命令1签出PR,但在某些情况下,它失败并显示错误消息fatal: Couldn't find remote ref refs/pull/11/merge

请帮我理解错误原因

编辑1:

我的实际问题是,如果PR来自分支并且存在冲突,我的CI无法获取PR的代码。

如果没有冲突的相同PR工作正常。

分支级别的PR工作正常,有或没有冲突。

这是我的CI正在做的以获取PR的代码。

来自fork的PR

没有冲突。

git clone --no-checkout https://mygithubenterprise.com/org/repo .
git cat-file -e c14714a5e9a33bd64f94f6af8ebc81fe64223c38
git fetch -t https://mygithubenterprise.com/org/repo refs/pull/173/merge
git reset --hard c14714a5e9a33bd64f94f6af8ebc81fe64223c38 --
git branch -M refs/pull/173/merge
git reset --hard c14714a5e9a33bd64f94f6af8ebc81fe64223c38 --
# done checking out code
来自带有冲突的fork的

for PR。

git clone --no-checkout https://mygithubenterprise.com/org/repo .
git cat-file -e 59ca091ee41a0b1170955378c324d2036ff5406c
git fetch -t https://mygithubenterprise.com/org/repo refs/pull/171/merge
fatal: Couldn't find remote ref refs/pull/171/merge

我怎样才能避免这个问题,即使有冲突,也要结帐PR。

1 个答案:

答案 0 :(得分:0)

命令1请求完全限定名称refs/pull/ID/merge,命令-2请求不完全限定名称pull/ID/head。如果两个名称都以head结尾或两者都以merge结尾,则它们之间没有实际差异,因为 - 如gitrevisions中所述(点击链接查看六个步骤),如果Git找不到.git/pull/11/head(假设ID为11且后缀为head),则接下来会查找.git/refs/pull/11/head.git/pull/永远不会存在。< / p>

但名称​​不是相同的。一个人要求refs/pull/11/head,另一个要求refs/pull/11/merge。您必须在给定的名称下查找pull请求。 创建拉取请求的人给了该请求它的名字;您必须使用相同的名称。

(对于我自己,如果我要使用这样的名字,我总是使用完全限定的表格,即refs/pull/ID/suffix,而不是剥离refs/的版本。 Git在六个gitrevisions解决步骤的第1步停止,如果非限定名称以infologs等目录名开头,则不会发生错误。)

注意:根据https://gist.github.com/piscisaureus/3342247中的一些讨论条目,GitHub使用refs/pull命名空间的方式是将原始请求本身放在ID/head下,以及合并的结果(假设合并有效)在ID/merge中。我并不完全清楚GitHub如何使用headmerge名称,但我可以根据讨论做出一些好的猜测。

重新&#34;编辑1&#34;

似乎是这样的情况,当在GitHub上调用pull请求机制时,如果pull请求干净地合并 1 ,就Git而言,GitHub对合并结果进行合并提交,以及ID/merge名称的标签。如果干净地合并,GitHub将丢弃尝试的合并,并且创建相应的ID/merge名称。

换句话说,只需将标签ID/pull附加到某人已推送到GitHub的某个特定提交,即可形成拉取请求。例如,一些pull-request user-let称他为R for Request-可能会推送三个提交到一些现有的主分支(这是 R 中的视图&#39; s库):

...--o--o             <-- main-branch
         \
          o--o--o     <-- R

主分支可能会或可能不会附加额外的提交,例如,可能,但 ,这是的视图 GitHub 存储库):

...--o--o-------o     <-- main-branch
         \
          o--o--o     <-- R

在R之前甚至之后,他都会努力创建这个分支R

此时,有问题的用户点击&#34;发出拉取请求&#34;。当他这样做时,他提供了他希望某个其他人的分支的名称 - 让其他人称为管理者,因为这个其他人管理主分支 - 合并R&# 39;提交进入。

GitHub现在尝试合并,它通过运行git merge --no-ff来完成。 2 即使可以进行快进合并,这也会强制进行真正的合并提交 。如果真正的合并成功(再次参见脚注1),则会创建一个新的合并提交:

...--o--o---------o     <-- main-branch
         \         \
          \         o   <-- [one name goes here]
           \       /
            o--o--o     <-- R, [another name goes here]

如果合并失败,GitHub将放弃合并尝试,这将离开我们:

...--o--o-------o     <-- main-branch
         \
          o--o--o     <-- R, [another name goes here]

请注意,这些之间的唯一区别是最终合并提交的存在以及额外名称。

这两个名称是refs/pull/ID/head,它指向与R相同的提交,而refs/pull/ID/merge指向合并提交。当且仅当自动合并成功时,才会创建第二个merge - 后缀名称​​。

这意味着您可以使用是否存在merge - 后缀名称来判断GitHub是否自动创建了合并。如果他们这样做,它还会告诉您合并了哪些提交,因为这些是相应提交的两个父级。这不足以识别实际的分支名称,因为图形看起来像这样:

...--o--o---------o     <-- main-branch, second-name, third-name
         \         \
          \         o   <-- refs/pull/11/merge
           \       /
            o--o--o     <-- R, fifth-name, refs/pull/11/head

虽然refs/pull/11/merge^1指向与main-branch相同的提交,但指向与分支名称second-name和分支名称{{1}相同的提交}}。因此,根本不知道管理器应该如何知道,至少从这些信息中,哪个分支是拉取请求的目标,即哪个分支应该结束指向同一个合并提交。

当然,正如脚注2所述,可以告诉GitHub制作壁球&#34;合并&#34;而不是真正的合并。我没有看到GitHub本身曾进行过快速合并,但我不知道它不会(我自己只使用GitHub)。但是,似乎GitHub总是在拉取请求时进行真正的合并,即使Manager稍后会出现并从请求中进行压缩合并。

更多信息,包括在管理器合并或关闭拉取请求后处理两个third-name名称空间标签,请参阅上面汇总的讨论。

1 所有这些都意味着Git本身没有发现任何冲突。生成的合并必然正确。如果自动化测试可用(它们在某些与GitHub集成的系统上),那些自动化测试可以检测到至少一些误合并,Git认为事情没有问题,但实际上并不好。当然,这些自动化测试的可靠性取决于它们的完整性和编写它们的人的技能。

2 当根据某人的拉取请求实际将合并添加到分支时,使用GitHub接口的人 - 在我们的示例中的经理 - 可以选择进行压制&#34; merge&#34;,这是一个单一的提交,其内容与之前成功的自动合并相同,但其只是一个父:

refs/pull

...--o--o---------o--o <-- main-branch \ \ \ o <-- refs/pull/11/merge \ / o--o--o <-- R, refs/pull/11/head 上的最后一次提交在 snapshot 方面与main-branch指向的提交相同,但不是合并提交且未连接到三个提交以refs/pull/11/merge分的结尾。