c---e---g--- feature
/ \
-a---b---d---f---h--- master
如何找到提交“c”何时合并到主分支(即找到合并提交“h”)?
c---e---g--- feature
/ \
-a---b---d---f---h--- master
将以下内容添加到~/.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
要查看合并的提交消息和其他详细信息,请使用相同参数的git show-merge
命令。
(基于Gauthier的答案。感谢Rosen Matev和javabrett指出与sort
有关的问题。)
你的示例显示分支 feature
仍然可用。
在这种情况下,h
是以下内容的最终结果:
git log master ^feature --ancestry-path
如果分支feature
不再可用,则可以在 c
和 master
之间的历史线路中显示合并提交记录:git log <SHA-1_for_c>..master --ancestry-path --merges
然而,这也将显示在feature
分支上从e
到g
和在h
之后发生的所有合并。
比较以下命令的结果:
git rev-list <SHA-1_for_c>..master --ancestry-path
git rev-list <SHA-1_for_c>..master --first-parent
将会给您一个SHA-1值,它作为在common中的最后一行。
如果您有可用的话,可以对这些结果使用comm -1 -2
。如果您正在使用msysgit,则可以使用以下perl代码进行比较:
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
(这段代码来自于http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/,原始作者是“comp.unix.shell新闻组”的某位成员)。
如果你想将其转换为单行代码,请查看进程替换。
master
分支被合并到了 feature
分支,然后立即将 feature
分支以快进模式合并回 master
分支(即 feature
的指针直接替换了 master
的指针)。这会导致 --first-parent
返回错误的父提交吗? - Kelvincomm -1 -2
,但它没有起作用。comm
只能用于排序后的行。(这个Perl一行代码有效,但我看不懂。) - Domon(什么也不返回,但应该返回h),
git find-merge d master(返回f,但应该返回d),
git find-merge c feature`(返回e,但应该返回g)。 - hIpPygit-get-merge会定位并显示您正在查找的合并提交:
pip install git-get-merge
git get-merge <SHA-1>
git get-merge <SHA-1> origin/master
。 - phdperl -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
编辑:由于这里使用了进程替换 "<()
",它不符合POSIX标准,并且可能无法在您的shell中正常工作。但它可以在bash
或zsh
中工作。
我需要做这件事,然后不知怎么地找到了git-when-merged
(它实际上引用了这个stackoverflow问题,但是Michael Haggerty从未在此处添加他非常好的Python脚本的引用)。所以现在我有了。
在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
或者为了方便和重复使用,这里有一个函数可以插入到.bashrc
中:
function git-find-merge() {
git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
comm
不起作用。 - hIpPygit log --topo-order
然后查找提交之前的第一个合并。
~/bin/git-find-merge
。它基于 Gauthier 的答案 和 evilstreak 的答案,经过一些调整以处理边角情况。当输入未排序时,comm
报错,而 grep -f
则可以正常工作。
边角情况:
~/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
这个脚本也可以在我的Github上找到。
对于Ruby开发者,有git-whence。非常简单。
$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway
我使用 Ruby 语言实现了 @robinst 的想法,速度比原来快了两倍(在查找非常旧的提交时尤为重要)。
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
ruby find-commit.rb SHA master
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2
无法正确找到最后一行的共同点。这里是一个失败的示例。 - Rosen Matev16db9fef5c581ab0c56137d04ef08ef1bf82b0b7
,这不是预期的吗?你用的是什么操作系统? - robinst-k2
)应用了基于字节的决策器,当第二个字段(提交哈希)相等时,它不会保留输入顺序所导致的。可以通过多种方式停止这种行为:-s|--stable
开关可以实现此目的 - 如果将其添加到 @RosenMatev 的粘贴的排序中,则会按预期进行排序,即结果为16db9fef5c581ab0c56137d04ef08ef1bf82b0b7
而不是29c40c3a3b33196d4e79793bd8e503a03753bad1
。也可以通过将该排序更改为sort -k2,2 -k1,1n
来实现此结果。哪个是正确的 - 原始 cat+cat 顺序还是按数字排序? - javabrett