想象一下以下历史:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
如何将提交“c”合并到master中(即查找合并提交“h”)?
答案 0 :(得分:132)
您的示例显示分支feature
仍然可用。
在这种情况下,h
是最后一个结果:
git log master ^feature --ancestry-path
如果分支feature
不再可用,您可以在c
和master
之间的历史记录行中显示合并提交:
git log <SHA-1_for_c>..master --ancestry-path --merges
但是,这也会显示h
之后以及e
上g
和feature
之间发生的所有合并。
比较以下命令的结果:
git rev-list <SHA-1_for_c>..master --ancestry-path
git rev-list <SHA-1_for_c>..master --first-parent
会将h
的SHA-1作为共同的最后一行。
如果您有空,可以对这些结果使用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/的perl代码,它来自“comp.unix.shell新闻组中的某人”)。
如果你想让它成为一个单行,请参见process substitution。
答案 1 :(得分:95)
将此添加到您的~/.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's answer。感谢Rosen Matev和javabrett纠正sort
的问题。)
答案 2 :(得分: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
编辑:因为它使用process substitution“<()
”,它与POSIX不兼容,并且它可能无法与您的shell一起使用。它适用于bash
或zsh
。 子>
答案 3 :(得分:21)
git-get-merge将找到并显示您正在寻找的合并提交:
pip install git-get-merge
git get-merge <SHA-1>
该命令跟随给定提交的子节点,直到将合并到另一个分支(可能是master)中找到。
答案 4 :(得分:13)
我需要这样做,并以某种方式找到git-when-merged
(实际上引用了这个SO问题,但是Michael Haggerty从未在这里添加对他非常好的Python脚本的引用)。所以现在我有了。
答案 5 :(得分:12)
在Gauthier的最佳答案的基础上,我们不需要使用comm
来比较列表。既然我们正在--ancestry-path
寻找--first-parent
中的最后一个结果,我们可以在前者的输出中简单地使用后者:
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
}
答案 6 :(得分:4)
对于Ruby人群,有git-whence。很容易。
$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway
答案 7 :(得分:2)
我使用下面的bash脚本,我将其放在路径~/bin/git-find-merge
。它基于Gauthier's answer和evilstreak's answer,几乎没有调整来处理角落情况。输入未排序时抛出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
此脚本也可用on my github。
答案 8 :(得分:1)
我的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
答案 9 :(得分:1)
git log --topo-order
然后在提交之前查找第一个合并。
答案 10 :(得分:0)
你可以尝试这样的事情。我们的想法是迭代所有合并提交,看看是否可以从其中一个提交“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
答案 11 :(得分:0)
我必须多次这样做(感谢大家回答了这个问题!),最后写了一个脚本(使用Gauthier的方法),我可以添加到我的git实用程序的小集合中。您可以在此处找到它:https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point。