找出我们试图挑选的提交所依赖的内容

8
假设有以下内容:
                            HEAD/master     
                             |
A<--B<--C<--D<--E<--F<--G<--J  
        ^
        official 

official 是一个分支。
我想要从 official 分支中挑选出两个提交,例如 EJ
这两个提交都是针对相同的三个文件的修复。
当我执行 git cherry-pick E 时,一切都很顺利,但是当我执行 git cherry-pick J 时,出现了一些冲突。
查看差异后,我意识到我还需要挑选提交 F,在那三个文件中修改了两个方法的定义,而提交 J 是基于此进行的。
因此,只需执行 git cherry-pick F && git cherry-pick J 即可轻松解决问题。
问题:
如果我不知道那些文件发生了变化,而提交 F 是一个大的提交,更改了许多文件:有没有其他方法可以确定我们尝试挑选的提交取决于哪个提交,而不必手动在文件上执行 git log 并逐个查看提交?

答案: 可以使用 `git blame` 命令来找到每一行最后一次修改的提交。例如,要查看文件 `example.txt` 中第 10 行最后一次修改的提交,可以运行以下命令:
``` git blame -L 10,10 example.txt ```
这将显示最后一次修改第 10 行的提交的哈希值和作者等信息。
2个回答

7

有没有其他方法可以找出我们正在尝试挑选的提交所依赖的提交,而不是手动在文件上进行git日志并逐个提交?

是的 - 我编写了 git-deps 来自动化这个任务。由于它目前接受一系列要分析的提交,在您的示例中,您需要传递一个包含单个提交 J 的范围,并告诉它排除任何已在 official 中的依赖项:

git deps --exclude-commits official J^!

在幕后,该工具将查看JJ^的差异,然后对任何被删除或修改的行运行git blame,以及一定数量的周围上下文。这将导致它发现J删除或修改的一行或多行来自提交F,因此它将输出提交F的SHA1。

git-deps不仅可以发现单个提交或提交范围的依赖关系,还可以递归整个依赖树。因此,您所描述的整个樱桃选取场景可以自动化为一个命令:

git deps --recurse --exclude-commits official J^! | \ 
    tsort | \ 
    tac | \ 
    xargs -t git cherry-pick

请注意,这仅保证挑选的内容都能被干净地应用,而不是它们在语义上是否正确。因此,生成的分支头仍需要仔细检查和测试其正确性。
更方便地在分支之间移植提交是使用git-deps的最明显(但并非唯一)用例,出于这个原因,我已经专门为此用例在README中 dedicated a section of the README specifically to this use case。甚至还包括一个YouTube视频,向您展示如何使用它。
如果您想要更多细节,您可能会对我关于此和其他相关工具的两个演讲感兴趣:

我也在GitMinutes播客的第32集中谈到了这个工具。


谢谢你的回答!你知道是否有类似的挑选依赖跟踪解决方案,但适用于Subversion吗? - andrews
很确定Subversion本身并不足够强大以实现这一点。但是你可以使用git-svn - Adam Spiers

0
我遇到了一些[合并]冲突......是否有另一种方法来确定我们试图摘选的提交所依赖的提交呢,而不必手动在文件上进行git日志操作并逐个提交检查呢?
实际上没有。即使这样做也不一定可以解决问题——至少不能不考虑问题。想象以下这段C代码:
void f(int x) {
    int i;

    /*
     * additional lines here, enough to mess with git context
     * since that only looks at +/- 3 lines around each patch
     * segment
     */

    for (i = 0; i < x; i++)
        do_something(i);
}

假设一个中间提交引入了一个额外的变量j,然后稍后的提交将do_something(i)更改为do_something(j)。如果你只挑选后面的提交,Git会愉快地更改该行而不会发生冲突,但代码将无法编译,因为函数f中没有int j
话虽如此,可以编写一个工具来解析每个中间提交的git show输出,找出哪些行已更改(相对于工作树中的版本,而不是使用每个差异中的实际数字,因为这些可能取决于前一个跳过的差异),并指向修改冲突区域的提交。但我不知道有这样的工具。

那么在这种情况下,您的工作流程是什么?您发现最有效的是什么? - Jim
@Jim:通常来说,对提交的检查很多——基本上就是你最终所做的事情。复杂的cherry-pick应该很少见,因为工具无法很好地处理它们,而工具无法很好地处理它们部分原因是它们很少见,这有点像一个进退两难的局面。 - torek

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