查找包含特定提交的合并提交

Gui*_*rin 158 git

想象一下以下历史:

       c---e---g--- feature
      /         \
-a---b---d---f---h--- master
Run Code Online (Sandbox Code Playgroud)

如何将提交"c"合并到主服务器中(即查找合并提交"h")?

Gau*_*ier 140

您的示例显示分支feature仍然可用.

在这种情况下h是最后的结果:

git log master ^feature --ancestry-path
Run Code Online (Sandbox Code Playgroud)

如果分支feature不再可用,您可以在c和之间的历史记录行中显示合并提交master:

git log <SHA-1_for_c>..master --ancestry-path --merges
Run Code Online (Sandbox Code Playgroud)

然而,这将同时显示所有之后发生的合并h,以及之间e以及gfeature.


比较以下命令的结果:

git rev-list <SHA-1_for_c>..master --ancestry-path

git rev-list <SHA-1_for_c>..master --first-parent
Run Code Online (Sandbox Code Playgroud)

会给你SHA-1 h作为最后一行的共同点.

如果您有可用的,则可以使用comm -1 -2这些结果.如果您使用的是msysgit,则可以使用以下perl代码进行比较:

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
Run Code Online (Sandbox Code Playgroud)

(来自http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/的 perl代码,它来自"comp.unix.shell新闻组中的某人").

如果您想使其成为单行,请参阅流程替换.

  • 我刚刚编写了一个脚本git-when-merged来实现这个建议(还有很多其他功能).请参阅https://github.com/mhagger/git-when-merged (9认同)
  • 即使你有comm,你也不能使用它,因为"git rev-list"命令的输出没有按字典顺序排序.您当然可以在查找公共行之前对每个命令的输出进行排序,但是所需的提交不一定是最后一个.所以我觉得像perl命令(虽然模糊不清)之类的东西是必要的. (3认同)
  • 我试过`comm -1 -2`但它没有用.`comm`仅适用于排序行.(perl one-liner有效,虽然我看不懂.) (3认同)
  • 我通常只对第一次合并感兴趣。如果我这样做: `git log &lt;SHA-1_for_c&gt;..master --ancestry-path --merges --oneline | tail -1` 到目前为止,我总是得到我正在寻找的答案。在什么情况下可能不起作用? (3认同)
  • 假设在某些时候`master`被合并到`feature`,然后立即`feature`被合并到`master`作为快进('feature`的尖端替换`master`).这会导致`--first-parent`返回错误的父级吗? (2认同)
  • 这有点晚了,但是添加后使人们可以发现它有用,因为git本身不提供此功能。我认为有些死角案例无法解决此问题(请参阅下面的答案,该文章可以处理大多数死角案例),网址为http://stackoverflow.com/a/43716029/58678。以下是一些极端情况:`git find-merge h master`(不返回任何内容,但应返回h),`git find-merge d master`(返回f但应返回d),`git find-merge c功能(返回) e,但应返回g)。 (2认同)

rob*_*nst 110

将此添加到您的~/.gitconfig:

[alias]
    find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
    show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用别名:

# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master
Run Code Online (Sandbox Code Playgroud)

要查看合并提交的消息和其他详细信息,请使用git show-merge相同的参数.

(根据Gauthier的回答.感谢Rosen Matevjavabrett解决问题sort.)

  • 美丽!这是最好的直接解决方案. (4认同)
  • @robinst这个问题是由第一个排序(`-k2`)应用基于字节的决胜局引起的,当第二个字段(提交哈希)相等时不保留输入顺序。可以通过多种方式停止此行为:“-s|--stable”开关可以执行此操作 - 如果将其添加到@RosenMatev的粘贴的排序中,它将按预期排序,即结果是“16db9fef5c581ab0c56137d04ef08ef1bf82b0b7”而不是“ 29c40c3a3b33196d4e79793bd8e503a03753bad1`。通过将该排序更改为“sort -k2,2 -k1,1n”也可以实现此结果。哪个是正确的 - 原始的 cat+cat 顺序,还是按数字排序? (2认同)
  • @powlo:没什么,为方便起见,它只是一个命令而不是两个命令. (2认同)

Jia*_*ian 24

git-get-merge将找到并显示您正在寻找的合并提交:

pip install git-get-merge
git get-merge <SHA-1>
Run Code Online (Sandbox Code Playgroud)

该命令跟随给定提交的子节点,直到找到合并另一个分支(可能是master).


Tot*_*tor 21

也就是说,总结一下Gauthier的帖子:

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' <(git rev-list --ancestry-path <SHA-1_for_c>..master) <(git rev-list --first-parent <SHA-1_for_c>..master) | tail -n 1
Run Code Online (Sandbox Code Playgroud)

编辑:因为它使用进程替换 " <()",它不兼容POSIX,它可能无法与您的shell一起使用.它可以使用bash或者使用zsh.

  • 我不经常从互联网上复制/粘贴代码,但是当我这样做时它完美无缺!谢谢Totor允许我不要思考. (4认同)
  • 不幸的是,@ TheodoreR.Smith,语法`<()`不兼容POSIX.你需要使用`bash`,`zsh`或支持[进程替换]的shell(http://en.wikipedia.org/wiki/Process_substitution).我相应地编辑了我的答案. (2认同)

Ale*_*puy 13

我需要这样做,并以某种方式找到git-when-merged(实际上引用了这个SO问题,但Michael Haggerty从未在这里添加对他非常好的Python脚本的引用).所以现在我有.


小智 12

基于Gauthier的出色答案,我们不需要comm用来比较列表.由于我们正在寻找最后的结果--ancestry-path,这也是在--first-parent,我们可以简单地用grep在前者的输出,后者:

git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1
Run Code Online (Sandbox Code Playgroud)

或者对于一些活泼且可重复使用的东西,这里有一个功能.bashrc:

function git-find-merge() {
  git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
Run Code Online (Sandbox Code Playgroud)


小智 8

git log --topo-order
Run Code Online (Sandbox Code Playgroud)

然后在提交之前查找第一次合并。


hIp*_*pPy 6

我使用下面放置在 path 的 bash 脚本~/bin/git-find-merge。它基于Gauthier 的回答evilstreak 的回答,并进行了一些调整以处理极端情况。comm当输入未排序时抛出。grep -f完美地工作。

角落案例:

  • 如果提交是分支的第一父路径上的合并提交,则返回提交。
  • 如果提交是分支的第一父路径上的非合并提交,则返回分支。它要么是 ff 合并,要么是仅在分支上提交,并且没有找到正确提交的好方法。
  • 如果提交和分支相同,则返回提交。

~/bin/git-find-merge 脚本:

#!/bin/bash

commit=$1
if [ -z $commit ]; then
    echo 1>&2 "fatal: commit is required"
    exit 1
fi
commit=$(git rev-parse $commit)
branch=${2-@}

# if branch points to commit (both are same), then return commit
if [ $commit == $(git rev-parse $branch) ]; then
    git log -1 $commit
    exit
fi

# if commit is a merge commit on first-parent path of branch,
# then return commit
# if commit is a NON-merge commit on first-parent path of branch,
# then return branch as it's either a ff merge or commit is only on branch
# and there is not a good way to figure out the right commit
if [[ $(git log --first-parent --pretty='%P' $commit..$branch | \
    cut -d' ' -f1 | \
    grep $commit | wc -l) -eq 1 ]]; then
    if [ $(git show -s --format="%P" $commit | wc -w) -gt 1 ]; then
        # if commit is a merge commit
        git log -1 $commit
    else
        # if commit is a NON-merge commit
        echo 1>&2 ""
        echo 1>&2 "error: returning the branch commit (ff merge or commit only on branch)"
        echo 1>&2 ""
        git log -1 $branch
    fi
    exit
fi

# 1st common commit from bottom of first-parent and ancestry-path
merge=$(grep -f \
    <(git rev-list --first-parent  $commit..$branch) \
    <(git rev-list --ancestry-path $commit..$branch) \
        | tail -1)
if [ ! -z $merge ]; then
    git log -1 $merge
    exit
fi

# merge commit not found
echo 1>&2 "fatal: no merge commit found"
exit 1
Run Code Online (Sandbox Code Playgroud)

这让我可以这样做:

(master)
$ git find-merge <commit>    # to find when commit merged to current branch
$ git find-merge <branch>    # to find when branch merged to current branch
$ git find-merge <commit> pu # to find when commit merged to pu branch
Run Code Online (Sandbox Code Playgroud)

这个脚本也可以在我的 github 上找到


ste*_*eel 5

对于 Ruby 人群,有git-whence。好简单。

$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway
Run Code Online (Sandbox Code Playgroud)