コミットメッセージは「大切な資産」だと思う


皆さんのチームや、個人開発でも Git は使っていると思いますが、
その中で、何かしらの「**コミットルール**」ってあると思います。

でも、よく見てみると、**意外とルールが曖昧だったり、なんとなく運用されてるだけ**というケースもあるんじゃないでしょうか。

<img width="200" alt="ルールが曖昧" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/884ea61c-5619-494d-82c3-38ce812e9577.jpeg">

コミットメッセージって、システムの「**開発の歴史**」であり、「**資産**」だと自分は思っています。
過去のコミットを振り返ることで、**なぜそのコードが実装されたのか・どういう経緯だったのか**が見えてきます。

<img width="200" alt="開発の歴史" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/a357b5d2-a329-476f-9caf-db5b76043183.jpeg">

それに、コミットメッセージは**他の開発者がコードを理解するための大事な手がかり**にもなります。
「コードだけじゃ意図が読み取れない」とき、メッセージがヒントになることって多いですよね。

個人開発でもこれは同じで、
しばらく時間が空いたあとにコードを見返したり、過去の実装を流用しようと思ったとき、
**コミットメッセージがあると「あーそうそう、こういう処理にしたんだった！」って思い出しやすくなります。**

ということで今回は、
**これまで自分がチーム開発や個人開発で考えて・試して・実際に運用してきた「コミットルール」** について、まとめてみようと思います。

## 🔐 コミットルールを決めておこう

<img width="200" alt="コミットルールを決める" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/2c100e47-03dc-470c-b0e0-e8842a02a482.jpeg">

まず最初に、**コミットルールをあらかじめ決めておくこと**が大切です。

ルールがあることで、チーム全体で**統一感のあるコミットメッセージ**を書けるようになり、
あとから履歴を追いやすくなりますし、レビューもスムーズになります。

特にチーム開発では、**お互いの認識を揃えておくこと**も重要です。
人によって「粒度」や「書き方」の感覚が違うこともあるので、
ルールを作ったらちゃんと共有して、**チーム全体で共通の認識を持つこと**が大切です。

### コミットの目的をはっきりさせる

コミットには、必ず **「目的」** があります。
「どのくらいの単位でコミットするか？」よりも、まずは **何のためのコミットなのか** を考えるようにしています。

自分は、**1つの目的に対して1コミット（1目的＝1コミット）** を意識してコミットしています。

ここで言う「目的」というのは、たとえばこんな感じです：

* ログイン機能の実装
* コンポーネントのUI修正
* 内部処理のリファクタリング

つまり、**何をするコミットなのか？がはっきりしていること**が大事です。

たとえば、こんなコミットメッセージはNGです：

```text
❌ NG例）
ログイン時にセッション情報が保存されない問題を修正、併せてリファクタリングを行う
```

このコミットには **「バグ修正」と「リファクタリング」という異なる目的** が混ざっています。
目的が複数あると、履歴を見たときに「この変更は何のため？」がわかりにくくなります。

なので、目的ごとにコミットを分けて、こう書くのが理想です：

```text
✅ OK例）
ログイン時にセッション情報が保存されない問題を修正
```

```text
✅ OK例）
ログイン機能の内部処理をリファクタリング
```

このように、**「何のための変更なのか」がひと目で伝わるように、目的ごとにコミットを分ける**と
あとから履歴を見返すときにもとてもわかりやすくなります。

### コミットメッセージは「他人が読んでもわかる」ようにする

チーム開発をしていると、コミットは当然ながら**自分だけが見るものじゃない**ですよね。
特にコードレビューでは、**レビュアーがあなたのコミットメッセージを読んで内容を把握しようとする**ことが多いです。

でも、コミットメッセージがふんわりしてたり、ざっくりしすぎてると……

「これ、結局どこをどう直したの？」
ってなってしまって、**レビューしづらくなるんです**。

たとえば、こんなコミットメッセージはどうでしょう？

```text
❌ NG例）
ログイン機能を修正する
```

「どのへん？」「何のために？」「バグ？仕様変更？」って、読み手は迷ってしまいます。
こうなると、レビュアーは結局コードを全部追って調べる羽目に…これはつらい。

じゃあどう書けばいいかというと、こんな感じです：

```text
✅ OK例）
ログイン時にセッション情報が保存されない問題を修正
```

これなら「バグ修正」だとすぐにわかるし、**どこに注目してレビューすればいいのか**も明確。
**コミットメッセージは「未来の自分」と「他の人」が読んで理解できるか？** を意識するとかなり変わってきます。

コミットはメモじゃなくて「チーム全体への説明」みたいなもの。
少しだけ丁寧に書いておくだけで、レビューも履歴確認もすごく楽になると思います。

### コミットの粒度を揃える

コミットって、**細かく分けすぎても、全く分けなくても見づらくなる**ことがありますよね。
だからこそ、**適切な粒度（＝ちょうどいい分け方）でコミットする**のが大事です。

自分はどちらかというと「**できるだけ分散させない派**」。
というのも、あまりに細かく分けすぎると、**変更全体の流れが見えづらくなる**のが気になってます。

レビュアーにとっても「結局この変更って何のため？」が伝わりづらくなっちゃうので、
ある程度**意味のある単位でまとめた方が親切**だと思っています。

もちろん、改修ごとにちゃんとブランチを切って PR を出すなら、
コミットが細かくてもコンテキストは追えるんですが、
そのへんは**チームのルールや開発スタイル次第**かなと。
個人開発や小規模プロジェクトなら、**自分なりのルールを決めておくと後でラク**です。

たとえば、こんなケースを考えてみます。
「API通信処理を実装する」ときに、こんな感じでコミットを分けたとします。

```text
API通信処理を実装する
環境変数からベースURLを取得する処理を追加する
APIキーの読み込み処理を追加する
```

このままだと、パッと見たときに「バラバラの作業」に見えてしまうかもしれません。
でも実際には、どれも「**API通信を可能にする**」ための変更ですよね。

関連する内容なのに分かれていると、レビュアーは**各コミットを追いかけないと全体像が見えてこない**し、
あとから履歴を読むときも意図がつかみにくくなります。

なので、こういう場合は「**目的が共通しているなら、1コミットにまとめる**」という考えもありです。

たとえば、こんな感じに：

```text
feat: API通信処理を実装

- 通信処理を実装
- ベースURLを Info.plist から取得する処理を追加
- APIキーを読み込んでヘッダーに設定
```

タイトルでは「何をしたのか（API通信処理の実装）」をシンプルに書いて、
本文では**具体的な作業内容を箇条書き**にしておくと、レビュアーにも意図が伝わりやすくなります。

こうしておけば、**「意味のある1コミット」として履歴にもきれいに残る**し、
自分や他の人があとから見返すときにも理解しやすくなります。

## 📝 コミットメッセージのルールに従おう

<img width="200" alt="ルールに従う" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/9ad554e4-57f1-4268-af29-1de5512da499.jpeg">

コミットメッセージにも、「**こう書くといいよ**」っていうルールがあります。

### Semantic Commit Messages

Git のコミットメッセージには、**Semantic Commit Messages** という書き方のスタイルがあります。
ざっくり言うと、`<type>: <description>` という形で書くルールです。

[Semantic Commit Messages](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716/)

* `type`：どんな種類の変更か（何をしたのか）
* `description`：どんな内容の変更か（どうしたのか）

`type` には、以下のようなもの指定します：

| type     | 意味                     |
| -------- | ---------------------- |
| feat     | 新しい機能を追加したとき           |
| fix      | バグを直したとき               |
| docs     | ドキュメントだけを変えたとき         |
| style    | 空白やフォーマットなど、見た目だけ変えたとき |
| refactor | 中身を整理したけど、動作は変えてないとき   |
| perf     | パフォーマンスをよくしたとき         |
| test     | テストコードを追加・修正したとき       |
| chore    | その他の雑多な作業（ビルド設定の変更など）  |

この書き方に従えば、プロジェクトやチームでコミットの書き方を統一しておくと、履歴が見やすくなったり、自動で変更ログやリリースノートを作ったりできて便利です。

### Conventional Commits

**Semantic Commit Messages** はあくまで「こう書くといいよ」という**スタイルの提案**で、厳密なルールがあるわけではありません。

そこで登場するのが、厳密なルールとして定義された、**Conventional Commits** という**明確なルール付きのフォーマット**です。

https://www.conventionalcommits.org/en/v1.0.0/

基本の書き方はこんな感じです：

```text
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
```

* `type`：変更の種類（例：`feat`, `fix` など）
* `scope`（省略可）：どの機能やモジュールに関する変更か
* `description`：簡潔な説明
* `body`（任意）：詳しい説明や背景など
* `footer`（任意）：チケット番号や破壊的変更の宣言など

#### 🔥 破壊的変更（Breaking Change）を表すには？

**footer に `BREAKING CHANGE:` を書く**ことで、後方互換性のない変更があることを明示できます。

```text
BREAKING CHANGE: removed support for legacy API
```

または、**type や scope の後ろに `!` をつける**ことでも破壊的変更を示せます。

```text
chore!: drop support for Node 6
feat(api)!: send an email to the customer when a product is shipped
```

## 🛠️ コミットメッセージのフォーマットを決めよう

<img width="200" alt="コミットメッセージのフォーマット" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/4f84d576-0882-4ca3-890c-a54e52e12fb9.jpeg">

基本的には **Conventional Commits** をベースに、
そこに**絵文字**を加えた以下のフォーマットを使っています。

```text
<タイプ>(<スコープ(任意)>): <絵文字> <説明>
空白行
<本文(任意)>
```

コミットで「何をしたのか」を**ひと目でパッとわかるように**するために、
絵文字をうまく使って視覚的に伝わるようにしています。

絵文字は **gitmoji** を参考にして選んでいます。

https://gitmoji.dev/

### フォーマット例

**本文なし：**

```text
feat: ✨ ログイン機能の実装
```

**本文あり：**

```text
fix: 🩹 ログイン機能の不具合修正

ログイン時にセッション情報が保存されない問題を修正
```

:::note warn
**フォーマットを崩すときの注意点**

タイプ（`feat` や `fix` など）を**先頭に書かないスタイル**を使いたい場合もあるかもしれません。
その場合、`standard-version` や `git-cliff`、`semantic-release` といった
自動で変更ログやリリースノートを生成するツールの実行前に一手間加える必要があります。

そのため、できればタイプを先頭に書くスタイルを使うのがオススメです。
:::

### タイプと絵文字のルールを決めよう

コミットメッセージの先頭には、「**どんな種類の変更なのか**」を表す
**タイプ（`feat`, `fix` など）** と、**それに合った絵文字** をセットで付けるようにしています。

タイプはあくまで、**コミットの"目的"を表すもの**です。
たとえば、「リファクタリングの中で不要なファイルを削除した」という場合は、
`remove` ではなく `refactor` を使うのが適切です。

::: note info
コミットタイプは、**"何をしたか"** ではなく **"なぜやったか"**
を意識して決めるとブレません。
:::

**❌ NG例（物理的な操作に引っ張られてる）：**

```text
remove: 🔥 不要ファイルの削除
```

**✅ OK例（意図にフォーカス）：**

```text
refactor: ♻️ 不要ファイルの整理
```

#### 一般的なコミット

| タイプ | 絵文字 | 意味・目的 | 使うタイミング |
| --- | --- | --- | --- |
| Initial commit | 🎉 | 初回コミット（絵文字以降は不要） | リポジトリを新たに作成し初めてコミットを行う場合 |
| feat | ✨ | 機能の追加・変更 | 機能の追加や変更を行った場合 |
| fix | 🩹 | 不具合の修正 | **システムの仕様に影響を与える**機能の不具合修正を行った場合 |
| docs | 📚 | ドキュメントの更新 | README.mdの更新、設計書の更新などの文書化に関連する変更 |
| refactor | ♻️ | リファクタリング | **システムの仕様に影響を与えない**ソースコードの改善を行った場合 |
| design | 🎨 | デザインに関する修正 | UIデザインの変更、レイアウトの変更などのデザインに関連する変更 |
| style | 💄 | スタイルに関する修正 | 空白・インデント・セミコロンの追加や削除など、動作に影響しないコードの整形 |
| rename | 📝 | ファイル名変更 | ファイル名を変更した場合 |
| move | 🚚 | ファイル移動 | ファイルを移動した場合 |
| perf | ⚡️ | パフォーマンスに関する修正 | **システムの仕様に影響を与えない**パフォーマンスの改善を行った場合 |
| remove | 🔥 | ファイル削除 | 不要なファイルの削除を行った場合 |
| chore | 🔧 | 雑事（カテゴライズ不要のもの） | ライブラリの更新など、特定のカテゴリに分類する必要のない作業 |

#### 修正関連のコミット

「修正」といっても意味はいろいろあるので、`fix` だけでなく、`update` や `change`、`bug` などのタイプを使い分けることもあります。


| タイプ | 絵文字 | 意味・目的 | 使うタイミング |
| ------ | --- | ----------------- | ------------------------------------------- |
| update | 🆙 | 機能の軽微な変更・改善 | バグではないが、既存の機能に手を加えて調整や改善をしたいとき |
| change | 🔄 | 機能の仕様変更 | 仕様そのものが変わったことで、既存の機能を変更する必要があるとき |
| bug | 🐛 | 実装ミスなどによる明確なバグの修正 | **システムの仕様に影響する**不具合（例：誤ったロジック、条件分岐ミスなど）の修正時 |

#### ビルドやテスト関連

| タイプ | 絵文字 | 意味・目的 | 使うタイミング |
| --- | --- | --- | --- |
| test | ✅ | テストコードに関する修正 | テストコードの作成や修正を行った場合 |
| build | 👷 | ビルドに関する修正 | ビルド設定の変更、Jenkinsfileの修正などのビルドプロセスに関連する変更 |

#### コミット関連

| タイプ | 絵文字 | 意味・目的 | 使うタイミング |
| --- | --- | --- | --- |
| revert | ⏪️ | コミット取り消し | 特定のコミットを取り消した場合 |
| merge | 🔀 | マージコミット | 複数のブランチまたはコミットをマージした場合 |

#### その他

これは、私が個人的に気に入って使っているものです。
広告やアプリ内課金、プロモーションなど、一般的なタイプでは分類しづらいものには、専用のタイプを作って使うようにしています。

| タイプ | 絵文字 | 意味・目的 | 使うタイミング |
| --- | --- | --- | --- |
| ad | 📢 | 広告に関する修正 | 広告の追加や修正を行った場合 |
| storekit | 💳 | StoreKitに関する修正 | StoreKitの追加や修正を行った場合 |
| localize | 🌐 | ローカライズ | 多言語対応のためのローカライズに関する変更 |
| promotion | 🎯 | プロモーション | プロモーションに関する変更 |
| package | 📦 | パッケージに関する修正 | パッケージのバージョンアップや依存関係の変更など、パッケージに関連する変更 |
| version | 🔖 | バージョンアップ | バージョンアップを行なった場合 |

### 説明

私がコミットを書くときに意識しているポイントは、以下のようなことです。

* どんな変更かがひと目で分かるように書く
* 「〜する」や「〜を追加する」など、**命令形**で書く
* できるだけ **50文字以内** に収めて、簡潔にまとめる

**例：**

```text
feat: ✨ ログイン機能を実装する
```

```text
fix: 🩹 ログイン失敗時にパスワードがクリアされるように修正する
```

### 本文

コミットの本文には、その変更についての**詳しい説明**を書きます。
「何をしたのか」「なぜそうしたのか」といった背景や意図を書いておくと、
あとで見返したときにとても分かりやすくなります。

```text
feat: ✨ ログイン機能を実装する

ログイン画面を配置して、ユーザー名とパスワードによるログイン機能を実装しました。
```

また、GitHub や Redmine などのタスク管理ツールを使っている場合は、
どの Issue やチケットに対応しているかを明示しておくと便利です。
`refs #123` などのように書いて、コミットとリンクさせましょう。

このような情報は、説明の最後やフッターに書くのが一般的ですが、
チームのルールに従って書く場所を統一すると良いと思います。

```text
feat: ✨ ログイン機能を実装する refs #123

ログイン画面を配置して、ユーザー名とパスワードによるログイン機能を実装しました。
```

```text
feat: ✨ ログイン機能を実装する

ログイン画面を配置して、ユーザー名とパスワードによるログイン機能を実装しました。

refs #123
```

## 💡 サンプル

フォーマットに沿ったコミットメッセージのサンプルをいくつか紹介します。
そのままコピペして、内容を自分の変更に合わせて書き換えて使えます。

### Initial commit

```text
🎉 Initial commit
```

### feat

```text
feat: ✨ ログイン機能を実装する

ログイン画面を追加し、ユーザー名とパスワードによる認証処理を実装しました。
```

### fix

```text
fix: 🩹 ログイン時にクラッシュする不具合を修正する

パスワード未入力時にアプリがクラッシュする問題を修正しました。
```

### docs

```text
docs: 📚 READMEに環境構築手順を追記する

初期セットアップに必要なコマンドと前提条件をREADMEに追加しました。
```

### refactor

```text
refactor: ♻️ 認証処理の内部ロジックを整理する

可読性向上のため、冗長な条件分岐を関数に分離しました。動作に変更はありません。
```

### design

```text
design: 🎨 ログイン画面のUIを調整する

ボタンの配置と配色を調整し、見た目を改善しました。
```

### style

```text
style: 💄 インデントとスペースの統一を行う

コードフォーマッタに従って自動整形を実施しました。動作への影響はありません。
```

### rename

```text
rename: 📝 LoginViewController → AuthViewController に名称変更

クラス名が処理内容に合うようリネームしました。処理内容は変更していません。
```

### move

```text
move: 🚚 AuthView を Components ディレクトリに移動する

構成整理のため、UIコンポーネントを共通ディレクトリに移動しました。
```

### perf

```text
perf: ⚡️ 画像の読み込み処理を非同期化する

パフォーマンス向上のため、画像読み込み処理をバックグラウンドで実行するよう変更しました。
```

### remove

```text
remove: 🔥 使用されていないデバッグ用ファイルを削除する

不要になった `debug_user.json` を削除しました。
```

### chore

```text
chore: 🔧 ライブラリの依存関係を最新に更新する

`Alamofire` を 5.10.0 にアップデートしました。
```

### update

```text
update: 🆙 パスワード入力欄のバリデーションを改善する

バリデーションルールに最低文字数と記号の必須条件を追加しました。
```

### change

```text
change: 🔄 ログイン制御の仕様変更に対応する

セッションの保持方法をCookieからTokenに変更しました。
```

### bug

```text
bug: 🐛 ログアウト後にログイン画面が表示されない問題を修正する

ナビゲーションスタックのリセット処理が抜けていたのが原因でした。
```

### test

```text
test: ✅ ログイン機能のユニットテストを追加する

成功・失敗パターンに対するテストケースを新たに追加しました。
```

### build

```text
build: 👷 CIのビルド設定を修正する

Xcodeのバージョン指定を16.0から16.3に変更しました。
```

## 🙌 おわりに

コミットメッセージは、開発の歴史を残す大事な記録だと思っています。
きちんと書かれているとコードレビューもスムーズになるし、
あとから履歴を追うときにもとても助かります。

コミットメッセージは自分のためだけでなく、
**他の人が読んでもわかりやすいように書く**ことが大切です。

日々の習慣として、丁寧にコミットメッセージを書くことを心がけていくと、
自然とプロジェクト全体がキレイに整っていく気がします。

ソースコードも、コミットメッセージも、やっぱり**キレイなのが好き**です。

## 🔗 参考リンク

**コミットメッセージ仕様:**
* [Conventional Commits - コミットメッセージ仕様](https://zenn.dev/sumiren/articles/418f593dbbf601)
* [コミットメッセージ規約 · GitHub](https://gist.github.com/minop1205/5fc4f6ef0ec89fb1738833ba25ae00a0)

**プレフィックス選定:**
* [【必須】Gitコミットの書き方・作法【prefix/emoji】](https://suwaru.tokyo/%E3%80%90%E5%BF%85%E9%A0%88%E3%80%91git%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%83%BB%E4%BD%9C%E6%B3%95%E3%80%90prefix-emoji%E3%80%91/)
* [【Git】コミットメッセージの先頭につけた方が良い単語リスト- prefix集 - #GitHub - Qiita](https://qiita.com/muranakar/items/20a7927ffa63a5ca226a)

**コミットメッセージの書き方:**
* [Gitのコミットメッセージの書き方（2023年ver.）](https://zenn.dev/itosho/articles/git-commit-message-2023)
* [ASCII.jp：gitmojiの絵文字ってどれを使えばいいの？ おすすめをご紹介](https://ascii.jp/elem/000/004/081/4081225/)
* [伝わる！Gitコミットメッセージの書き方](https://zenn.dev/miz_dev/articles/how-to-write-git-commit-messages)