回答:
あなたの例は、ブランチ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ニュースグループの誰か」から取得したもの)。
ワンライナーにしたい場合は、プロセス置換を参照してください。
master
にマージされたfeature
後、すぐに早送りとしてfeature
マージさmaster
れたとします(feature
置換のヒントmaster
)。それ--first-parent
は間違った親を返す原因になりますか?
comm -1 -2
がうまくいきませんでした。comm
ソートされた行でのみ機能します。(私はそれを読むことができませんでしたが、perlワンライナーは機能します。)
git find-merge h master
何も返さず、hをgit find-merge d master
返す必要があります)、(fを返すが、dをgit find-merge c feature
返す必要があります)、(eを返すが、gを返す必要があります)。
これをあなたに追加してください~/.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
は、同じ引数を指定して使用します。
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2
共通の最後の行が正しく検出されないことに注意してください。ここで「それが失敗した例です。
16db9fef5c581ab0c56137d04ef08ef1bf82b0b7
ペーストで実行するとここで見つかりますが、それは予期されていませんか?どのOSを使用していますか?
29c40c3a3b33196d4e79793bd8e503a03753bad1
git-get-mergeは、探しているマージコミットを見つけて表示します。
pip install git-get-merge
git get-merge <SHA-1>
コマンドは、別のブランチ(おそらくマスター)へのマージが見つかるまで、指定されたコミットの子をたどります。
つまり、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
編集:これはプロセス置換 " <()
"を使用しているため、POSIX互換ではなく、シェルで動作しない可能性があります。それはで動作しますbash
かzsh
けれども。
私はこれを行う必要があり、どういうわけか見つかりましたgit-when-merged
(実際にはこのSOの質問を参照していますが、Michael Haggertyが非常に優れたPythonスクリプトへの参照をここに追加したことはありません)。だから今私は持っています。
ゴーティエの素晴らしい答えに基づいて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
入力がソートされていない場合は機能しませんでした。
Rubyの群衆のために、git-whenceがあります。非常に簡単。
$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway
私はパスに配置した以下のbashスクリプトを使用します~/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でも入手できます。
@robinstのアイデアのルビーバージョンは、2倍速く動作します(これは非常に古いコミットを検索するときに重要です)。
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
このようなものを試すことができます。アイデアは、すべてのマージコミットを反復処理し、そのうちの1つからコミット "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
git rev-list <SHA-1_for_c>..master --ancestry-path --merges
私はこれを数回実行する必要があり(この質問に回答した皆さんに感謝します!)、結局、Gauthierの方法を使用して、gitユーティリティの小さなコレクションに追加できるスクリプトを作成しました。ここで見つけることができます:https : //github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point。