発端:たまった未コミット変更を「良い単位で」片付けたかった
family-trips は、家族で行った旅行をひとつのアーカイブにまとめている Astro + Cloudflare Pages のサイトだ。週末や夜に少しずつ触っているうちに、git status の赤と緑が画面を埋めるようになっていた。ディズニーランドのガイド、別府・湯布院方面のシミュレーター更新、ナビゲーション差し替え、宿泊の予約確定反映――テーマがバラバラのまま積み上がっている。
そのまま git add -A で一括コミットすると、後から git log を眺めたときに何が何の変更なのか追えなくなる。半年後の自分が「この行いつ入れたんだっけ」と git blame を叩く未来が見えたので、Claude Code に「良い単位でコミットしてプッシュしておいて」と一言だけ投げた。
コミット粒度:機能ごとに切ってもらって7コミットになった
/commit スキルにそのまま任せた。中で diff と新規ファイルを一通り走査してから、論理的な単位を提案してくる。今回返ってきた分割案はこんな並びだった。
- dev-server のログを
.gitignoreに追加 - memo ディレクトリの引き継ぎメモとスクリーンショット類
- ディズニーランドのガイドページ追加
- ナビゲーションの更新
- 別府方面の宿泊シミュレーターの再構成
- 大分の残3件の宿泊予約の確定反映
- 上記をまとめてプッシュ
提案を眺めて、特に違和感がなかったのでそのまま走らせた。1コミットずつメッセージを生成 → ステージ → git commit を順に流して、最後に git push。7コミットがリモートに乗ったところで、Cloudflare Pages の自動デプロイが裏でビルドを始める。
自分でやろうとすると、git add -p でハンクを選びながら頭の中でカテゴリ分けして、メッセージを毎回考え直して……と地味に重い作業だ。手は動かしても頭の負荷は集中力を確実に削る。差分を読んで「これとこれは同じテーマ」と判断する部分を AI にやらせると、自分は「7コミットで OK」と頷くだけで済む。
粒度分けの基準は、結局「後から git log を grep したくなる単位」
7コミットに分けてもらった並びを眺めて気づいたのは、どれも「後から検索したくなる単語」が独立しているということだった。
.gitignoreの変更は、別の開発環境で「dev サーバーのログがコミットされる事故」を調べるときに引きたい- memo の引き継ぎは、過去に何を考えていたか思い出したいときに引きたい
- ディズニー、別府、ナビ、宿泊予約――どれも別タイミングで「あれどこで直した」と探したくなる粒度
「機能単位」「日付単位」「カテゴリ単位」のどれで切るかと聞かれると毎回迷うが、git log --grep で自分が将来叩きそうな単語がちゃんと1コミットに閉じているか、で判断すれば外しにくい。Claude Code に粒度を任せるときも、「後から検索したくなる単位で」と添えれば外れ値が出にくくなりそうだ。
セキュリティレビュー:プッシュ直後にもう一度全変更を流す
コミットとプッシュが終わった直後、続けて Review this change for security vulnerabilities. と投げた。プッシュ前にやってもよかったが、コミットを分割した後の方がレビューする側も差分を読みやすい。1コミット = 1テーマなので、レビュー側も「このコミットでは何を見ればいいか」が一発で決まる。
レビュー対象は3グループに分かれた。
src/data/guides.jsonへの単純なデータ追加(ガイドの新規エントリ)- Vue コンポーネントのプレゼンテーション層リファクタ
- 別府方面の宿泊シミュレーターの構造リファクタ(
onsen→aquagardenのフィールド改名含む)
戻ってきた所見はどれも「No findings」だった。判定の根拠が短くまとまっていて、読みやすい。
- JSON はすべて開発者が書いた静的リテラル。
src/pages/index.astroで CSS 背景と/guides/<slug>の静的リンクとして消費されるだけで、攻撃者が触れる経路がない - Vue コンポーネントは入力が数値 ref のみ。テンプレート出力は全部
{{ }}の自動エスケープに通る。v-htmlも動的 class 合成もない - シミュレーターは静的な価格データに対する算術で、シェル/SQL/eval/FS/HTML 注入/ネットワーク/ログのどのシンクにも到達しない。
onsen→aquagardenの改名はScenario4型とsumScenario4の両方で揃っているので、レジストリ的な不整合もなし
「リネームが片側だけ漏れていないか」までチェック対象に入っていたのが地味にうれしい。型と集計関数のどちらかだけ古い名前のまま残っていると、ビルドは通っても挙動が崩れるパターンだ。
やってみて思ったこと
「コミット粒度を AI に判断させる」のは、何度か続けると安定する。 最初の数回は「自分ならもう少し細かく切る/もう少しまとめる」とズレを感じたが、3〜4回回すうちに自分の好みに合った提案が返ってくるようになった。スキル側のプロンプトに「機能・日付・カテゴリ別」と入っているのも効いている。
セキュリティレビューは分散コミット後の方が読みやすい。 一塊にした diff に「ここ大丈夫?」と聞くと、レビュー側は全テーマを同時に頭に入れる必要がある。コミット単位で意味が閉じていれば、レビュー側も「このコミットでは入力経路がない」「このコミットでは型の片側更新を確認」と1つずつ片付けられる。今回 No findings で終わったのは、レビューが軽かったというより、レビュー対象が読みやすい形に整っていたからだと思う。
家族旅行のサイトでも、ちゃんとセキュリティレビューを通す。 公開する以上、静的サイトでも入力経路はゼロではない(JSON にどう値が入るか、ユーザー操作で何が表示されるか)。「個人サイトだから」と素通りさせず、コミットの後に1コマンドだけ追加するのを習慣にしておくと、後で困らない。
1時間ほどの軽い片付けで、未コミット変更を整理し、リモートにプッシュし、セキュリティレビューまで通った。git status が真っ白になった画面を見て、ようやく今日の作業に区切りがついた気がした。