Open20

より良いコミットメッセージを書くために

ふくえもんふくえもん

これからモチベーション->リファレンス->アクション->レビューといった流れでやりたい思う

❤️‍🔥モチベーション

1年半後には働いているので、それまでによりよいコミットメッセージをかけるようになりたい
インターンやチーム開発にも参加したいので、そういった時にちゃんと伝わるように描きたい
未来の自分のために、今時間を消費します

ふくえもんふくえもん
ふくえもんふくえもん

まずは一番気になるものから
https://zenn.dev/itosho/articles/git-commit-message-2023

感想
コミットメッセージは自分を含む未来の開発者に向けて書くもの
今の自分が分かってても、「数年後みた時に、この作業内容が理解できるか」を意識する
この前どこかで、「自分が若い頃は、上司の人に「お前がもし明日から来れなくなっても、代わりに入った人がスムーズに開発に入れるようなコードをかけ」と言われてたな〜」って話を聞いた気がする
クリーンなコードを書くのは難しいけど、コミットメッセージなら日本語を鍛えるだけだから、意識すれば変わりそう

「相手に伝わるコードを書くためには、コミットメッセージから始めよ」

ふくえもんふくえもん

内容要約
フォーマットは以下を参考にして、gitmojiを足してらっしゃる
https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716

<Type>: <Emoji> #<Issue Number> <Title>
例:feat: ✨ #12 ログイン機能の実装
  • TypeとTitleは必須
  • Issue Numberは強く推奨
  • Emojiは任意
  • Description(スリーライン)は任意
  • 個人的にはemojiは見た目が映えるので、推していきたい
ふくえもんふくえもん

コミットの粒度も考えないといけないと感じた

新機能に関しては、まずはボンっと大きなcommitをするべきなのか、細かくするべきか
おそらく細かい方がいいだろうけど、いちいちこの書き方で書いてると煩雑な気もする

  • 実装したことがある機能で、自信があるもの->commit粒度は大きく
  • 新しく実装するもので、手探りの場合->commit粒度は小さく
  • リファクタリングや設定ファイルなどを変更する場合->commit粒度は極端に小さく

元々ある機能や、開発全体に影響するような設定を行う場合は、粒度を小さくして、間違った場合にどこが原因なのかを考える必要があると感じてる

ふくえもんふくえもん

Prefixの種類

chore
タスクファイルなどプロダクションに影響のない修正
docs
ドキュメントの更新
feat
ユーザー向けの機能の追加や変更
fix
ユーザー向けの不具合の修正
refactor
リファクタリングを目的とした修正
style
フォーマットなどのスタイルに関する修正
test
テストコードの追加や修正

ふくえもんふくえもん

コミットメッセージにWhyを書くべきかそうじゃないか

筆者曰く、一つ一つのコミットにWhyを書くのは、難しいとおしゃっている
descriptionに書くのなら、issueに紐づけて、issue(またはPR)の方で丁寧に書いた方がいいのではないかという意見

Whatよりだけど、曖昧なWhatは極力避ける方針
「〇〇をする」->「〇〇の〇〇をする」的なイメージ

ふくえもんふくえもん

実践する
VSCodeの拡張機能だと、Gitmojiが先頭になるので、

<gitmoji><Type>:<#issue番号><内容>

この書き方で実践してみる

ふくえもんふくえもん

CommitメッセージにLintを導入できるだって!?

早速やります
https://zenn.dev/kalubi/articles/27fa889c338cdf
https://zenn.dev/horitaka/articles/commit-message-rules

ふくえもんふくえもん

ライブラリインストール

npm install --save-dev @commitlint/cli @commitlint/config-conventional

commitlintの設定ファイルを追加

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

これで中身を書いた状態のファイルが作れる

ふくえもんふくえもん

huskyでcommit-msgフックを導入

npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'
ふくえもんふくえもん

これで@commitlint/config-conventionalという標準ルールに則って書くことはできる
試しに反してみる

ふくえもんふくえもん

これじゃあgitmojiとかも使えないんじゃあないかあ
カスタマイズする方法を探る

ふくえもんふくえもん

ChatGPTさんに騙された

header-regexというプロパティはなかった...

rulesでカスタマイズできる?
試しに実装してみる

module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'header-regex': [
      2,
      'always',
      /^(|🐛|📝|💄|♻️|⚡️|||...)(feat|fix|docs|style|refactor|perf|test|): #(\d+) (.*)$/
    ],
    'type-enum': [
      2,
      'always',
      ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore', 'revert', 'custom-type']
    ]
  }
}

ふくえもんふくえもん

MySet

今自分が使っているのはこんな感じかな

(✨:feat):新機能の実装
(⚡️:perf):パフォーマンスの改善
(🔥:fire):機能・ファイルの削除
(🐛:fix):バグの修正
(🩹:typo):ちょっとした修正(小さなミス・誤字など)
(📝:docs):コードと関係ない部分(Readme・コメントなど)
(💄:style):スタイル関係のファイル(CSS・UIだけの実装もこれかな)
(♻️:refactor):コードのリファクタリング
(🎨:art):コードのフォーマットを整える時(自動整形されたのも含む)
(🔧:config):設定ファイルの追加・更新(linterなど)
(✅:test):テストファイル関連(追加・更新など)
(🚚:move):ファイルやディレクトリの移動
(🎉:start):プロジェクトの開始
(🚀:deploy):デプロイする

とりあえずこれで進めてみる

ふくえもんふくえもん

リベンジ 〜自作scriptをhuskyで実行させる〜

上記のやり方ではうまくできなかったので、自作のgit-hooksを定義して、実行するようにする。
https://qiita.com/MasaoSasaki/items/f10ab4cd54e228fb436f

ふくえもんふくえもん

完成した...

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

#!/bin/bash

echo -e "\033[37;1m🪝 Running Git Hooks: commit-msg\033[0m"
# コミットメッセージを定義
MSG="$(cat "$1")"
readonly MSG
# 終了コードを定義。0: OK 1: NG
code=0

# gitmojiの存在チェック
echo -en " - gitmojiの存在チェック: "
readonly GITMOJI="✨|🐛|📝|💄|♻️|⚡️|✅|🎨|🚀|🩹|🔥|🚚|🔧|🎉"
if ! echo "$MSG" | grep -Eq "^(${GITMOJI}).*"; then
    echo -e "\033[31;22mNG"
    echo -e "================================================================"
    echo -e "コミットメッセージに有効なgitmojiが含まれていません。"
    echo -e ""
    echo -e "Valid gitmojis: ✨ 🐛 📝 💄 ♻️ ⚡️ ✅ 🎨 🚀 🩹 🔥 🚚 🔧 🎉"
    echo -e "================================================================\033[0m\n"
    code=1
else
    echo -e "\033[32;22mOK\033[0m"
fi


# Prefixの存在チェック
echo -en " - Prefixの存在チェック: "
## 必要なPrefixを定義
readonly CORRECT_PREFIXES=('feat' 'fix' 'docs' 'style''refactor' 'perf' 'test' 'art' 'deploy' 'typo' 'fire' 'move' 'config' 'chore' 'revert' 'custom-type' 'start')
## 各要素に": "を追加
for i in "${!CORRECT_PREFIXES[@]}"; do
  correct_prefixes[i]="${CORRECT_PREFIXES[i]}: "
done
## `grep -E`で配列からOR検索をするため、半角スペース(" ")の区切り文字をパイプ("|")に変更
prefixes="$(
  IFS="|"
  echo "${correct_prefixes[*]}"
)"
if ! echo "$MSG" | grep -Eq "${prefixes}"; then
  echo -e "\033[31;22mNG"
  echo -e "================================================================"
  echo -e "コミットメッセージにPrefixが含まれていません。"
  echo -e ""
  echo -e "Prefix"
  echo -e "  ${correct_prefixes[*]}"
  echo -e "================================================================\033[0m\n"
  code=1
else
  echo -e "\033[32;22mOK\033[0m"
fi

# issue番号の存在チェック
echo -en " - issue番号の存在チェック: "
readonly ISSUE_NO="\#[1-9]"
if ! echo "$MSG" | grep -q "${ISSUE_NO}"; then
  echo -e "\033[31;22mNG"
  echo -e "================================================================"
  echo -e "コミットメッセージにissue番号が含まれていません。"
  echo -e ""
  echo -e "Example: #1234"
  echo -e "================================================================\033[0m\n"
  code=1
else
  echo -e "\033[32;22mOK\033[0m"
fi

# コミットメッセージ形式のチェック
echo -en " - コミットメッセージ形式のチェック: "
## 指定された形式の正規表現を定義します
readonly FORMAT_REGEX="^(${GITMOJI}) *(${prefixes}) *${ISSUE_NO} *.+"
if ! echo "$MSG" | grep -Eq "${FORMAT_REGEX}"; then
    echo -e "\033[31;22mNG"
    echo -e "================================================================"
    echo -e "コミットメッセージが指定された形式に従っていません。"
    echo -e ""
    echo -e "Expected Format: <gitmoji><Type>:<#issue番号><内容>"
    echo -e "Example: ✨feat: #1234 Implemented a new feature"
    echo -e "================================================================\033[0m\n"
    code=1
else
    echo -e "\033[32;22mOK\033[0m"
fi


# 終了宣言
if [ ${code} -eq 0 ]; then
  echo ""
  echo -e "\033[32;1m✨ALL PASS!!\033[0m\n\n"
else
  echo ""
  echo -e "\033[31;1mGit Hooks: commit-msg: NG\033[0m\n\n"
fi

exit ${code}