gitで統合ブランチへ取り込まれたトピックブランチの一覧を抽出する


2011年 03月 21日

問題

「トピックブランチをばんばん作ってある程度のところで統合ブランチへマージする」
という開発スタイルを行っていたとしましょう。
例えばバージョン1をベースにガリゴリとトピックブランチを作って統合ブランチへマージし、
一区切りついたところでバージョン2としてリリースするといった具合です。

マージするトピックの数が数個であれば特に問題はないのですが、
10や20になってくると git log を眺めてもどのトピックブランチが取り込まれているのか一目では分からなくなってきます。
例えば git log master..$topic の出力が空であれば $topic が取り込まれていないことは分かりますが、
10や20もトピックブランチがある状態ならばこんな方法で1個づつ調べる気は起きません。
どうにかして統合ブランチへ取り込まれたトピックブランチの一覧を抽出する方法はないでしょうか。

解決方法

git log--mergesオプションを使います。
これはマージコミットのみを出力するオプションです。

例えばバージョン1(v1)から統合ブランチ(master)でマージがどれだけ行われたかは以下のコマンドで一覧できます:

$ git log --oneline --abbrev-commit --merges v1..master
7bc592a Merge remote branch 'origin/2218'
28630cd Merge remote branch 'origin/2209'
0e3dd86 Merge remote branch 'origin/2208'
43d7e06 Merge remote branch 'origin/2201'
...

後はこれをよしなに加工してあげればバージョン1から統合ブランチへ取り込まれたトピックブランチの一覧が得られます:

$ git log --oneline --abbrev-commit --merges v1..master | sed -e "s/.* '//;s/'.*//" | sort | uniq
origin/2169
origin/2175
origin/2183
origin/2190
...

補足

git mergeはデフォルトで fast-forward mergeを行うようになっています。

例えば各ブランチが以下のような状況になっていたとしましょう:

$ git log --graph --pretty=oneline --decorate --abbrev-commit
* af3e66f (topic) Add "copy" UI
* c611097 Refactor - Revice grouping of code chunks
* bf88c95 Refactor - Remove trailing spaces
* 3f5a586 Refactor - Sort using statements
*   332e5c3 (HEAD, origin/master, master) Merge remote branch 'origin/old-topic'
|\
| * a9baf1c (origin/old-topic, old-topic) Fix a great typo
...

この状態で topicmaster へマージすると fast-forward merge が行われます:

$ git merge topic
Updating 332e5c3..af3e66f
Fast-forward
 Great.aspx    |   27 ++-
 Great.aspx.cs |  503 +++++++++++++++++-------------
 2 files changed, 308 insertions(+), 222 deletions(-)

$ git log --graph --pretty=oneline --decorate --abbrev-commit
* af3e66f (HEAD, master, topic) Add "copy" UI
* c611097 Refactor - Revice grouping of code chunks
* bf88c95 Refactor - Remove trailing spaces
* 3f5a586 Refactor - Sort using statements
*   332e5c3 (origin/master) Merge remote branch 'origin/old-topic'
|\
| * a9baf1c (origin/old-topic, old-topic) Fix a great typo
...

マージするブランチ(topic)はチェックアウト中のブランチ(master)に対して線形にコミットを積み重ねたものであるため、
わざわざマージ処理を行うまでもなくマージ結果は topic と同一になります。
という訳で通常のマージ処理は行われず、
master の指すコミットを topic と同じものに差し替えるだけで済まされます。

実際、上記のようなケースは頻繁に発生します。
特にgit pullではよくあるケースです。
いちいちマージコミットを作成していてはコミットログを後から見たときに悲しいことになりますから、
デフォルトでは fast-forward merge が行われるようになっています。

ところが fast-forward merge が行われた場合、それを示すコミットが作成されないため、
git log --merges で一覧することができなくなります。
そのため、トピックブランチを統合ブランチへマージする際には
fast-forward merge されるケースであっても敢えてマージコミットを作成するよう指示しておく必要があります。
これには git merge --no-ff を使います:

$ git merge --no-ff topic
Merge made by recursive.
 Great.aspx    |   27 ++-
 Great.aspx.cs |  503 +++++++++++++++++-------------
 2 files changed, 308 insertions(+), 222 deletions(-)

$ git log --graph --pretty=oneline --decorate --abbrev-commit
*   149622e (HEAD, master) Merge branch 'topic'
|\
| * af3e66f (origin/topic, topic) Add "copy" UI
| * c611097 Refactor - Revice grouping of code chunks
| * bf88c95 Refactor - Remove trailing spaces
| * 3f5a586 Refactor - Sort using statements
|/
*   332e5c3 (origin/master) Merge remote branch 'origin/old-topic'
|\
| * a9baf1c (origin/old-topic, old-topic) Fix a great typo
...