Shimpei Wakida's Blog

日々の学びをゆるりと.

コミットメッセージに自動でブランチ名を追加した時に詰まったポイント

後々のコミットの検索性を考慮し、コミットメッセージの頭にブランチ名を書くのが好みです。 ただ、手動でブランチ名を毎回入力するのは大変面倒なので、自動でできるようにしちゃいます。

その過程で詰まったポイントがあったので、備忘録として記事にします。

詰まったところ

結論からいうと、「リベースした際、既にコミット済みのコミットメッセージの頭にブランチ名が追加されてしまうのを回避する」のに少し苦労しました。

最終的なコード

先に、最終形態のコードをお見せします。

.git/hooks/prepare-commit-msg

#!/usr/bin/env bash

# コミットメッセージを変数に格納
COMMIT_EDITMSG=$1 

# コミットメッセージの頭に追加する"[ブランチ名]"の文字列を変数に格納
BRANCH_NAME=$(git branch | grep '*' | sed 's/* //')  
INSERTED_BRANCH_NAME=["$BRANCH_NAME"] 

# コミットメッセージの頭に INSERTED_BRANCH_NAME を追加
addBranchName() {
  DESCRIPTION=$(git config branch."$BRANCH_NAME".description)
  echo "$INSERTED_BRANCH_NAME: $(cat $COMMIT_EDITMSG)" > $COMMIT_EDITMSG
  if [ -n "$DESCRIPTION" ] 
  then
     echo "" >> $COMMIT_EDITMSG
     echo $DESCRIPTION >> $COMMIT_EDITMSG
  fi 
}

# マージコミットであるか判定
MERGE_MESSAGE_LINES=$(cat $COMMIT_EDITMSG|grep -i 'merge'|wc -l)
# リベースのコミットであるか判定
REBASE_MESSAGE_LINES=$(cat $COMMIT_EDITMSG|grep -i "rebasing"|wc -l)

# リベースではない&マージコミットではない場合、コミットメッセージの頭にブランチ名を追加する
if [ $REBASE_MESSAGE_LINES -eq 0 ] && [ $MERGE_MESSAGE_LINES -eq 0 ] ; then
  addBranchName
fi

ちなみに、「コミットメッセージにブランチ名を追加する」だけなら、ググると記事も出てくるのでその通りに割と簡単にやればできます。

参考にしたサイト:Gitのブランチ名をコミットメッセージに追加する方法は?

この記事にあるコードをベースに、リベース時に回避する設定を追加した形になります。(シェルスクリプトはほとんど書いたことなく苦手なので、設定を追加するにもまず現状のスクリプトを読み解くのにも非常に苦労しました。。)

ポイント

「リベースのコミットであるかどうか」をどうやって判定するのか?が肝です。通常のコミット・マージコミットと、リベースコミットの違いをみてみます。

コミットの違い

  • 通常のコミット(ブランチ名を追加したい)
  • マージコミット(ブランチ名追加したくない)
  • リベースコミット(ブランチ名追加したくない)

まず、通常のコミットはこんな感じの形式になっています。

 (ここにコミットメッセージを書く)
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch {ブランチ名}
# Changes to be committed:
#       modified:   {ファイル名}
#

次に、マージコミットを見てみます。

Merge branch 'hoge' into fuga
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

最後に、リベースコミット( git rebase -i で、r (コミットメッセージの変更)をしたとき)

 (ここにコミットメッセージを書く)
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Fri Aug 12 01:15:05 2022 +0900
#
# interactive rebase in progress; onto hoge
# Last commands done (2 commands done):
#    pick hoge
#    reword fuga
# No commands remaining.
# You are currently editing a commit while rebasing branch 'hoge' on 'fuga'.
#
# Changes to be committed:
#       modified:   hogehoge
#

それぞれのコミットで、コメントアウトされている箇所に書いてある内容が違うことが分かるかと思います。この違いを見て、マージコミット・リベースコミットを判定しています。

マージコミットの場合は、mergeの文字列、リベースの場合は、rebasingの文字列が含まれているかどうかを見ます。

# マージコミットであるか判定
MERGE_MESSAGE_LINES=$(cat $COMMIT_EDITMSG|grep -i 'merge'|wc -l)
# リベースのコミットであるか判定
REBASE_MESSAGE_LINES=$(cat $COMMIT_EDITMSG|grep -i "rebasing"|wc -l)

wc -l で、最終的に merge もしくはrebasingの文字列を含むブロックがあるか、ある場合はその行数を取得しています。行数が0なら、マージ(リベース)コミットではないということで、コミットメッセージにブランチ名を追加します。

# リベースではない&マージコミットではない場合、コミットメッセージの頭にブランチ名を追加する
if [ $REBASE_MESSAGE_LINES -eq 0 ] && [ $MERGE_MESSAGE_LINES -eq 0 ] ; then
  addBranchName
fi

ちなみに、マージコミットの判定は参考にした記事にあったコードに書いてあったので、この処理の中身(シェルスクリプト・コミットの仕様)を読み解きながら、リベースコミットの判定を追加する形で進めました。

おわりに

以上です。誰かのお役に立てば幸いです。