こんにちは、@na4daです。
作業用に切ったブランチで作業している時に、「ここで細かくコミットすると粒度が小さすぎるので、ある程度纏めてコミットしたい」という状況が時々あると思います。今回は、そういった場合にmerge --squashを用いて、複数のコミットをまとめてコミットする手順をまとめた忘備録的な内容です。
手順
リモートからcheckoutしてきた(もしくはローカルで作成した)ブランチ(例:foo)から、さらにブランチを切り、チェックアウトします。ブランチ名はfoo-devとします。このfoo-devブランチはリモートへpushはせず、ローカルだけで用います。
git checkout -b foo-dev
その後、foo-devブランチでコミットします。後で一つにまとまるため、粒度が小さくなっても気にせずコミットしていきます。
ある程度切りの良いところまでコミットができたら、fooブランチに移動し、merge --squashを行います。
git checkout foo
git merge --squash foo-dev
すると、ブランチを分けた時点からfoo-devブランチの最新コミットまでの差分が一つにまとまり、fooブランチにマージされます。
その後、fooブランチのコミットを行います。
git commit
squashを行なっているため、git commitでエディタを開くと、foo-devブランチでコミットした情報が付加されていることが確認できます。そこで、コミットメッセージの追記とともに、あとで確認できるようfoo-devブランチで行なったコミットログの今回分を残して編集を終えます。
その後、fooブランチのコミットをリモートへpushします。
git checkout foo
git push origin foo
fooブランチにsquashしたコミットを行なった後はfoo-devブランチに戻り、fooブランチのコミットをmergeします。
これは、次回merge --squashを行う際に、前回のcommitと同一の箇所を編集することで発生するconflictを防ぐために行います。ちなみに、この手順のタイミングとしては、リモートにpushする前と後、どちらでも構いません。
git checkout foo-dev
git merge foo
ここまでの一連の流れをシーケンス図で表すと以下のようになります。
この図のように、必ずfoo-barを介さずに直接fooブランチにコミットし、pushすることもあると思います。その際も、foo-devにそのコミットを反映させることでconflictを防ぐことができます。
また、一つにまとめたコミットをfooブランチからgit logで確認すると、以下のような構成になっています(内容は一例です)。
commit f333c7c62f0a949014346c43fa9dd387367e9056
Author: test user <test@example.jp>
Date: Fri Jun 7 17:13:43 2019 +0900
Fix config files
Squashed commit of the following:
commit 1638a43820192c9a1e73ba630559a37fd38f3832
Author: test user <test@example.jp>
Date: Fri Jun 7 17:12:37 2019 +0900
Fix foo-config.txt
commit 5abe5741b8ab5cf87283b3ff400002015a743855
Author: test user <test@example.jp>
Date: Fri Jun 7 16:34:48 2019 +0900
Fix bar-config.txt
...
commit f1ec251f4eee1c42bce0abaed60da3195ebb2df2
Merge: d53b4ec e1e4093
Author: test user <test@example.jp>
Date: Fri Jun 7 15:34:28 2019 +0900
Merge branch 'foo' into foo-dev
少し手順が多いですが、以上の方法で複数のコミットをまとめて一つのコミットとしてpushすることができます。
終わりに
例えば、masterブランチの変更を反映させるためにfooにgit merge masterを行なった場合は、foo-devにも同じような操作(git merge foo)が必要になるため、多少作業量が増えてしまうなどの欠点はあります(confilictが発生する場合は特に)。
個人で作業しているのであればともかく、チームで作業ブランチを共有している場合は他の人が混乱しないように、そして、なるべく内容がまとまっている範囲内でこの方法を使うと良いかなと思います。
少しでも参考になれば幸いです。