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

Git 查找包含特定提交的合并提交,git,Git,想象一下下面的历史: c---e---g--- feature / \ -a---b---d---f---h--- master 当提交“c”已合并到主控中(即,查找合并提交“h”)时,如何查找?您可以尝试类似的方法。其思想是迭代所有合并提交,并查看是否可以从其中一个提交中访问提交“c”: $ git log --merges --format='%h' master | while read mergecommit; do if git log

想象一下下面的历史:

       c---e---g--- feature
      /         \
-a---b---d---f---h--- master

当提交“c”已合并到主控中(即,查找合并提交“h”)时,如何查找?

您可以尝试类似的方法。其思想是迭代所有合并提交,并查看是否可以从其中一个提交中访问提交“c”:

$ git log --merges --format='%h' master | while read mergecommit; do
  if git log --format='%h' $mergecommit|grep -q $c; then
    echo $mergecommit;
    break
  fi
done

您的示例显示分支
功能仍然可用

在这种情况下,
h
是以下各项的最后结果:

git log master ^feature --ancestry-path

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

git log <SHA-1_for_c>..master --ancestry-path --merges
将为您提供
h
的SHA-1作为公共的最后一行

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

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
(perl代码来自,它来自“comp.unix.shell新闻组的某人”)


看看你是否想让它成为一行。

也就是说,总结一下高蒂尔的文章:

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
perl-ne'print if($seen{$}.=@ARGV)=~/10$/”将找到并显示您要查找的合并提交:

pip install git-get-merge
git get-merge <SHA-1>
pip安装git获取合并
git获取合并

该命令跟随给定提交的子级,直到找到合并到另一个分支(可能是主分支)为止。

基于Gauthier的伟大答案,我们不需要使用
comm
来比较列表。由于我们正在查找
--祖先路径
中的最后一个结果,它也在
--第一个父项
中,因此我们可以在前者的输出中简单地对后者进行grep:

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

我已经做了好几次了(感谢所有回答这个问题的人!),最后我写了一个脚本(使用Gauthier的方法),可以添加到我的git实用程序小集合中。您可以在这里找到:。

我需要这样做,但不知怎么找到了(这实际上引用了这个问题,但Michael Haggerty从未在这里添加对他非常好的Python脚本的引用)。现在我有了。

将此添加到您的
~/.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'"
然后可以使用如下别名:

# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master
ruby find-commit.rb SHA master
#当前分支
git查找合并
#指定主控
git查找合并主机
要查看合并提交的消息和其他详细信息,请使用具有相同参数的
git show merge


(基于。感谢并纠正了
sort
的问题)

对于Ruby人群,有一个。很简单

$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway

我的@robinst想法的ruby版本,运行速度快了两倍(这在搜索非常旧的提交时很重要)

find commit.rb

commit = ARGV[0]
master = ARGV[1] || 'origin/master'

unless commit
  puts "Usage: find-commit.rb commit [master-branch]"
  puts "Will show commit that merged <commit> into <master-branch>"
  exit 1
end

parents = `git rev-list #{commit}..#{master} --reverse --first-parent --merges`.split("\n")
ancestry = `git rev-list #{commit}..#{master} --reverse --ancestry-path --merges`.split("\n")
merge = (parents & ancestry)[0]

if merge
  system "git show #{merge}"
else
  puts "#{master} doesn't include #{commit}"
  exit 2
end

我使用下面的bash脚本,我将它放在路径
~/bin/git find merge
中。它是基于和很少调整,以处理角案件<代码>通信
在输入未排序时抛出
grep-f
工作正常

角落案例:

#!/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
(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
  • 如果提交是分支的第一个父路径上的合并提交,则返回提交
  • 如果提交是分支的第一个父路径上的非合并提交,则返回分支。它要么是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
(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
#/bin/bash
提交=1美元
如果[-z$commit];然后
echo 1>&2“致命:需要提交”
出口1
fi
提交=$(git rev parse$commit)
分支=${2-@}
#如果分支指向提交(两者相同),则返回提交
如果[$commit==$(git rev parse$branch)];然后
git日志-1$commit
出口
fi
#如果提交是分支的第一个父路径上的合并提交,
#然后返回commit
#如果提交是分支的第一个父路径上的非合并提交,
#然后返回分支,因为它是ff合并,或者提交仅在分支上
#没有一个好的方法来找出正确的承诺
如果[[$(git log--第一个父级--pretty='%P'$commit..$branch |\
切割-d'-f1|\
grep$commit | wc-l)-eq 1]];然后
如果[$(git show-s--format=“%P”$commit | wc-w)-gt 1];然后
#如果提交是合并提交
git日志-1$commit
其他的
#如果提交是非合并提交
回显1>&2“”
echo 1>&2“错误:返回分支提交(ff合并或仅在分支上提交)”
回显1>&2“”
git日志-1$branch
fi
出口
fi
#从第一个父级和祖先路径底部开始的第一个公共提交
合并=$(grep-f)\

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

我不经常从互联网上复制/粘贴代码,但当我这样做时,它工作得很好!感谢Totor允许我不去思考。@TheodoreR.Smith不幸的是,语法
对我不起作用。我想我的功能分支在合并到master之前首先被合并到另一个分支。这是uld解释为什么您的命令会导致“合并分支'发布'分支'”而不是“合并分支'功能'分支'”。即使您有comm,您也不能使用它,因为“git版本列表”的输出命令不是按字典顺序排序的。当然,在查找公共行之前,您可以对每个命令的输出进行排序,但所需的提交不一定是最后一行。因此,我认为有必要使用类似perl命令的内容(尽管不太清楚)。我只是在合并时编写了一个脚本git,以实现此建议(具有许多其他功能)。请参见假设在某个点上,
master
被合并到
feature
,然后立即将
feature
合并到
master
,作为一种快进(feature
的提示替换
master
)。这会导致第一个父项返回错误的父项吗?我尝试了
comm-1-2
,但没有成功。
comm
只在排序行上工作。(perl one liner可以工作,尽管我看不懂。)这有点晚了,但是添加它可以让人们发现它很有用,因为git本身不提供
git log --topo-order