12853


あるトピックブランチ上のコミット A が、特定のブランチ B (eg. develop) へマージされているとします。

このコミットAがブランチBへマージされた際のマージコミットがどれであるかを判定したいのですが、これはどうやったら実現できますでしょうか。

* * *

追記: コミットAがブランチBへマージされるマージコミットとは、ブランチBからfirst parent
のみを辿って得られる歴史の上で、一番最古の、コミットAの子孫であるマージコミットのことです。


CC BY-SA 3.0
2015-07-30T14:37:56.430
12852
2016-04-05T17:31:13.330
2015-07-30T15:07:01.210
754
754
question
git
特定のコミットに対して、それが対象のブランチへ、どのマージコミットでマージされたかを判定するには？


bash 依存になりますが、以下の方法はいかがでしょうか。  
他のシェルでも、プロセス置換が行えるなら同様のことはできると思います。

[code]

    grep -Fxf \
      <(git log --first-parent --merges --pretty=format:%H B; echo) \
      <(git log --ancestry-path --merges --pretty=format:%H A..B; echo) \
    | tail -n 1
    
[/code]

需要がありそうな要望なので、git のみでもっと簡単にできそうな気もしますが、方法を見付けられなかったので他コマンドと組み合わせました。

なお、A が B
へマージされたものではなく、Bの最初の子孫から辿り着けるものだった場合、全く関係ない最古のマージコミットが結果として表示されてしまうので注意して下さい。

## 解説

上記コマンドの各断片の意味は以下の通りです。

  * `grep -Fxf A B`  
ファイル A と B の共通の行を取り出すイディオム。  
ここでは A と B としてコマンドのプロセス置換を記述することにより、ふたつのコマンドの出力の共通行を取り出しています。

  * `git log --first-parent --merges --pretty=format:%H B`  
Bからfirst parent のみを辿って得られるマージコミットのハッシュのみを列挙します。この後に
`echo`が続いているのは、最後の出力行に付かない改行を補完するためです。

  * `git log --ancestry-path --merges --pretty=format:%H A..B`  
Bとその祖先のうち、Aの子孫であるマージコミットのハッシュを列挙します。これも改行を補完するため `echo` を付けています。

  * `tail -n 1`  
標準入力の最後の行を表示します。

これらを組み合わせることによって、

> Bからfirst parent のみを辿って得られる歴史の上で、一番最古の、コミットAの子孫であるマージコミット

のハッシュが得られます。


CC BY-SA 3.0
2015-07-30T17:03:38.940
12853
2015-07-30T17:09:13.703
2015-07-30T17:09:13.703
7831
7831
12852
answer


@yoh2 さんの回答に、プロセス置換が利用できない場合や(例:
msys)にも利用できるように、改善したものが次です。(かつ、もう少し汎用的な計算をしています。)

[code]

    #!/bin/bash
    
    CMT=$1
    BR=$2
    
    git rev-list --first-parent $CMT..$BR | {
        exec 3<&0
        {
            git rev-list --ancestry-path $CMT..$BR
            git rev-parse $CMT
    
        } | {
    
            answer=
    
            while read rev1 <&3; do
                while true; do
                    if ! read rev2; then
                        break 2
                    elif [ $rev1 = $rev2 ]
                    then
                        answer=$rev1
                        break
                    fi
                done
            done
    
            echo $answer
    
        }
        exec 3<&-
    }
    
[/code]


CC BY-SA 3.0
2016-04-03T19:46:42.793
23712
2016-04-04T14:40:30.713
2016-04-04T14:40:30.713
754
754
12852
answer


[Find merge commit which include a specific
commit](https://stackoverflow.com/q/8475448/3090068) というまさにこれの英語版を本家で見つけました。

一番洗練されてると思ったのは、 @robinst の回答で、

[code]

    [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 | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
        show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"
    
[/code]

を gitconfig に追加することでした。 (そして悔しいことに、多分これは msys, つまり windows の git
環境でも利用可能だと思われます。)


CC BY-SA 3.0
2016-04-05T17:31:13.330
23770
2016-04-05T17:31:13.330
2017-05-23T12:38:56.467
-1
754
12852
answer