如何列出当前正在验证(在VSTS中)的请求中更改的所有文件?

时间:2018-11-28 18:10:08

标签: git

我有一个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 = b00bf1df0B = 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不会返回任何内容。

2 个答案:

答案 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 GH不在您的存储库中,则 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,所以至少可以将其用作心理模型。


最简单的情况:A = O,具有快速前进的潜力

假设图形确实看起来像这样:

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 GC匹配;哈希ID有所不同:GitHub已经制作了G'G的副本,尽管没有必要制作这样的副本。 (我曾经希望GitHub根本不制作这些副本。其他服务可能没有。)原始提交不会进入;副本进去了。

如果您使用压扁并合并按钮,则会得到以下提示:

G

其中{{1}的 parent C,而...--D--E--F--A--S <-- B content S匹配究竟。同样,提交AS本身不会进入存储库:只有C的内容进入(因为“ squash”提交中的新快照提交G)。 / p>

定义您想要的东西

现在您知道,拉取请求实际上是对分支名称进行移动的请求,从现在的位置(C)到从他们请求的提交派生的内容( C),或者通过添加新的合并提交S,或者通过添加新的squash-merge(普通的单亲非合并提交)A,或者通过复制一些或他们所有的提交。

您是否应该接受他们的拉取请求,取决于您在GitHub上单击的按钮,或者您使用的是其他任何东西(Bitbucket,GitLab?可能是什么),无论系统提供了什么,实际上会发生什么。由您决定实际上会发生什么。

然后,知道实际会发生什么,由您来决定如何比较放入存储库中的提交-可能尚未实际存在的提交!提交您的存储库中已经 are 的内容。您要比较CM的内容吗?假设S的哈希ID可用,您是否想将CA的内容进行比较?或者,您是否想仔细查看与父对象相比,每个每个提交将执行的操作,即使这些提交实际上还不存在?

显然,最后一个是最困难的:但是这些新提交的产生遵循一个定义明确的过程,因此要找出它们将包含的内容,一旦它们存在,您可以自己创建自己存储库,用同样的方式,如果您接受拉取请求,您的Web服务将在明天创建它们。需要注意的是,如果您这样做执行此操作(如果您预测他们明天将要执行的操作),然后同意您明天点击按钮,那么明天分支C会发生什么情况指向O以外的其他提交?

如果您选择了最后一个选项,即根据将发生的事情接受,您将需要围绕整个操作建立某种流程,以确保会发生什么事件与发生事件相同。也有很多方法可以实现这一目标,但都不是完美的。

实现您想要的

一旦定义了您想要的内容,您仍然必须实现。对于GitHub而言,这相对简单。 (我不确定您将对Bitbucket或其他系统执行什么操作。)首先,使用OB和任何父提交的副本复制到自己的存储库克隆中它缺少你。

让我们假设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/BC,而无需查看任何中间提交),那么将要修改的文件是按以下方式列出的文件:

refs/heads/pr123

但是,如果您还希望检查中间提交,则还有更多工作要做。

如果处于 merge 情况下,事情将变得更加复杂,因为-即使您只是将最终结果与单个提交进行比较-现在,您必须决定是否比较提交AC或其他任何东西,例如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就是该标签,而不是分支。对于将在没有人工监视警告消息的情况下运行的脚本,最好拼写全名:pr123pr123。您甚至可以将其解析为哈希ID,然后再使用哈希ID,因为哈希ID永远不会改变。

答案 1 :(得分:0)

我认为您应该使用...而不是..