比较强制推拉请求的新旧版本

时间:2016-09-25 08:13:25

标签: git github pull-request git-diff

我的同事经常会对开放式拉取请求进行一些更改,将其本地分支重新绑定到基本分支 - 通常也会将其更改压缩到以前的提交中 - 并强制推送。

如何查看旧版PR和新版PR之间的变化?

我想我可以在PR首次提出时执行git pullgit checkout $BRANCH_NAME,然后在PR更新后再git fetch然后git diff $BRANCH_NAME..origin/$BRANCH_NAME - 但这也会显示已引入基本分支(通常为主分支)并通过rebase引入PR的更改。是否有可能消除噪音并只显示PR本身的变化?

5 个答案:

答案 0 :(得分:8)

结帐this回答另一个想要做与您想要达到的目标非常相似的问题。

它描述了你的情况:

newcommit -> the new pull request commit
oldcommit -> the old pull request commit
upstream -> the base branch commit the new pull request is based on

现在这样做:

git commit-tree newcommit^{tree} -p oldcommit -p upstream -m "message"
git show <commit id returned by previous command>

这个想法是,commit-tree会伪造oldcommitupstream生成newcommit树之间的合并,因此恰好包含newcommit的代码。 它根本不会修改您当前的分支,它会创建一个新的无头提交并为您提供其ID。 这意味着git show会将每个修改列为冲突解决方案,这是新PR和旧PR之间的确切差异。

为了能够做到这一点,你需要在你的git存储库中的某个地方使用以前的PR(如果已经执行了强制推送,git历史记录已经被重写并且除非你在你的电脑上或者你有它,否则无法恢复有权访问服务器reflog)。检查 VonC 答案,了解相关详情。

假设:

  • 基本分支:master
  • 你在当地有旧公关分支:$BRANCH_NAME
  • 远程分支中的新PR:origin/$BRANCH_NAME

你可以这样做:

# fetch locally upstream changes (origin/$BRANCH_NAME)
git fetch
# produce the fake merge commit
git commit-tree origin/$BRANCH_NAME^{tree} \
         -p $BRANCH_NAME \
         -p `git merge-base master origin/$BRANCH_NAME` \
         -m "message"
# see "fake" conflict resolution = difference between the two PR
git show <commit id returned by previous command>

git merge-base用于查找两个分支之间的共同祖先,在这种情况下,在基本分支中查找新PR所基于的提交,如果您愿意,可以直接编写提交ID

答案 1 :(得分:6)

  

旧版PR

您可以直接在GitHub上执行此操作:请参阅“Find committer of a force push on GitHub

  

点击“强制推送”链接会在两次提交之间显示 two dot comparison

原始答案:2016

仅在远程仓库的 reflog 中提供,其中包括分支强制推送的先前HEAD。 由于远程仓库是GitHub,因此您仍然可以通过查看推送事件来推断旧提交:请参阅“Does github remember commit IDs?”。

  

hat还会显示已引入基本分支(通常是主分支)的更改

更准确地说,您将始终与共同的祖先(包括来自基本分支的提交,如master)有差异

请参阅What are the differences between double-dot ".." and triple-dot "..." in Git diff commit ranges?

http://mythic-beasts.com/~mark/git-diff-help.png

因此,在您的情况下,您的强制推送分支在远程仓库中看起来像这样:

      x--x--x        (old branch in reflog)
     /
 m--M0--M--M   (master)
            \
             X--X--X (new branch forced push)

diff old_HEAD..newHEAD将包含来自基本分支的少量M提交,因为它们是共同祖先(M0)路径的一部分。

所以你可以比较一个强制推动的分支(假设你正在监视pushEvents并知道该分支的前一个HEAD)。
但是,如果没有共同的祖先路径,你就不能轻易地比较两个分支。

答案 2 :(得分:1)

自 Git 2.19 起,git range-diff 提供了一种比较重定位历史的好方法。当新历史记录具有相同的提交结构而只有很小的更改时,它会很好地工作(但如果新版本的拉取请求既有新的基础又有不同的提交分解,则它可能对您没有太大帮助)。它比较每个提交中的补丁并显示差异,并通过相当好的突出显示来区分上下文更改和补丁更改。

假设拉取请求已从 c1 重新定位到 c2,目标分支为 main,并且您有一个本地工作目录,其中 myrepo 指向带有拉取请求的 GitHub 存储库。您可以按如下方式下载提交并比较历史记录:

git fetch myrepo c1 c2
git range-diff main c1 c2

请注意,您需要拉取请求的旧提示的本地副本。 I don't know how to obtain the commit ID automatically;这就是 GitHub Web 界面在“... force-pushed the mywork branch from c1 to c2”中显示的内容。在我写的时候,我认为 GitHub 总是允许通过他们的 ID 获取提交,即使它们只出现在旧版本的拉取请求中(过去情况并非如此)。如果您不希望它从您的工作副本中被垃圾收集,请为提交指定一个分支名称。

如果在您已经审核过的部分之后有新的提交,将重新调整的部分与新的提交分开的一种方便的方法是搜索您审核过的最后一次提交的提交消息。在 bash/zsh 语法中:

git range-diff main {c1,c2}'^{/This is the commit message}'

对于更复杂的情况(例如,如果某些旧提交因为合并了同一子功能的不同实现而失去了相关性),您可以指定不同的起点:git range-diff OLD_START..OLD_END NEW_START..NEW_END

答案 3 :(得分:0)

我相信,按照此票证的建议,完全不可能获得旧版本的请求请求:https://github.com/isaacs/github/issues/999在该存储库中发布的用户为advised to contact GitHub support,因此GitHub支持可能已经回复了创建票证是不可能的。

这是Gerrit具有的GitHub拉取请求中缺少的主要功能,并且Gerrit用户严重错过了该功能。

答案 4 :(得分:0)

以下方法有效,但是对于大型存储库而言效率不高,因为已下载了整个存储库工作树:

repo=rossant/awesome-math
a=61e250
b=2b53ad
tmp=$(mktemp -d -p /tmp)
mkdir -p $tmp/{a,b}
curl -SL https://github.com/$repo/archive/$a.tar.gz | tar xz --strip-components=1 -C $tmp/a
curl -SL https://github.com/$repo/archive/$b.tar.gz | tar xz --strip-components=1 -C $tmp/b
git diff --no-index $tmp/{a,b}
rm -r $tmp

如果Github会-WhatIf common parameter,这可能会更简单,更精简,但事实并非如此