我有一个PR验证版本,我想列出PR中更改的所有文件以及状态。
在每个构建中同步源。
因此,在合并PR更改之前,源为修订版A
(通常为origin/master
)。
让我将PR合并提交指定为B
。
我当前的实现调用git diff-tree --name-status -r -M A..B
,但正如Why is the list of files for a range of commits different from the aggregation of the lists of files per commit in the same range?所示,这是不正确的。
那么,正确的方法是什么?请注意,拉取请求可能包含多个提交,其中至少有一个合并提交-B
。但是那里可能会有更多的合并提交。
我非常确定有一种纯粹的Git方法可以执行此操作,并且无需针对TFS服务器执行Restful API来检查Pull Request对象。
编辑1
让A = b00bf1df0
和B = 81317ea59
。
给出(我正在使用Powershell):
C:\Dayforce\tip [master ≡]> git log --format="%h" b00bf1df0..81317ea59
81317ea59
b7d9617fc
C:\Dayforce\tip [master ≡]>
并且确实,所讨论的PR有一个提交-b7d9617fc
,其中81317ea59
是PR合并提交(即B
)
正如我的其他帖子所显示的,git diff-tree --name-status -r -M b00bf1df0..81317ea59
是错误的。
我相信使用...
也是不正确的,的确如此:git diff-tree --name-status -r -M b00bf1df0...81317ea59
不会返回任何内容。
答案 0 :(得分:1)
基本问题是问题的形式不正确:
...列出所有在PR中更改的文件以及状态
实际上,拉取请求是以下形式的请求:请更改分支名称B
,以便不要指向更改时指向的任何提交,它指向提交C
。您可以根据自己的喜好来执行此操作,但可以通过自己的合并提交来完成。这种请求请求可能会也可能不会—很难说,因为请求请求不是Git本身的一部分,而是由各种Web服务提供的附加组件,每个Web服务都可以实现它们,但是它们一样,包括以下形式的信息:顺便说一句,当我要求您进行更改时值B
到哈希ID C
,值是哈希ID O
。
暂时假设它提供了所有三个项目:分支名称 B
,旧的提交哈希ID O
和请求的提交哈希ID C
。我们还要声明 B
的实际哈希值当前是 A
。也许 {A
= O
,也许不是。 (如果 O
未包含在拉取请求中,那并不是致命的,但是您将需要找到合适的替代品并定义其所有工作方式,依此类推。 )
现在,关于提交哈希ID的第一件事是它指定一个特定的提交,并且每个提交都是所有文件的完整快照。这根本不是一组更改!这只是一种状态,就像宣布今天的外面的温度是68°F(20°C)。就其本身而言,这不能告诉您昨天或上周的情况。要将状态转换为更改,必须选择其他状态进行比较。如果昨天的温度为25°C(77°F),则变化为5°C(9°F)。
我们对Git中的提交执行相同的操作:我们选择一个状态(例如 C
)并将其与先前的某个状态进行比较。但是我们只是说 actual 的先前状态为 A
,而 recorded 的先前状态为 {{1} } 。如果您将 O
与 C
进行比较,则得到的答案将与您比较 O
时得到的答案不同em> vs C
,当然,除非 A
= A
。
但这并不是提交的唯一内容。每个提交还记录零个或多个 parent 提交哈希ID(通常为1),第二个最常见的是合并提交2。 (零位父母表示该提交是 root 提交;对于第一次提交,每个存储库通常只有一个提交。三个或多个是章鱼合并。) O
的父母各自具有自己的权利,也有父母,依此类推。考虑到父母,我们真正拥有的可能是这样的:
C
或者,它可能更简单:
...--D--E--F--O--A <-- B
\ \
G--H--C <-- (pull requested at C)
其中...--D--E--F--A <-- B
\
G--C <-- (pull requested at C)
和A
是同一提交。甚至它可能是删除某些提交的请求,尽管某些Web服务不允许这样做,或者如果您使用它们的“接受请求”接口则不采取任何措施,但我们只需绘制一下即可:>
O
(请求总计为请“快退” B,以便使...--C--O--A <-- B
和A
消失。)
让我们再次看一下该图:
O
至少在GitHub上,如果您使用默认类型的“合并拉取请求”,则GitHub将要做的是添加 new 提交-我们将其称为...--D--E--F--O--A <-- B
\ \
G--H--C <-- (pull requested at C)
-其< em>快照是通过运行 new M
(在GitHub上)形成的, 1 即使git merge
本身是合并提交。 C
中的快照将是通过合并更改而产生的快照。最终产品将是:
M
但是GitHub还提供了两种其他方式来接受此请求,每种方式都有所不同。如果提交...--D--E--F--O--A--M <-- B
\ \ __/
G--H--C
,G
和H
不在您的存储库中,则 rebase and merge 选项将生成此图:
C
同时 squash and merge 选项产生:
...--D--E--F--O--A--G'-H' <-- B
其中...--D--E--F--O--A--S <-- B
具有S
拥有的内容,如果GitHub已完成M
。
1 GitHub进行合并的方式不是使用M
,至少不是从字面上看,因为没有办法处理冲突。如果存在合并冲突,GitHub甚至不会提出git merge
。但是效果是好像 GitHub运行了文字M
,所以至少可以将其用作心理模型。
假设图形确实看起来像这样:
git merge
,以便 ...--D--E--F--A <-- B
\
G--C <-- (pull requested at C)
的 current 值与 {{1}的 old 值相同} 发出请求的人当时发出了请求。也就是说,我们有 B
= B
。如果您在GitHub上使用默认的“合并”按钮,则会得到以下信息:
A
,但是提交O
的内容将与提交...--D--E--F--A------M <-- B
\ /
G--C
的内容完全匹配,这在几种方面都有帮助。
如果您使用合并按钮的 rebase and merge 模式,则会得到以下信息:
M
其中C
和...--D--E--F--A--G'-C' <-- B
提交是上拉请求者的G'
和C'
提交的副本:快照匹配,甚至父提交ID G
与C
匹配;哈希ID有所不同:GitHub已经制作了G'
和G
的副本,尽管没有必要制作这样的副本。 (我曾经希望GitHub根本不制作这些副本。其他服务可能没有。)原始提交不会进入;副本进去了。
如果您使用压扁并合并按钮,则会得到以下提示:
G
其中{{1}的 parent 为C
,而...--D--E--F--A--S <-- B
的 content 与S
匹配究竟。同样,提交A
和S
本身不会进入存储库:只有C
的内容进入(因为“ squash”提交中的新快照提交G
)。 / p>
现在您知道,拉取请求实际上是对分支名称进行移动的请求,从现在的位置(C
)到从他们请求的提交派生的内容( C
),或者通过添加新的合并提交S
,或者通过添加新的squash-merge(普通的单亲非合并提交)A
,或者通过复制一些或他们所有的提交。
您是否应该接受他们的拉取请求,取决于您在GitHub上单击的按钮,或者您使用的是其他任何东西(Bitbucket,GitLab?可能是什么),无论系统提供了什么,实际上会发生什么。由您决定实际上会发生什么。
然后,知道实际会发生什么,由您来决定如何比较将放入存储库中的提交-可能尚未实际存在的提交!提交您的存储库中已经 are 的内容。您要比较C
和M
的内容吗?假设S
的哈希ID可用,您是否想将C
与A
的内容进行比较?或者,您是否想仔细查看与父对象相比,每个每个提交将执行的操作,即使这些提交实际上还不存在?
显然,最后一个是最困难的:但是这些新提交的产生遵循一个定义明确的过程,因此要找出它们将包含的内容,一旦它们存在,您可以自己创建自己存储库,用同样的方式,如果您接受拉取请求,您的Web服务将在明天创建它们。需要注意的是,如果您这样做执行此操作(如果您预测他们明天将要执行的操作),然后同意您明天点击按钮,那么明天分支C
会发生什么情况指向O
以外的其他提交?
如果您选择了最后一个选项,即根据将发生的事情接受,您将需要围绕整个操作建立某种流程,以确保会发生什么事件与发生事件相同。也有很多方法可以实现这一目标,但都不是完美的。
一旦定义了您想要的内容,您仍然必须实现。对于GitHub而言,这相对简单。 (我不确定您将对Bitbucket或其他系统执行什么操作。)首先,使用O
将B
和任何父提交的副本复制到自己的存储库克隆中它缺少你。
让我们假设A
是GitHub存储库的名称,并且拉取请求是#123。然后:
git fetch
您现在有了一个名为C
的分支,其尖端提交是提交origin
,以及您的远程跟踪名称git fetch origin # update everything so that we have origin/B pointing to A, etc
git fetch origin refs/pull/123/head:refs/heads/pr123
指向提交pr123
。
现在很容易判断C
是否是origin/B
的祖先,即是否最简单的情况有效。这个特殊的测试是在bash中完成的(不确定PowerShell):
A
在简单的情况下,无论使用哪种方法接受拉取请求,最终A
指向的最终提交的内容都将与提交C
的内容相匹配-到if git merge-base --is-ancestor refs/remotes/origin/B refs/heads/pr123; then
echo "it's the simple case, yay"
else
echo "it's the merge case, boo"
fi
为止。 2 如果您确定要测试的更改是总体摘要更改 (即,从origin/B
到C
,而无需查看任何中间提交),那么将要修改的文件是按以下方式列出的文件:
refs/heads/pr123
但是,如果您还希望检查中间提交,则还有更多工作要做。
如果处于 merge 情况下,事情将变得更加复杂,因为-即使您只是将最终结果与单个提交进行比较-现在,您必须决定是否比较提交A
,C
或其他任何东西,例如git diff-tree -r --name-status [options] refs/remotes/origin/B refs/heads/pr123
和A
的实际当前合并基础,无论可能是什么提交。
如果要做要使用实际的合并基数,则此处的三点语法很有用。但是,由于旧版Git中存在一些小错误,建议您在此处运行O
并收集其输出。这将列出一定数量的哈希ID,理想情况下仅列出一个:如果仅获得一个,则表示合并基础提交。如果获得多个,则它们是 all 个候选合并基础,默认的A
策略将首先合并所有合并基础,然后将所得提交用作合并的合并基础
(拒绝复杂的请求请求通常是最明智的选择,或者至少是最简单的做法,告诉编写它们的人,他们必须重新处理他们的请求请求,这样就不需要任何特殊的/特别的合并。 )
2 通常,如果您具有指向所需提交的远程跟踪名称C
和分支名称git merge-base --all refs/heads/B refs/heads/pr123
,则可以使用这些名称。但是,Git用来将名称转换为哈希ID的方法是一个六步过程,概述在the gitrevisions documentation中,而在步骤 four 处,“用作分支名称”的方法很简单。 ,在“用作标签名称”之后; “用作远程跟踪”名称是步骤 5 。实际上,这意味着如果同时具有分支 git merge -s recursive
和 tag origin/B
,则名称pr123
就是该标签,而不是分支。对于将在没有人工监视警告消息的情况下运行的脚本,最好拼写全名:pr123
和pr123
。您甚至可以将其解析为哈希ID,然后再使用哈希ID,因为哈希ID永远不会改变。
答案 1 :(得分:0)
我认为您应该使用...
而不是..