※本エッセイはすべて創作です。登場するコミット例・リポジトリ・出来事はすべて架空のものであり、実在のいかなる個人・組織・プロジェクトとも関係ありません。
シライショウタ(ポエマイゼーション:ソノダマリ)
ある朝、あるリポジトリ(コードを保管する倉庫のようなもの)の履歴を眺めていて、目を疑った。fixとだけ書かれたコミット——コードに加えた変更ひとつぶんの記録——が、47件、縦に並んでいた。
47件、全部 fix。直しただけは伝わる。何を直したかは一切わからない。最初の fix から最後の fix まで、3週間。3週間ぶんの「直した」が、一語の塔になっている。
その隣のリポジトリでは、最終コミットが3年前の日付で止まっていた。WIP: refactor in progress(作業中:書き直し進行中)。3年経っても in progress のまま。リポジトリの墓場。
コードの差分は、機械が読む。コミットメッセージ(変更に添える短文)は、半年後の他人と、半年後の自分が読む。前回はコードの中のポエマイゼーション(事実が印象に変わる現象)を見た。今回はコードの後ろにある短文を見る。
Conventional Commits(カンベンショナル・コミッツ)という規約がある。コミットメッセージの先頭に feat: fix: refactor: といった「種別の札」を貼る——変更の種類を一目でわかるようにする、という目的の運用ルールだ。
札はだいたい次のように使い分ける:
feat: 新機能を足した fix: バグを直した refactor: 動きは変えずに書き直した chore: 雑務(ビルド設定や依存パッケージの整理など) docs: 文書だけを直した style: 空白とインデントだけ整えた build: ビルドの仕組みをいじった perf: 性能を改善した revert: 過去のコミットを取り消した
運用は健全に始まる。ところが半年もすると、規約はだんだん別のものに変質していく。
たとえば、ある日の俺のコミット:
refactor: improve readability of authentication module
翻訳すると「認証まわりのコードを、読みやすくなるよう書き直しました」。立派な札だ。実態はどうか。バグを踏んだ。原因が特定できなかった。仕方がないので関連箇所を全部書き直した。直ったかどうかも、半分くらいしか確信がない。けれど fix: と書くと「バグを直した記録」になり、どこを直したかをレビュアー(コードを審査する同僚)に問われる。怖い。だから refactor: と書く。refactor: ならば動きは変わっていないと宣言したことになり、どこを直したかではなく「読みやすさ」というあいまいな尺度で評価されるだけになる。
refactor: は、自分の理解の浅さを 「読みやすさ」という気持ちのいい言葉 に変装させる札だ。同じことが chore: bump deps(雑務:依存パッケージを上げた)でも起きる。「雑務です」と宣言する札の内側で、依存ライブラリを上げる過程で動作の細部が変わるケースが、ふつうに混じる。build: でも同じことが起きる。札を見ただけでは見抜けない。
札は、内容ではなく 「真面目さアピール」 として機能している。feat: add user authentication は「ちゃんとした機能を足しました」というメッセージで、コードレビューを通したい一心の prefix(接頭辞)だ。
そして、 札のなかでも特に強力なのが fix typo(誤字を直した) だ。fix typo と札を貼ったプルリクエスト(変更を取り込む申請)を、現場のレビュアーは2秒で承認する。誤字は誤字、見ればわかる、議論の余地はない、という前提で読み飛ばす。
だからプログラマーは、忙しい金曜の午後、本当はタイプミスだけではない変更にも fix typo と札を貼ってみたくなる瞬間がある。たとえば実態は3ファイルで合計80行、コメントの誤字に紛れて関数名のスペル修正を2箇所、ついでに引数の順序の入れ替え1箇所。札の表面は「typo」一語。レビュアーは2秒で LGTM(Looks Good To Me:見たかぎり問題なし)を打ち、コーヒーを淹れに行く。札がそのとき、ほんの少し、別の意味で機能している。実演してみせるまでもなく、現場のプログラマーはこの呼吸を知っている。俺も知っている。
コミットメッセージの中には、書き手が自分を守るための言葉が、いくつか定型化している。
WIP: not ready for review yet, just pushing for backup hotfix: temporary workaround for staging bug, proper fix later revert: revert "refactor: clean up auth flow" — broke prod chore: small cleanup, nothing important
ひとつずつ翻訳する。WIP は Work In Progress(作業中)の略で、「まだ見せられる状態じゃないので批判しないでほしい」という事前の盾。hotfix: temporary workaround は「いまは応急処置です、本格対応はまた後日」という時限つきの言い訳で、ほぼ百発百中で「また後日」は来ない。revert は自分が前に入れたものを取り消す札で、ここに「broke prod」(本番を壊した)と添える書き方は、 失敗の自己申告のあらかじめ短い形 だ。chore: small cleanup, nothing important は「重要じゃない掃除なので深く読まないでください」という事前の鎮静剤。
共通しているのは、 批判される前に自分で自分を弱く見せる 構造だ。完璧な仕事ですと宣言してから批判されるよりも、「未完成です」「応急処置です」「重要じゃないです」と先に申告して、批判の角度をあらかじめ削っておく方が、心が痛まない。
俺も、月曜の朝に WIP を盾にした朝がある。週末の作業の中途半端な状態を、月曜の自分のためにバックアップ目的でプッシュ(サーバへの送信)する。not ready for review yet と添える。誰もまだ見ていないし、レビュー要求もしていない。それでも盾を先に立てる。
ソノダマリのポエマイゼーションでいえば、これは 変装 だ。「自信がない」を「Work In Progress」に変装させる。「壊れているけど直す気力がない」を「temporary workaround」に変装させる。マンション広告が「駅から遠い」を「閑静な住宅街」に変装させるのと、修辞の構造はぴったり同じだ。
自己防衛の反対側に、自己誇示の文法がある。
🎉 Initial commit ✨ feat: dark mode lands 🚀 ship onboarding v2 🔥 nuke unused config keys 🐛 fix: rare race in payment retry
絵文字。クラッカー、キラキラ、ロケット、火炎、虫。Gitmoji(ギットモジ)という非公式な慣例があって、コミットメッセージの先頭に絵文字を貼ると、変更の種類が一目でわかる、というのが建前だ。クラッカーは初回コミット。キラキラは新機能。ロケットはリリース。火炎はコード削除。虫はバグ修正。
建前は便利だ。しかし運用の実態は、 儀式 だ。クラッカー絵文字を打った瞬間、書き手は「お祭り感のあるエンジニア」になる。ロケットを打った瞬間、 俺たちは出荷した、世界を変えた という気分が、リポジトリの履歴に刻まれる。火炎絵文字でコードを200行消すと、ただ削除しただけのコミットが「果敢に焼き払った勇気あるリファクタリング」に昇格する。
俺は、人生で初めて 🚀 を打った日のことを覚えている。前職を辞めて、知り合いに誘われた12人のスタートアップに移った最初の週、Slackの開発チャンネルで「コミットメッセージはみんな絵文字使ってるから合わせてね」と言われた。前の会社では絵文字どころか、コミットメッセージは「[チケット番号] 概要」の四角い形しか書いたことがなかった。指が止まった。:rocket: とタイプして、自動補完を確定して、コミットして、プッシュした。指先がほんの少し他人の指のように感じた。それが 🚀 ship initial onboarding という6語の最初のロケットだった。打った瞬間、自分のコミットメッセージが急に他人のもののように見えた。
これは増幅だ。「コードを足した」という単純な事実に、ロケットの絵文字を貼ると、 「世界を出荷する人間」 というキャラクターが補填される。中身は同じ git diff だ。札が違うだけで、書き手の自己像が変わる。
🚀 ship it という4文字の英語と1個の絵文字には、驚くほど多くの自己誇示が圧縮されている。「俺は出荷する人間だ」。出荷できないチームを批判する含みもあれば、自分が議論より行動を選ぶ性格だと表明する含みもある。commit という英単語自体が「献身」「決意」を含む語だ——書き手はその語を毎日使っている、という事実だけでも、職業的なキャラクターの強化として効いている。
同じ「コードを変えた」という出来事が、書き手の所属によって三種類の文体に分かれる。これは現場を移ってきた人間にとっては、見ていて面白い現象だ。
スタートアップ(架空のSaaS企業、社員12名)。絵文字とポップな英語が走る:
🎉 LFG 🔥 nuke the legacy auth 🚀 shipped onboarding flow v2 👀 @taro looks good?
LFG は Let's F***ing Go の略——日本語にすれば「いくぞ」くらいの勢いの語だ。looks good? は同僚へのメンションつきの問いかけ。コミットメッセージが、もはや履歴ではなくチャットになっている。書き手の高揚感がそのまま流れ込む。宛先は 「現在の高揚」 だ。今このスプリントを生き延びている12人の仲間にだけ、伝わればいい。
大企業(架空の金融系SIer、開発本部)。チケット番号と formal な日本語:
[FIN-2847] 顧客検索画面における検索条件の初期値変更対応 - 課題管理No: KMS-19283 - 影響範囲: 顧客検索画面のみ - 回帰テスト: SCN-014, SCN-018, SCN-021 - 障害ランク: C - レビュアー: 川崎、岡本 - 動作確認: ステージング環境にて確認済み
絵文字はゼロ。固有名詞すら少ない。代わりにチケット番号と影響範囲と回帰テストと障害ランクとレビュアー名が定型で並ぶ。テンプレートはたぶん社内Wikiに「コミットメッセージ規約 v3.2」として15ページぶんくらいある——空欄を全部埋めることが、ほぼ仕事の一部だ。書き手の俺の同僚に、大企業から転職してきた人間がいるが、最初の頃、社内Wikiを開かないとコミットメッセージが書けない、と冗談半分で言っていた。
このコミットの宛先は、書いている本人ではない。半年後にこの画面のバグを踏んだ別チームの担当者が、第一報として参照する文書だ。「障害発生時にどこを見るか」「誰が承認したか」「どこまでテストしたか」を、一通のコミットで完結させるよう、テンプレートが設計されている。個人の声を消すことが、組織の説明責任の代わりになっている。 宛先は 「組織の監査」 だ。
OSS(架空のミドルウェア・プロジェクト)。丁寧な英語と Co-authored-by(共同著者)の表記:
backend/router: avoid double-locking when retrying connection When a transient error occurs, the previous implementation could re-enter the lock, leading to a deadlock under heavy load. This patch reorders the cleanup path so that the lock is released before retry. Fixes #4827 Reviewed-by: Sato Kenji Co-authored-by: Park Minji
主語は静かで、変更の動機・問題・解決法・参照Issueの番号・レビュー者・共同著者が、決まった順序で並ぶ。コミットの一通が、 世界中の知らない誰かに対する手紙 として書かれている。宛先は 「未来の他者」 ——3年後にこのコードを読んで「なんでこうなってるんだ」と思った人に、過去から返事を書いている。
同じ「ロックを直した」という出来事が、スタートアップでは 🔥 fix lock bug の3語、大企業では [FIN-2847]の四角い書式、OSSでは段落つきの説明文になる。三国に分かれる。事実は同じなのに、書き手の自己像と読者層の違いが、文体を完全に書き換える。
面白いのは、人が会社を移ると、3週間ほどで文体が乗り換わることだ。俺の同僚で、スタートアップから大企業に転職した人間がいた。最初の月、開発チャンネルでの絵文字使用率が体感で8割。二ヶ月目には2割を切った。本人に聞くと「絵文字を打つと、レビュアーに『真面目に書け』と返される」のだという。文体は、その人の頭の中ではなく、デスクの位置と上司の顔色のほうから生えてくる。
23歳のころ、初めての会社で、初めて任された機能のリリース直前、深夜2時に俺は書いた:
fix everything
2語。今読み返すと、何が「すべて」だったのかが、もう自分でもわからない。git log(履歴の閲覧)を遡って、その日の git diff を開いてみても、推理小説を読むみたいに当時の自分を再構成しないと、何を直したのか復元できない。
当時の俺は、テストが落ちていて、原因が特定できなくて、リリース時刻が迫っていて、しかしどうしても何かをコミットしないと先輩に怒られる、という状態だった。怒られたくなかった。だから動くようになるまで雑に直して、最後に fix everything と打ってプッシュした。
git push --force(履歴を強制的に上書きしてサーバに送る、危険な操作)を打つときに、指先が震えていたのを覚えている。エンターキーを押すまでに、たぶん5秒くらい止まった。プッシュが終わったあと、Slackの開発チャンネルに「デプロイ完了しました」とだけ送って、すぐに通知をミュートした。誰も何も返してこないでほしかった。先輩からの「ありがとう」も「お疲れさま」も、その夜は受け取りたくなかった。
家に帰る終電に間に合わず、タクシーに乗った。背中が汗で冷たく濡れていて、運転手のラジオから知らない曲が小さく流れていた。それを聞いていない。後部座席で、隣に乗っていない誰かのほうに頭を傾けて目を閉じた。マンションのエントランスに着いて、メーターを見て、領収書をもらわずに降りた。経費で落とすつもりだったのに、領収書を頼むのを忘れた。それを翌週、申請しなかった。fix everything という札と一緒に、3,800円ぶんの自費がそこにある。
その夜の俺は、「すべて」と書くしかなかった。何を直したか、自分でわかっていなかったから。「すべて」の中には、本来直してはいけなかった箇所も混じっていたかもしれない。テストが通ったから良し、と判断した。
5年後の俺がこのコミットを読み返すと、 23歳の俺の不安が、消されないまま、まだそこにある 。「fix everything」という2語の後ろに、夜中の2時の蛍光灯と、震える指と、ミュートしたSlackと、3,800円の領収書のない夜が、消えずに残っている。git rebase(履歴の書き換え)で消そうと思えば消せる、しかし共有されたあとはもう消せない。 23歳の俺の不安は、今も誰かのリポジトリの履歴に残っている。
もうひとつ、コミットメッセージには、書き手と現在のレビュアー以外に、 もう一人の読者 が想定されている。
その読者は、半年後にバグを踏んで「いつから壊れていたんだ」と git blame(変更箇所がどのコミットから来たかを表示する機能)を打つ別のプログラマーかもしれない。あるいは、3年後にこのプロジェクトを引き継ぐ次の担当者かもしれない。あるいは、退職後に「この人ってどんなコードを書く人だったの」と次の採用面接でリポジトリのURLを開いている自分自身かもしれない。
俺は、後任者の git blame のシーンを、ときどき頭の中で再生する。3年後のある夜、誰かがバグを踏んで、原因を特定するために git blame backend/router.go を打つ。該当行に、「shirai」という著者名と fix everything というメッセージが出る。後任者は数秒、画面を眺めて、ため息をついて、Slackで誰か別の同僚に「これ、何してるかわかる?」と聞く。聞かれた同僚も知らない。俺の23歳の夜が、3年後の誰かの2時間ぶんの労力に変換されている。
コミットメッセージは、未来の他者の目線をいつも背負っている。だからプログラマーは、未来の誰かに自分がどう見えるかを、毎日少しずつ計算しながら、短文を書いている。
5年前の fix everything は、5年後の俺の採用面接で、もし誰かに見られたら、たぶん「この人は丁寧じゃない」と判定される。それを当時の俺は計算しなかった。23歳の俺は、目の前のリリースしか見ていなかった。
5年経って計算するようになった俺は、いま refactor: improve readability と書く。これは将来の俺の採用面接に向けて書いている札でもある。
git diff は、機械が読む。コードが動くか動かないかを判定する。
コミットメッセージは、半年後の他人と、半年後の自分が読む。自己防衛と自己誇示と他者監査の三つ巴で、言葉が選ばれる。 WIP と書く朝、 🚀 ship it と書く昼、refactor: と書く夕方、fix everything と書く深夜。書き手の精神状態が、短文として履歴に積まれていく。
プログラマーは、毎日少しずつ、自分の墓碑銘を書いている。git log --author="shirai" を打てば、白井翔太がいつ何を恐れていつ何を誇示しようとしていたか、5年ぶんが時系列で並ぶ。書いている本人以外には、ほぼ誰も読まない。けれど履歴は、消えない。
前回のエッセイで、コードの中にもポエマイゼーションがあると書いた。今回見たのは、コードの後ろに張り付いた短文の中にあるポエマイゼーションだ。ソノダマリの6操作——補填、翻訳、蒸発、消去、変装、増幅——のうち、コミットメッセージで特に濃いのは 変装 と 増幅 だ。「自信のなさ」を WIP に変装させ、「コードを消した」を 🔥 ship it で増幅する。
47件の fix が縦に並んだあのリポジトリの書き手は、いまどこかで生きていて、今日も誰かのコミットメッセージを書いている。3年前で止まっている WIP: refactor in progress の書き手も、たぶんどこかで別のリポジトリを使っている。墓場のコミットを残したまま。
俺の墓場のコミットも、どこかにある。いつか、5年後の誰かに見つかる予定で、墓場でいまも待機している。
書き手・シライショウタ(Bot開発・API連携エンジニア)