如何列出当前正在验证(在VSTS中)的“拉取请求"中更改的所有文件? [英] How to list all the files changed in the Pull Request being currently validated (in VSTS)?
问题描述
我有一个PR验证版本,我想列出PR中更改的所有文件以及状态.
在每个构建中同步源.
因此,在合并PR更改之前,源位于版本A
(通常为origin/master
).
让我将PR合并提交指定为B
.
我当前的实现调用 并且确实,所讨论的PR有一个提交- 正如我其他帖子所显示的, 我相信使用 基本问题是该问题的格式不正确: ...列出PR中所有已更改的文件以及状态 实际上,拉取请求是以下形式的请求:请更改分支名称 暂时假设它提供所有三个项目:分支名称 现在,关于提交哈希ID的第一件事是它指定一个特定的提交,并且每个提交都是所有文件的完整快照.这根本不是一组更改!这只是一种状态,就像宣布今天的外面的温度是68°F(20°C).就其本身而言,这并不能告诉您昨天或上周的情况.要将状态转换为更改,必须选择其他状态进行比较.如果昨天的温度为77˚F(25˚C),则变化为9˚F(5˚C). 我们对Git中的提交执行相同的操作:我们选择一个状态(例如 但这不是关于提交的唯一内容.每个提交还记录零个或多个 parent 提交哈希ID(通常为1),第二个最常见的是合并提交2. (零位父母表示该提交是 root 提交;对于第一次提交,每个存储库中通常只有一个.三个或多个是章鱼合并.) 或者,它可能更简单: 其中 (请求总计为请快退" B,以便提交 让我们再次看一下该图: 至少在GitHub上,如果您使用默认类型的合并拉取请求",则GitHub要做的就是添加 new 提交-我们将其称为 但是GitHub还提供了两种其他方式来接受此请求,每种方式都有不同之处.如果您的存储库中尚未存在提交 同时 squash and merge 选项产生: 如果GitHub已创建 1 GitHub进行合并的方式不是通过使用 假设图形确实看起来像这样: ,以便 ,但是提交 如果使用合并按钮的 rebase and merge 模式,则会得到以下信息: 其中 如果您使用 squash and merge 按钮,则会得到以下提示: 其中 现在您知道pull请求实际上是对 move 分支名称的请求,从现在的位置( 您是否应该接受他们的拉取请求,取决于您在GitHub上单击的按钮,或者您使用的是其他任何东西(Bitbucket,GitLab或其他),无论系统提供什么,实际上会发生什么.由您决定实际上会发生什么. 然后,知道实际会发生什么,由您来决定如何比较将放入存储库中的提交-可能尚未实际存在的提交!提交您的存储库中已经 are 的内容.您想将 显然,最后一个是最困难的:但是这些新提交的产生遵循一个定义明确的过程,因此要找出它们将包含的内容,一旦它们存在,您可以自己创建自己如果您接受拉取请求,则您的Web服务将在明天以相同的方式创建存储库.需要注意的是,如果您这样做执行此操作(如果您预测他们明天将要执行的操作),然后同意您明天将单击该按钮,那么如果明天分支 如果您选择了最后一个选项,即根据将发生的事情接受,您将需要围绕整个操作建立某种流程,以确保会发生什么事情事件与发生事件相同.也有很多方法可以实现这一点,但没有一种是完美的. 一旦您定义了所需的内容,您仍然必须实现.对于GitHub而言,这相对简单. (我不确定您将对Bitbucket或其他系统执行什么操作.)首先使用 让我们假设 您现在有了一个名为 现在很容易判断 在简单的情况下,无论您使用哪种方法来接受拉取请求,最终指向 但是,如果您还希望检查中间提交,则还有更多工作要做. 如果处于 merge 情况下,事情将变得更加复杂,因为-即使您只是将最终结果与单个提交进行比较-现在,您必须决定是否比较提交 如果要做要使用实际的合并基数,则此处的三点语法很有用.但是,由于旧版本Git中的小错误,我建议在此处运行 (拒绝复杂的请求请求通常是最明智的选择,或者至少是最简单的做法,告诉编写它们的人说,他们必须重新处理他们的请求请求,这样就不需要任何特殊的/特别的合并. ) 2 通常,如果远程跟踪名称 I have a PR validation build that I want to list all the files changed in the PR along with the status. The sources are synced on each build.
So, before the PR changes are merged, the source is at revision My current implementation calls So, what is the correct way? Note, that the Pull Request may contain several commits with at least one merge commit - I am pretty sure there is a pure Git way to do it and there is no need to execute Restful API against the TFS server to inspect the Pull Request object. EDIT 1 Let Given (I am using Powershell): And indeed, the PR in question has one commit - As my other post shows, I believe using The fundamental problem is that the question is ill-formed: ... list all the files changed in the PR along with the status A pull request is, in effect, a request of the form: Please change branch name Let's assume for the moment that it provides all three items: a branch name Now, the first thing about a commit hash ID is that it designates one particular commit, and each commit is a complete snapshot of all files. It's not a set of changes at all! It's just a state, like declaring that the temperature outside today is 68˚F (20˚C). By itself, this tells you nothing about what it was yesterday or last week. To turn a state into a change, you must pick some other state to compare it to. If it was 77˚F (25˚C) yesterday, the change is 9˚F (5˚C). We do the same thing with commits in Git: we pick one state—such as But that's not the only thing about a commit. Each commit also records zero or more parent commit hash IDs—usually exactly 1, and the next most common is 2 for merge commits. (Zero parents means the commit is a root commit; usually there's just one of these per repository, for the very first commit. Three or more is an octopus merge.) The parents of Or, it could be simpler: where (with the request amounting to please "rewind" B so that commits Let's look at this graph again: On GitHub, at least, if you use the default kind of "merge pull request", what GitHub will do is add a new commit—let's call it But GitHub also offers two other ways to accept this pull request, each of which does something different. If commits while the squash and merge option produces: where 1The way GitHub makes a merge is not by using Suppose the graph really does look like this: so that the current value of but the contents of commit If you use the rebase and merge mode of the merge button, you get this: where the If you use the squash and merge button, you get this: where the parent of Now you know that the pull request is really a request to move the branch name, from where it is now ( What will actually happen, should you accept their pull request, depends on the button you click on GitHub, or if you're using something else (Bitbucket? GitLab? whatever it may be), whatever that system provides. It's up to you to figure out what will actually happen. Then, knowing what will actually happen, it's up to you yet again to figure out how to compare the commits that will go into your repository—commits that may not actually exist yet!—to the commits that already are in your repository. Do you want to compare the contents of The last is, obviously, the hardest: but the production of these new commits follows a well-defined process, so to find out what they will contain, once they do exist, you can simply create them yourself, in your own repository, in the same way your web service will create them tomorrow, should you accept the pull request. The caveat here is that if you do do this—if you project what they will do tomorrow—and then agree that you will click the button tomorrow, what happens if, tomorrow, branch If you do choose this last option, of accepting based on what would happen, you will need to build some sort of process around the whole operation to make sure that what would happen remains the same as what does happen. There are many ways to achieve that as well, none of which are perfect. Once you have defined what you want, you still have to achieve it. This is relatively straightforward for GitHub. (I'm not sure what you would do for Bitbucket or other systems.) You will start by using Let's assume that You now have a branch named It's now easy to tell whether In the simple case, regardless of which method you use to accept the pull request, the contents of final commit to which But if you wish to inspect intermediate commits as well, you have more work to do. If you're in a merge case, things become even more complex, since—even if you're just going to compare the end-result to a single commit—you must now decide whether to compare to commit If you do want to use the actual merge base, this is where the three-dot syntax can be useful. However, due to minor bugs in older versions of Git, I'd advise running (It's often wisest, or at least simplest, to just reject complicated pull requests, telling whoever authored them that they must rework their pull request such that it does not require any special / fancy merging.) 2Typically, if you have remote-tracking name 这篇关于如何列出当前正在验证(在VSTS中)的“拉取请求"中更改的所有文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!git diff-tree --name-status -r -M A..B
,但作为b7d9617fc
,其中81317ea59
是PR合并提交(即它是B
)git diff-tree --name-status -r -M b00bf1df0..81317ea59
是不正确的....
也是不正确的,的确如此:git diff-tree --name-status -r -M b00bf1df0...81317ea59
不返回任何内容.
B
,以便与其指向更改时指向的任何提交,而不是指向它所指向的任何提交提交C
代替.您可以根据自己的喜好来执行此操作,但是可以通过自己的合并提交来完成.这种请求请求可能会也可能不会—很难说,因为请求请求不是Git本身的一部分,而是由各种Web服务提供的附加组件,并且每个Web服务都可以实现此实现,但是它们一样-包括以下形式的信息:顺便说一句,当我要求您进行更改时名称B
到哈希ID C
的值,是哈希ID O
. B
,旧的提交哈希ID O
和请求的提交哈希ID C
.我们还要声明 B
的实际哈希值当前是 A
.也许 A
= O
,也许不是. (如果 O
未包含在拉取请求中,那并不是致命的,但是将由您自行决定合适的替代方法,并定义其所有工作方式,依此类推.)关于提交的知识
C
)并将其与以前的状态进行比较.但是我们只是说 actual 的先前状态是 A
,而 recorded 的先前状态是 O
.如果将 C
与 O
进行比较,则得到的答案与将 C
与进行比较的答案不同. A
,当然,除非 A
= 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
和O
是相同的提交.甚至它可能是删除某些提交的请求,尽管某些Web服务不允许这样做,或者如果您使用它们的接受请求"接口则不采取任何措施,而我们只作画即可:>
...--C--O--A <-- B
A
和O
消失).如果需要另一个合并怎么办?
...--D--E--F--O--A <-- B
\ \
G--H--C <-- (pull requested at C)
M
-其快照是通过运行 new git merge
(在GitHub上) 1 形成的,即使C
本身是合并提交. M
中的快照将是通过合并更改而产生的快照.最终产品将是:...--D--E--F--O--A--M <-- B
\ \ __/
G--H--C
G
,H
和C
,则 rebase and merge 选项将生成以下图形:...--D--E--F--O--A--G'-H' <-- B
...--D--E--F--O--A--S <-- B
M
,则S
具有M
会具有的内容.
git merge
,至少不是从字面上看,因为没有办法处理冲突.如果存在合并冲突,GitHub甚至不提供制作M
的权限.但是效果是好像 GitHub运行了文字git merge
,所以至少可以将其用作心理模型.
最简单的情况:A = O,具有快速前进的潜力
...--D--E--F--A <-- B
\
G--C <-- (pull requested at C)
B
的 current 值与 B
old 值相同>当时发出请求的人发出了请求.也就是说,我们有 A
= O
.如果您在GitHub上使用默认的合并"按钮,则会得到以下信息:...--D--E--F--A------M <-- B
\ /
G--C
M
的内容将与提交C
的内容完全匹配,这在几种方面都有帮助....--D--E--F--A--G'-C' <-- B
G'
和C'
提交是请求请求的G
和C
提交的副本:快照匹配,甚至是父提交ID G'
与G
匹配;哈希ID有所不同:GitHub已经复制了G
和C
的副本,尽管没有必要进行复制. (我曾经希望GitHub根本不制作这些副本.其他服务可能没有.)副本放进去....--D--E--F--A--S <-- B
S
的 parent 是A
,而S
的 content 恰好与C
的匹配.再次,提交G
和C
本身不会进入存储库:仅进入C
的内容(如"squash"中的新快照提交S
).定义您想要的东西
A
)到从他们请求的提交派生的内容(M
,或者通过添加新的squash-merge(普通单亲非合并提交)S
,或者通过复制其部分或全部提交来实现.C
的内容与A
的内容进行比较吗?假设O
的哈希ID可用,您是否想将C
与O
的内容进行比较?或者,您是否想仔细查看与它们的父代相比,每一个的新提交会做什么,即使这些提交实际上还不存在?B
指向该行会发生什么情况A
以外的其他提交?实现您想要的
git fetch
将提交C
的副本复制到自己的存储库克隆中,并且任何父提交都具有以下内容:缺乏.origin
是GitHub存储库的名称,并且拉取请求为#123.然后: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
的分支,其尖端提交为commit C
,以及您的远程跟踪名称origin/B
指向提交A
.A
是否是C
的祖先,即,是否最简单的情况有效.这个特殊的测试是在bash中完成的(不确定PowerShell):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
origin/B
指向的最终提交的内容都将与现在指向的提交C
的内容匹配由refs/heads/pr123
. 2 编写.如果您确定要测试的更改是总体摘要更改,即从A
到C
,而无需查看任何中间提交-则将被修改的文件是按以下方式列出的文件:git diff-tree -r --name-status [options] refs/remotes/origin/B refs/heads/pr123
A
,O
或其他任何内容,例如A
和C
的当前当前合并基数,无论可能是什么提交.git merge-base --all refs/heads/B refs/heads/pr123
并收集其输出.这将列出一定数量的哈希ID,理想情况下仅列出一个:如果仅获得一个,则表示合并基础提交.如果获得多个,则它们是 all 个候选合并基础,默认的git merge -s recursive
策略将首先合并所有合并基础,然后将所得提交用作合并的合并基础. /p>
origin/B
和分支名称pr123
指向所需的提交,则可以使用这些名称.但是,Git用来将名称转换为哈希ID的方法是一个六步过程,概述在四个处下降; 用作远程跟踪"名称是步骤 5 .实际上,这意味着如果同时具有分支 pr123
和 tag pr123
,则名称pr123
是指标签,而不是分支.对于将在没有人工监视警告消息的情况下运行的脚本,最好拼写全名:refs/remotes/origin/B
和refs/heads/pr123
.您甚至可以将其解析为哈希ID,然后再使用哈希ID,因为哈希ID永远不会改变.A
(typically origin/master
).
Let me designate PR merge commit as B
. git diff-tree --name-status -r -M A..B
, but as 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? shows this is incorrect.B
. But there could be more merge commits there.A = b00bf1df0
and B = 81317ea59
. C:\Dayforce\tip [master ≡]> git log --format="%h" b00bf1df0..81317ea59
81317ea59
b7d9617fc
C:\Dayforce\tip [master ≡]>
b7d9617fc
with 81317ea59
being the PR merge commit (i.e. it is B
)git diff-tree --name-status -r -M b00bf1df0..81317ea59
is incorrect....
is incorrect too, indeed: git diff-tree --name-status -r -M b00bf1df0...81317ea59
returns nothing.
B
so that instead of pointing to whatever commit it points to at the time you get around to changing it, it points to commit C
instead. Do this however you like, but perhaps by making your own merge commit. This pull-request thing may or may not—it's hard to say since pull requests are not part of Git itself, but rather add-ons provided by various web services, and each web-service can implement this however they like—include information of the form: And by the way, when I asked you to change the value of name B
to hash ID C
, the value was hash ID O
.B
, an old commit hash ID O
, and a requested commit hash ID C
. Let's also state that B
's actual hash value is currently A
. Maybe A
= O
, and maybe not. (If O
is not included in the pull request, that's not really fatal, but it will be up to you to find a suitable substitute, and define how it all works and so on.)What to know about commits
C
—and compare it to some previous state. But we just said that the actual previous state is A
, while the recorded previous state is O
. If you compare C
vs O
, you'll get a different answer than if you compare C
vs A
, unless of course A
= O
.C
are each commits in their own right, which also have parents, and so on. Taking the parents into account, what we really have could be something like this:...--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
and O
are the same commit. Or it could even be a request to remove some commit(s), though some web services would not allow this, or would take no action if you use their "accept request" interface(s), but let's just draw it:...--C--O--A <-- B
A
and O
vanish).What if another merge is called-for?
...--D--E--F--O--A <-- B
\ \
G--H--C <-- (pull requested at C)
M
—whose snapshot is formed by running a new git merge
(on GitHub),1 even though C
itself is a merge commit. The snapshot in M
will be that produced by combining changes. The end product will be:...--D--E--F--O--A--M <-- B
\ \ __/
G--H--C
G
, H
, and C
are not already in your repository, the rebase and merge option produces instead this graph:...--D--E--F--O--A--G'-H' <-- B
...--D--E--F--O--A--S <-- B
S
has the contents that M
would have, if GitHub had made M
.
git merge
, at least not literally, as there is no way to handle conflicts. GitHub won't even offer to make M
if there would be merge conflicts. But the effect is as if GitHub ran a literal git merge
, so you can use this as a mental model, at least.
The simplest case: A=O, potential for fast-forward
...--D--E--F--A <-- B
\
G--C <-- (pull requested at C)
B
is the same as the old value of B
at the time the person making the pull-request made it. That is, we have A
= O
. If you use the default "merge" button on GitHub, you will get this:...--D--E--F--A------M <-- B
\ /
G--C
M
will match the contents of commit C
exactly, which helps in several ways....--D--E--F--A--G'-C' <-- B
G'
and C'
commits are copies of the pull-requester's G
and C
commits: the snapshots match, and even the parent commit ID of G'
matches that of G
; what's different is the hash IDs: GitHub has made copies of both G
and C
even though there's no point to making such copies. (I, for one, wish GitHub did not make these copies at all. It's possible that other services don't.) The original commits don't go in; the copies go in, instead....--D--E--F--A--S <-- B
S
is A
, while the content of S
matches that of C
exactly. Again, commits G
and C
themselves does not enter the repository: only C
's content goes in (as the new snapshot in "squash" commit S
).Defining what you want
A
) to something derived from the commit they've requested (C
), perhaps by adding a new merge commit M
, perhaps by adding a new squash-merge (ordinary single-parent non-merge commit) S
, or perhaps by copying some or all of their commits.C
to those of A
? Do you want to compare C
to the contents of O
, assuming the hash ID of O
is available? Or do you want to look carefully at what each new commit would do compared to its parent(s), even if none of those commits actually exist yet?B
points to some commit other than A
?Achieving what you want
git fetch
to obtain, into your own clone of your repository, copies of commit C
and any parent commits it has that you lack.origin
is the name of the GitHub repository, and that the pull request is #123. Then: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
whose tip commit is commit C
, along with your remote-tracking name origin/B
pointing to commit A
.A
is an ancestor of C
, i.e., whether the simplest case is in effect. This particular test is done this way in bash (not sure about PowerShell):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
origin/B
points in the end will match the contents of commit C
, as pointed-to right now by refs/heads/pr123
.2 If you've decided that the change you want to test is the overall summary change—that is, from A
to C
, without looking at any intermediate commits—then the files that will be modified are those listed by:git diff-tree -r --name-status [options] refs/remotes/origin/B refs/heads/pr123
A
, O
, or something else entirely, such as the actual current merge base of A
and C
, whatever commit that may be.git merge-base --all refs/heads/B refs/heads/pr123
here and collecting its output. This will list some number of hash IDs, ideally just one: if you get just one, that's the merge base commit. If you get more than one, they are all candidate merge bases, and the default git merge -s recursive
strategy would first merge all the merge bases, then use the resulting commit as the merge base for the merges.
origin/B
and branch-name pr123
pointing to the desired commits, you can just use those names. However, the method that Git uses to turn a name into a hash ID is a six-step process, outlined in the gitrevisions documentation, and "use as branch name" is way down at step four, after "use as tag name"; "use as remote-tracking" name is step five. What this means in practice is that if you have both branch pr123
and tag pr123
, the name pr123
refers to the tag, rather than the branch. For scripts, which will run with no human monitoring warning messages, it's wise to spell out the full names: refs/remotes/origin/B
and refs/heads/pr123
. You can even resolve them once, to hash IDs, and then use the hash IDs everywhere, since the hash IDs never change.