由一组提交引起的差异审查

3
我希望查看仅两个提交之间的差异。
例如:
$ git log --oneline
0ff4567 fix bug #1, now really really really
1ff4567 fix bug #1 really
2ff4567 fix bug #2
3ff4567 fix bug #3
4234567 refactor code
5ff4567 fix bug #1
6234567 fix bug #4

我想只查看与bug #1相关的提交,即提交0ff45671ff45675ff4567
我不关心其他提交的差异。
有没有简单的方法可以做到这一点?
更新:我知道相关提交的列表。鉴于此列表,我希望获得一个单独的差异,更易于审查。

重新排序提交是否可行?如果这些提交是您自己的,并且您尚未推送它们,甚至可以将它们压缩成一个提交。请参阅https://dev59.com/2HE85IYBdhLWcg3whDzj - johnsyweb
不,不是这样的。它们已经被推送了。否则我就不会有问题了。 - Elazar Leibovich
然后我会 git clone repo temp_repo 并在临时副本中进行操作。 - johnsyweb
@Johnsyweb:不需要那样做 - 你只需要创建一个新的分支来进行变基。 - Mark Longair
@MarkLongair:确实如此,但这是一种便宜且简单的方式,可以在没有任何风险的情况下进行尝试。 - johnsyweb
2个回答

2
您可以使用--grep选项来过滤git log,它只会输出匹配特定正则表达式的提交记录。在您的情况下,可以这样做:
git log --oneline --grep='bug #1'

如果你想要查看每个提交引入的补丁,当然,你应该执行以下操作:
git log -p --grep='bug #1'

在下面的评论中,您解释说您真的想要一个补丁作为输出,该补丁表示这三个提交引入的补丁的累积效应。在这种情况下,您可以尝试以下方法之一:
  • 使用patchutils中的combinediff工具来组合差异。(这可能不起作用,具体取决于中间提交更改了什么。)
  • 创建一个临时的新分支,并使用交互式变基(可能带有巧妙构造的GIT_EDITOR环境变量中的命令)来重新排序和压缩提交。

稍微解释一下后者选项,这个脚本是基于Jefromi的一个("超级笨拙的")示例制作的:
#!/bin/sh

set -e

if [ $# -ne 2 ]
then
    echo "Usage: $0 REGEX TEMPORARY_BRANCH_NAME"
    exit 1
fi

REGEX="$1"
BRANCH_NAME="$2"

git checkout -b "$BRANCH_NAME"

FIRST_COMMIT=$(git log --grep="$REGEX" --pretty=format:%H | tail -1)
if [ -z "$FIRST_COMMIT" ]
then
    echo "No commits matched '$REGEX'"
    exit 2
fi

export GIT_EDITOR="f() { if [ \"\$(basename \$1)\" = \"git-rebase-todo\" ]; then sed -i -n '/${REGEX}/p' \$1 && sed -i '2,\$s/pick/squash/' \$1; else vim $1; fi }; f"
git rebase -i ${FIRST_COMMIT}^

"...你可以这样调用:"
squash-matching-commits 'bug #1' tmp-branch

这段文字的意思是:创建一个名为tmp-branch的分支,然后将其变基到第一个匹配bug #1的提交的父级,仅选择与bug #1匹配的提交并压缩除第一个提交以外的所有提交。(您可能需要解决一些冲突,并为已压缩的提交提供提交消息。)如果成功,那么您只需要执行以下操作:
git show

“…查看组合的补丁。我并不认真推荐任何人使用这个脚本,但我认为这是一种有趣和hacky的做法来实现你想要的。”

1
我不想看到补丁列表,我想看到单个补丁。 - Elazar Leibovich
我忘记了 -p 选项。+1 - VonC
哦,我添加了另外两个可能的选项。我认为给出负评有点过分了,因为问题并没有明确表明 OP 是否知道 --grep 选项。 - Mark Longair

1

您可以使用git log --grep=fix1(如Git参考中所示)来隔离相关提交,然后对每个提交执行git show <commit>

请参见“简写方式以及其与父级的差异?”。

将这些补丁组合成单个差异并不容易,正如Jefromi在“带作者过滤器的git diff”中所解释的那样。

这里的问题在于你不能在一般情况下这样做。
假设Alice更改了一个特定的文件,然后Bob更改了它 - 包括Alice更改的部分 - 最后Alice再次更改了它。
如何将Alice的两个差异合并为单个差异?
如果将它们作为两个补丁,第二个补丁就无法应用,除非先应用Bob的补丁!
但是你也不能简单地将最终状态与原始状态进行比较,因为那会包括Bob的更改。
在你的情况下,一个可能的(相当繁琐的)解决方案类似于“提取代码审查的相关更改”:
检出一个工作副本,在第一次更改之前的修订版本。然后将所有相关提交合并到你的工作副本中。
现在你有一个工作副本,它仅通过相关更改与其基础不同。你可以直接审查它,或从中创建一个补丁进行审查。
所以:一个专门的fix1_review分支是可能的,但这仍然是一个半自动化的设置(因为你必须解决可能的冲突)。

@Johnsyweb:我在最近编辑我的答案时解决了这个问题。 - VonC
我在编辑后阅读了你的答案,但仍然感觉不对。我需要用 meld 重新审查一切,并思考是否存在问题。使用 grep 是无关紧要的。我有我感兴趣的确切提交列表。 - Elazar Leibovich
@Elzar:但是你不能总是将这些差异合并在一起,除非它们是连续的提交。 - VonC
@ElazarLeibovich:我添加了我能找到的最强大的解决方案:专门用于审查所有fix1更改的分支。 - VonC
@ElazarLeibovich:是的,这是一个类似的解决方案,你仍然需要处理潜在的冲突。 - VonC
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接