Git Notes: Gitで最もクールで嫌われている機能(2022)
(tylercipriani.com)- Git notesは、Gitオブジェクトを変更せずに別の名前空間でメタデータを付与する機能だが、使い勝手の低さと採用の限定性から広く使われていない
- 古いコミットメッセージを修正しなくても新しい情報を追記できるため、レビュー・ビルド・チケット情報のように自動化システムが残す記録に向いている
- GitプロジェクトとGerritはnotesを実際に活用し、コミットごとのメーリングリストでの議論、テスト結果、レビュアー情報を
git logで確認できるようにしている - Googleのgit-appraiseはgit notesの上に分散コードレビューを実装し、レビュー依頼、コメント、レビュー、マージをローカルで行えるようにしている
- GitHubは2014年にコミットnotesの表示を停止し、blob・tree notesはGit内部コマンドに慣れている必要があるため、プロジェクト履歴の分散という可能性があっても使いにくい
Gitオブジェクトを変更しないメタデータ
- Git notesは、Gitが追跡するオブジェクトに別のメタデータを保存する機能
- 対象はコミットだけでなく、blobとtreeも含まれる
- オブジェクト自体を変更せず、別の名前空間に情報を付与する
- すでに履歴に入ったコミットメッセージは通常、安全に修正するのが難しいが、notesを使えば古いコミットにも新しい情報を追加できる
- 次のように
git notes add -mでメモを付けられるgit notes add -m 'Acked-by: <tyler@tylercipriani.com>' - その後、
git logでは該当コミットの下にNotes:ブロックとして表示される
- 次のように
- Scott Chaconは2010年のGitHub.blogで、notesを他の開発者との会話よりも、チケット・ビルドシステムのような自動化記録を付ける用途により適した機能だと見ていた
実際の活用と行き詰まる点
- Gitプロジェクトは、各コミットをメーリングリストでの議論と結び付けるためにnotesを使っている
- 例示コミットの
Notes (amlog)にはMessage-Idが含まれており、この値がパッチ議論スレッドにつながる
- 例示コミットの
- notesは、コミットやブランチごとの作業時間追跡、
git logへのレビュー・テスト情報の追加、完全分散コードレビューといった用途にも使われる - Gerritのreviewnotesプラグインは、コードレビューメタデータをGit内でオフライン表示できるようにする
- notesを取得して表示するコマンドは次のとおり
git fetch origin refs/notes/review:refs/notes/review git log --show-notes=review - 表示情報には
Verified+1、Verified+2、Code-Review+2、Submitted-by、Submitted-at、Reviewed-on、Project、Branchなどが含まれる
- notesを取得して表示するコマンドは次のとおり
- Googleのgit-appraiseは、git notesの上に構築された「fully distributed code review」システム
- GitHub、GitLabのようなコードforgeから独立して動作する
- 変更レビューの依頼、変更へのコメント、レビューとマージをローカルコンピュータ上で実行できる
- Webインターフェースも含む
- 最大の弱点は使い勝手
- GitHubは2014年にコミットnotesの表示を停止した
- コミットnotesは
gitconfig設定により、自動fetchとgit log表示をある程度簡単にできるgit config --add \ remote.origin.fetch \ '+refs/notes/*:refs/notes/*' git config \ notes.displayRef \ 'refs/notes/*' - blobやtreeにnotesを保存するには、Gitのplumbingに慣れている必要がある
- Gitはコード履歴を分散するが、Gitリポジトリの多くの価値はGitHubのようなforgeの中に閉じ込められている
- git notesは、コードだけでなくプロジェクト全体の履歴を分散する道になり得る
1件のコメント
Hacker News のコメント
あまり知られていない別の機能として git trailers がある: https://alchemists.io/articles/git_trailers
コミット作成時に含められるキー・バリュー形式の構造化データで、一部のシステムはこれをメタデータの付与に使っている。たとえば Gerrit は Change-Id を付けるためにこの機能を使っている
PostgreSQL のさまざまなデータベースオブジェクトにテキストを付けられるようにするもの。PostgreSQL にも、編集可能な構造化キー・バリュー形式のデータベースオブジェクト用メタデータ機能があるとよさそう
[skip ci]を入れる代替として git trailers を使うことを最近知った。おそらくコミットメッセージを消費する下位システム側で、より簡単に取り除けるようにするためだと思う: https://docs.github.com/en/actions/managing-workflow-runs-an...なぜ最後の trailer でなければならないと強制しているのかは分からない。正規表現の都合かもしれない
オープンソースの upstream と作業しながら、
git rebase -iでブランチを完璧に整えたいときに便利だった。今なら、その情報は git trailers に入れるほうがよさそうに見える。Change-Id については、Git 自体にこの種の識別子があればツールも理解できるので良いと思う。コミットメッセージでコミットを識別するのは、特に MR でメッセージを変更できる場合には脆弱だ。コミット ID はコミットを一意に識別するが、同じ変更を別のコミットの上に移せる場合には有用な識別子ではない。ただし trailers は実際のコミットの一部で、notes はそうではないので、自分が使っていた用途には良い代替にはならなさそうコミットメッセージに手で入れるのと
--trailerフラグを使うのが、機能的に同じなのか気になるローカルでインスタンスを立てて、GitHub にホストされたリポジトリと統合しようとして、ただ挫折しただけだった。コミットをまたいだ変更追跡などを GitHub よりうまく扱い、なおかつより活発に開発されていて GitHub 連携にも親和的な代替があるのか気になる。GitHub のコードレビュー用ツールは本当に嫌いだ
Forgejo も今年1月に出たバージョン 10 から対応している: https://forgejo.org/2025-01-release-v10-0/#new-features
https://codeberg.org/forgejo/forgejo/pulls/4753
本当にすごく良さそうだが、amend や rebase のように、実質的にコミットを修正済みコピーに置き換える履歴の書き換え機能と notes がどう一緒に動くのか気になる
notes は特定のコミット、ツリー、blob ID に付くもののように聞こえる。
git rebaseなどが notes を新しいコミットへコピーするほど賢いのか、それとも単に消えてしまうのか気になる。インタラクティブ rebase で複数のコミットを1つに squash したらどうなるのかも疑問だ。blob やツリーに notes を付ける場合も同じ問題がありそう。リポジトリ内のファイルやディレクトリにメタデータを付けているように感じるが、実際には特定の内容に付けていることになる。たとえば"Hello world!"という文字列を含む blob に note を付けた場合、Git はその内容を持つすべてのファイルに note を関連付けるのだろうか? また、あるファイルを"Hello, world!"に変更すると notes を失うのだろうか?notes.rewriteの項目はgit-config(1)を見ればよいGit はたぶん10年ほど使ってきたが、git notes があるとは知らなかった。すごい
「すべての forge がコードレビューメタデータを Git 内でオフライン利用できるようにしてほしい」という要求は、GitHub のような商用 forge にはあまり通じなさそうだ。本人も言っているように、Git リポジトリの価値の多くが GitHub のような forge に閉じ込められているからだ。営利企業は通常、自社の付加価値を汎用化することに積極的ではない。GitHub を責めたいわけではなく、優れたサービスと非常に寛大な無料枠を提供していて、移行したければ API で全データを取り出せるようにしている点ではよくやっていると思う。ただ商業運営の本質がそういうものだというだけ
Git notes は、コミットがすでに作られて他人の目に触れたあとで、テキストを頻繁に追加する場合にだけ素晴らしい
Acked-By やメーリングリストでの議論へのリンクの例は、あまり良い例ではないように思う。どちらもコミットを作る時点ですでに分かっている可能性が高い。Git のコミットメッセージには事実上ほとんど長さ制限がないので、forge 上で行われたコミット関連の議論をコミットメッセージ自体にそのままコピーすることもできる。より良い例は、あとで revert されたコミットに git note を追加する場合だと思う
自分が変なのかもしれないが、コードがそもそもなぜ書かれたのかを思い出そうとして、コメントや annotate をちゃんと見ない同僚をあまりにも多く見てきた。とにかくいきなり変更して、問題が自分に結び付かないことを願うようなやり方だ。だが、バグ修正を待ち続けていた怒った顧客を相手にし、その後まもなくそのバグが再発するのを経験すると、バグ修正にはもっと慎重になれる。複数のバグを一度に直すにはリファクタリングが必要なことが多く、リファクタリングは新機能の機会や性能改善につながることもある
あとで revert されたコミットに印を残す用途なら、コミットメッセージのほうがよい。ファイルに対して blame すればそのファイルの最新の変更が見え、あるコミットが別のコミットの変更を revert しているなら、より新しい revert コミットが blame に現れる
これは知識不足ではなく UI の問題。GitHub の UI が notes を表示すれば、利用はすぐにはるかに増えるはず
「Git の最もクールだが愛されていない機能」はたくさんある。たとえば bisect、pickaxe、reflog、range-diff、archive、annotated tags など
多くの人が Git を派手な Google Drive 程度にしか考えていないため、こうした機能がよく忘れられてしまうのは残念
それでも問題ないと思う。Unix 哲学は、1 つのことに集中し、それをうまくやることだから
LibreOffice プロジェクトでは、Apache OpenOffice リポジトリの各コミットを追跡するために Git notes を使っていた
そのリポジトリを LibreOffice Git リポジトリのブランチとしてミラーしながら、各コミットが無関係な変更なのか、たとえば LibreOffice がずっと前により良いものへ置き換えたビルドシステムの変更なのか、すでに LibreOffice にあった変更と重複しているのか、あるいはまれなケースとして LibreOffice に取り込まれたのか、どのコミットとして cherry-pick されたのかを記録していた。今でも https://cgit.freedesktop.org/libreoffice/core/log/?h=aoo/tru... で直接見ることができ、この Git フロントエンドはいまも notes を表示する。数年前からはこうした変更追跡をやめているが、おそらく Apache OpenOffice の変更ペースが非常に遅くなり、わずかな変更を cherry-pick して得られるメリットがあまりなくなったためだろう
最もクールだが愛されていない機能というより、会社全体を開発者だけで運営するチームのような、かなり特定のケースではクールだったかもしれない ギミック機能 に近い
必要なものはコミットメッセージに入るし、別システムのチケットを参照するのはバグではなく機能だ。JIRA や他のシステムは非開発者とコミュニケーションするために使われるからだ。たとえばビジネスアナリストはコードにもリポジトリにもまったくアクセス権がなく、サポート担当者もリポジトリやコードにアクセスできない。非開発者が notes を見たり編集したりできるフロントエンドを作ることはできるが、それでもあまり意味はない。ビジネスアナリストやサポートチームなどは特定のコミットには関心がなく、1 つの機能が 1 つのコミットにぴったり対応することもあるが、普通はそうではない。複数のリポジトリを使い、1 つの機能が複数のサービスにまたがると、git notes はかなり役に立たなくなり、結局は外部システムへの参照が必要になる
しかし、それが主流だ。ときどき、同じモノレポを共有している別チームのアナリストが、コード 1 行を見ればすぐ答えられる質問を私にしてくる。そのアナリストは技術寄りで SQL も分かるし、私たちのコードは非常に慣用的で高レベルに書かれている。それでも文化というものは、内在する非効率によって死に至るまでは自ら変われない
[^1] https://news.ycombinator.com/item?id=44348438
GitLab の notes サポートを求める 9 年前の機能リクエスト が最近クローズされた: https://gitlab.com/gitlab-org/gitlab/-/issues/15029
残念ながら読むにはログインが必要だが、どの gitlab.com アカウントでもよいはず