3 ポイント 投稿者 GN⁺ 2024-09-12 | 1件のコメント | WhatsAppで共有
  • GitHub式のPRレビューでは、元の変更の上に修正コミットを積み増ししやすく、レビュー過程と最終的なコード履歴が混ざってしまう問題がある
  • 良いパッチシリーズは、リファクタリング、新しいAPIの追加、既存利用者の移行のように、論理的に分離されたコミットを順番に読めるべきである
  • "fix review""minor" のようなコミットが積み重なると、変更意図がぼやけ、git blamegit bisect で問題の原因を探すコストが大きくなる
  • interdiff レビューでは、パッチシリーズの新しいバージョンを発行し、git range-diff main..v1 main..v2 でコミットごとの変更差分を比較する
  • レビュアーは500行全体を読み直さずに50行の増分だけを確認でき、作者は "address review" のようなノイズコミットなしで最終コミット構成を維持できる

コードレビューツールと出発点

  • Gerrit Code Review は Git リポジトリと連携して動作するオープンソースのコードレビューツールで、パッチを投稿し、他の人がコードをレビューしてコメントを残す流れを支援する
  • コードレビューの方式は、Gerrit、GitHub、Phabricator だけでなく、バグトラッカーに .patch ファイルを上げる方式、git send-email、同僚との長い議論の末に実装へ導く方式までさまざまである
  • Go プログラミング言語は Gerrit を使っており、KDE と LLVM は Phabricator を使っていた。また Jujutsu は Gerrit の利用を検討したことがある
  • Linux カーネルはメールベースのワークフローを独特のやり方で使っており、多くのプロジェクトは使いやすく導入コストの低い GitHub を選ぶ
  • 核心的な問題は、ツールごとに同じレビューのモデルを提供しているわけではなく、GitHub の標準的な体験が常に十分とは限らない点にある

良いパッチシリーズの条件

  • 理想的なパッチシリーズは、ひとつの大きな変更を論理的な段階に分けて提出する形である
    • まず偶然見つけたコード整理を行う
    • 次に新しい API を追加する
    • 最後に既存 API 利用者を新しい API へ移行する
  • 各パッチは独立した理由を持つべきであり、順番に適用したときにコードが段階的に進化していく様子が見えるべきである
  • この構造は、作者やレビュアーだけでなく、後で blamebisect によって変更理由を追わなければならないメンテナにも有利である
  • 実際のパッチサイズは状況によって変わる
    • リファクタリングがないこともある
    • 100行のこともある
    • 中核APIの変更のように、すべての呼び出し箇所を修正する必要があるなら500行になることもある

GitHub式「diff soup」が生む混合履歴

  • GitHub は、レビューコメントを反映するときに、元のコミットの上へ新しいコミットを追加する流れを明示的・暗黙的に促している
  • 例では、元の3コミットの後ろに、Alice と Bob のレビュー反映、テスト追加、"minor" 実装変更コミットが順に積み重なる
  • コミットグラフには親子関係しか残らないため、レビュー修正コミットが元のどのコミットのどの問題を直したのかは見えない
    • ひとつの "fix review" コミットが複数の元コミットを同時に触ると、概念モデルはさらに複雑になる
    • ひとつの修正コミットが厳密にひとつの指摘だけを反映するようにもできるが、その分 fixup コミットの数は増える
  • このように、大きな変更のまとまりとレビュー修正がひとつの器に混ざった状態が「diff soup」である

git blamegit bisect のシグナルがぼやける

  • git blame は行単位で動作するため、レビュー反映コミットが既存行のごく一部だけを変えた場合でも、その行の出所が "fix alice review" のようなコミットとして見えることがある
  • 実際の変更理由を見つけるには、元のコミットとレビュー修正コミットを追い直すコミット考古学が必要になる
  • git bisect でも、"minor" コミットが本当の原因なのか、新しい API が最初に追加された時点からあったバグが後になって表面化しただけなのかが不明瞭になりうる
  • 新しい API が大きな性能向上をもたらすなら、元に戻すのが望ましくない、あるいは不可能な場合もある
  • 回帰が数週間後に現れた場合、P1 会議のような緊急状況で、"minor" というコミットメッセージだけを見て追加調査しなければならないコストが発生する
  • レビューが2回往復しただけの例でも履歴は複雑になり、オープンソースプロジェクトのように何度もレビューが繰り返される場合は問題がさらに大きくなる

GitHub UX がこの流れを強化する仕組み

  • GitHub で増分レビューを行うには、新しいコミットを上に積む方式が事実上もっとも簡単である
    • 新しい API の500行を読み直すより、+/- 10 行の "fix alice review" パッチを見るほうがレビュアーの負担は小さい
  • PR の diff タブは、デフォルトではすべてのコミットをひとつの diff にまとめて表示する
    • これは git diff master..foo-branch を見るのに近い
    • しかし、これは人が変更を書き、読み取るやり方とはあまり合っていない
  • GitHub の UX は名前付きブランチモデルに強く最適化されており、ブランチ以外の単位同士の差分を見にくくしている
  • force push 後、PR の「Force Push」行にある「Compare」ボタンで diff を見ることはできる
    • ただし表示されるのは、以前のブランチ head と現在のブランチ head の全体 diffだけである
    • より細かい比較をしたければ、コミット ID を自分で探して URL に入れる必要がある

interdiff レビューと git range-diff

  • interdiff レビューでは、元の3コミットの上に修正コミットを追加するのではなく、同じ3コミットから成る新しいバージョンを発行する
  • たとえば v1 パッチシリーズで Bob のコメントを反映する必要があるなら、1つ目のコミットと3つ目のコミットを修正して v2 シリーズを作る
  • その後、Alice のコメント、テスト追加、"minor" 変更まで同じやり方で反映しても、最終結果は依然として3コミットのままである
  • v1 のコミット A、B、C が v2 の X、Y、Z へ進化したなら、git range-diff は各位置のコミット同士の差分を表示する
git range-diff \
  main..v1 \
  main..v2
  • このコマンドは、v1 ブランチの3コミットと v2 ブランチの3コミットの間にあるペアごとの差分を表示する
    • 1つ目のコミットは diff(A, X)
    • 2つ目のコミットは diff(B, Y)
    • 3つ目のコミットは diff(C, Z)

interdiff 方式の実務上の効果

  • GitHub が通常 diff(main, C)diff(main, Z) のようなブランチ全体の diff を見せるのに対し、interdiff はコミットバージョン間の差分を見せる
  • レビュアーは、すでに見た500行の API 変更を読み直すのではなく、修正された50行だけを確認できる
  • 作者は "address review" のようなノイズコミットを履歴に30個も積み上げずに済む
  • git blame は、より少ないノイズで元の変更コミットへ行を結び付けられる可能性が高くなる
  • git bisect は、回帰を新しい API コミットのような、より意味のある単位として指し示せる可能性が高くなる
  • 結果として、基本的な診断ツールの信号対雑音比が改善する

マージ戦略と rebase に関するメモ

  • パッチのマージ戦略に関する説明は TODO のまま残されている
  • git rebase は、公開ブランチの上に他の人がコミットを積み上げることが期待される場合でなければ問題ない、という立場である
  • interdiff レビューシステムは、より小さく、より早くマージ可能なパッチを促進する
    • 5コミットすべての準備が整うまで待つ必要はない
    • 前の3つが問題なく、後ろの2つにさらに作業が必要なら、3つだけをマージできる
  • 目標は、人々が長期ブランチではなく main ブランチを基準に作業するようにし、複数のリモートブランチが互いに絡み合ってマージされる状況を減らすことである
  • Linux カーネルのように、公開ブランチを他のリポジトリとマージしたり、別のブランチの上にあるものとして明示的に公開したりするプロジェクトもある
    • Linux 開発者は、パッチシリーズを作って磨き上げる際に git rebase を使える
    • ただし公開ブランチを作成した後は、誰かのツリーにマージされる可能性があるため、force push はせず、新しいコミットを含む新しいブランチを作る

1件のコメント

 
GN⁺ 2024-09-12
Hacker Newsの意見
  • GitHubではだいたいこういう流れを使っているが、欠点は自分のやることが増えることと、共同作業者にとって直感的ではないことだ
    それでも、レビュアーが自分のフィードバックだけが反映された差分を見られて、git blamegit bisectを壊さないという利点はそのままある
    レビューのフィードバックを反映するときはgit commit --fixupでコミットし、pushしたあとレビューコメントへの返信にfixupコミットハッシュを残す
    PRが承認されてマージ直前になったらgit rebase --interactive origin/main --autosquashを実行してfixupコミットを元のコミットにまとめ、最後にgit push --force-with-leaseしてからマージする
    レビューが終わる前のforce pushには注意が必要だ。そうするとレビュアーが前回のレビュー以降に追加された内容を見られなくなる
    ターミナルの自動補完にかなり頼っていて、git reくらいまで打てば長いコマンドまで行けるが、やや無骨なので、この流れを支援して推奨してくれるツールがあるといい。とはいえGitHubに縛られているなら、これでも十分悪くない

    • 自分もそう言おうとしていた。インタラクティブrebaseは、筆者が不満を述べていた「diff soup」の問題をかなり解決してくれる
      ただし、gitの高度な機能をあえて学ぶような、規律あるエンジニアリングチームで実際に使われることが多い
    • ~/.gitconfigに以下の設定を入れればいい
      [rebase] autosquash = true
      そうすると以後はgit rebase -i origin/mainだけでfixup/squashコミットが自動的に並べ替えられる。小さな設定だが、作業フローは大きく良くなった
    • https://news.ycombinator.com/item?id=37086022
    • fixupコミットも良いアプローチだが、個人的には好きではない。Saplingのabsorbコマンドのように、内部のSCCS weave上で関連する差分に変更を自動吸収し、対話的UIで確認させる方式のほうがずっと洗練されていると思う
      複数ブランチが載ったコミットシリーズをrebaseするときに--update-refsが必要になるのと似た領域だ。人間がグラフ関係を追跡してコミットを手で入れ、ブランチを動かさなければならないのはなぜなのかと思う。コンピュータはグラフの扱いが得意なのだから任せればいい
      git absorbもあるが、Saplingの実装ほど堅牢ではない[1]
      本当の問題はインタラクティブrebaseかどうかではなく、たいていはレビュー ツール自体のユーザー体験と、それが生み出す循環構造にある。たとえばfixupコミットでは、GitHubが基準点同士の差分を表示する問題を解決できず、基準点が大きいとレビューを完全に台無しにしうる。たとえば新しいコミット10個の上にrebaseした場合がそうだ
      Git自体のUXにも不満はあるが、原文は主にGitHubへの不満に近い
      [1] 2つの基盤アルゴリズムの違いを示す例は、このGitHub issueにある: https://github.com/martinvonz/jj/issues/170
    • Gitエイリアスは本当に魔法みたいだ
  • このやり方が理想的だという点には100%同意する。GitHubのやり方は本当にひどく、あれを当たり前のものとして受け入れる人が増えすぎたのは悲劇だ
    昔はPhabricatorでこうやっていて、すべてのレビューを一度に更新するコマンドラインマクロのおかげで、ある程度は手動で可能だった。それでも明示的なUIがあればなお良い

    • 筆者の自分だが、冒頭で「コードレビューはだいたいかなり良いアイデアだ」とわざわざ書いた。昔Phabricatorのホームページにあった売り文句の1つだったからだ :) 懐かしい
  • そう、そのとおり。頭の中で本来のコードレビューのスタイルとして思い描いていたのはまさにこれであって、GitHubのやり方ではない。名前が付いていると知れてうれしい
    さらに、レビューシステムが、準備のできたパッチをレビューから「外へ」押し出せるといい。大きな機能を作業している途中で作った小さなバグ修正は、小さく独立したパッチであるべきで、レビュアーとも素早く合意できる可能性が高い
    そうなれば、そのパッチを全体のシリーズから切り出してmainにcherry-pickし、レビューを新しいHEADの上にrebaseしたい。あるいは最新のパッチシリーズをmainの上にrebaseしつつ、合意済みのパッチを先頭に並べ替えてから、mainをそのパッチへfast-forwardしてもよい
    要するに、レビュー対象を「まだ議論中の部分」に絞りつつ、バグ修正は準備できしだいマージされるようにしようということだ
    反論としては「単に別のレビュー/PRとして作ればいい」となるだろうが、そうするとパッチセットAがパッチセットBに依存し、Bがマージされたあとはmainに依存する、といった複雑さが生じる

    • 何度も言っているが、Gerritは基本的にそれをやってくれる :) Gerritでは任意の2つのパッチ間の関係を見られるし、さらに重要なのは各パッチを個別に表示してくれることだ。だからA -> B -> CのシリーズでBが小さくて問題なければ、そのまま入れられる
      ここではAttention Setのような賢いUXのアイデアも一役買っている。基本的には「次の行動を取るべき人は誰か?」を示すもので、ターン制ゲームのように動く。自分が今しがたレビューしたなら、そのパッチのattention setにはもう自分は入っておらず、作者が入っている
      だからGerritのUIでは、その項目は自分のキューの下のほうへ移動する。キューの一番上には、自分がattention setに入っている項目が来る。自然と仕事がそういうふうにまとまる
      GitHub UXのほかの細かな苛立たしい問題までは触れていないが、pull requestの一覧ですら代替手段より劣っている。どの項目がどんな状態なのかわからず、結局は全部読まなければならない
    • Gerritならまさにそれができる。x-b-c-d-eのチェーンをpushすると、UIでは積み上がった形で見えるが、bをmainに簡単にcherry-pickして、CI通過と通常のレビューを確認したうえで、残りをその上にrebaseできる
      一番下のxならそのまま送信して、残りは引き続き進められる
  • コードレビューへの新しいアプローチを見るのは、いつだって興味深い。GitHubにも利点はあるが、完璧にはほど遠い
    提示されたシナリオなら、3つのパッチを相互依存する別々の pull request に分けることを考えられる。GitHub は標準では対応していないが、適切なコードレビュー ツールなら、pull request を小さく保ちながら依存関係を管理できるべきだ。たとえば、パッチ 3 をパッチ 2 に、パッチ 2 をパッチ 1 に依存させられる
    ツールが提供する依存関係追跡のおかげで、必要ならそれらをまとめてデプロイされるよう保証できる
    各パッチを個別にレビューすれば、フィードバックはより明確になり、対応もしやすくなる。pull request の中でコミットを squash して、個々の変更を正確に反映したきれいなコミット履歴も作れる。さらに、適切なツールなら AI で pull request とレビューを要約し、手作業なしで正確なコミットメッセージを書くことも簡略化できる
    良いコードレビュー ツールは、rebase、merge、force push のような git 操作に振り回されるべきではない。裏でどんな複雑な git 操作が起きようと、レビュアーは前回レビュー以降の変更だけを見られるべきだ。そうすれば大きな diff を再レビューせずに新しい内容へ集中でき、レビュー履歴はコミット履歴と切り離されてきれいに保たれる
    このように pull request を分けて相互依存を追跡するやり方で、要件を満たせるのか気になる

    • 「コードレビューへの新しいアプローチ」という表現は前向きで、既存の強者にも礼儀正しい言い方だが、これはまったく新しいアイデアではない
      文字通り git が対応するよう設計されたワークフローであり、GitHub が pull request を備えて以来ずっと提起されてきた古い批判の核心だ
      このアイデアが カレンダーを確認したところ 15年以上ものあいだ「メーリングリストの化石たち」のやり方としてこき下ろされ、今になってようやく流行の開発文化圏に入ってきたのはなぜなのか不思議だ
      多くのソフトウェア開発者が、最もよく使うツールの1つをきちんと学ぶことを長らく拒んできたので、わざわざ悪いワークフローを選んでいるのだと思っていた。だから会社を git に移行するとき、そういうツールとフローを選んで作った。まあ、IBM を買ったからといって解雇されるわけではないし
    • 私の知る限り、シリーズを個別の PR に分ける方式は、リポジトリにコミット権限がある場合にしかうまく機能しない。そうでないと、ある PR を main ではなくメイン リポジトリの別ブランチの上に載せられないからだ
      外部コントリビューターがリポジトリの fork を使う場合、3つの PR はそれぞれ A、A+B、A+B+C を段階的に含むことになる。すると最後の2つの PR では、すでに別の PR でレビューしたコードまで diff として再び見る必要があり、レビューが難しくなる
    • 著者はすでにブランチとそのコミット群を持っている。なら、そのブランチを1コミットずつ入った 3 つの pull request に分ける目的は何だろう?
      各コミットは独立してレビューできる。コミット間の依存関係も追跡できる。AI が組み込まれていないのも良い点だ。PR と違って、コミット間の interdiff も見られる
      コミットは Git の基本素材だ。素直にコミットを使えばいい
    • このスレッドの別の場所でも出ていたが、これは Sapling が採っているアプローチでもある
      GitContext が、fixup、rebase、並べ替えのような操作を経たコミットをどう追跡するのか気になる
    • ただ古き良き merge train 方式ではだめなのだろうか? pull request A がブランチ B を指し、B が master を指すようにして、その後 B を master にマージし、続いて A をもう一度 master に向け直せばよいのではないか。私が要点を見落としているのだろうか?
  • この記事を書いた本人です。何でも聞いてください
    ついでに、ルール違反かどうかは分からないが、最近新しい仕事が必要になった。開発ツールや難しい問題に取り組むのが好きだ。この記事が気に入ったり、開発チームの生産性を高めたかったり、私のすばらしくて時々妥協的な趣味を体験して楽しみたかったりするなら、プロフィールにメールアドレスがある

    • いい笑いをありがとう :)
      真面目な話、履歴書は印象的だ。うまく、そして早く落ち着き先が見つかることを願っている。ごく最近の転職活動の経験からすると、今の採用市場は致命的なまでに病んでいる。よりシニアで経験が多いほど、狂った面接・HR 慣行や説明のない不採用で心がさらに削られる
      友人が下のリンクを送ってくれた
      https://danluu.com/hiring-lemons/
      https://danluu.com/programmer-moneyball/
      https://danluu.com/algorithms-interviews/
      幸運を祈る
    • interdiff レビュー スタイルの思考モデルと、GitHub のコードレビュー アプローチの問題をとてもよく要約している
      まだ触れられていない点が1つある。diff soup のせいで、人々が fixup コミットの「ノイズ」を消すために squash merge 戦略を好むようになるかもしれないということだ。すると最初の良い原子的な 3 コミットまで一緒に捨てられてしまう
      interdiff レビュー スタイルなら、最初の 3 コミットは残り、それぞれを個別に取り込むか squash するかは、そのコミット自体と実際の原子性に完全に基づいて決められる
    • GitHub の無料部分を使った経験では、diff soup という表現は非常によく当てはまる。有料版はもっと良いのだろうか? GitLab は Gerrit に近づけるのだろうか?
      GitHub の苦痛を和らげようとする外部サービスもあり、stacked diff のサポートを提供しているが、かなり高価に見える。特に self-hosted Gerrit と比べるとそうだ。こうしたツールも検討したのか気になる
    • Merge Request Dependencies と Squash+Merge マージ戦略を設定した GitLab についてどう思うか気になる
      以前、MR シリーズのパターンをかなり簡単に組めた記憶がある。3 つの MR をマージすると、各 MR ごとに単一の squash コミットを持つ 3 つの merge commit ができた。MR のコミット履歴とは無関係だった
      トレードオフは、レビュー中に前方のシリーズ ブランチが変わると、後方のシリーズ ブランチに再度 merge しなければならない点だ
      それでもレビュー中は、コミット履歴を人々が好きなように扱える。どうせ squash されるのだから問題ない
      ただ、やっていたのはかなり前で、最近は GitHub に縛られているので、美化された記憶になっているのかもしれない
  • Review Board [https://www.reviewboard.org] では、2006年の時点ですでに interdiff が作られていた。実際、その用語は自分が作ったか、独自にたどり着いたものかもしれない
    今でも製品とコードレビューのプロセスでいちばん気に入っている部分であり、人々が GitHub のようなものへ移るときに最も恋しがる機能の一つだとよく聞く
    fix-it コミットは、まともな代替手段だと感じたことがない
    第一に、上位の変更がコミット列にどう反映されたのかを示してくれない
    第二に、一時的であってもコミットグラフを乱し、レビューを難しくする。レビューを追い続けていた人は fix-it コミットが修正するコードをすでに読んでいるかもしれないが、新しく入ってきた人は、そのコードが何をしようとしているのかや構造がどうなっているのかについて、悪い第一印象から始めることになりかねない
    第三に、誰もが Git や複数コミットを扱える構成管理システムを使っているわけではない。ゲーム開発では Perforce を、チップメーカーでは Keysight SOS のような特殊な構成管理システムを使うことも多い。そうした環境では fix-it コミット自体が選択肢にならない
    きちんとした interdiff 対応のコードレビューシステムであれば、あるレビュアーは最初に公開されたレビューリクエストから全更新を追って変わった部分だけを見られ、別のレビュアーは最新の全体変更にそのまま入り、fix-it の連なりを気にしなくてよい。そしてこれは構成管理システムに依存せず実現できる
    きちんと作れば、複数コミットから成る変更とも共存できる
    たとえば、小さなプロジェクトをレビューしやすくするために API ハンドラー、フロントエンド UI、ドキュメントの複数コミットに分け、それらのコミットが密接に関連しているので一つのレビューリクエストとして出すのが適切だと判断することがある。相互の関連が薄いなら、依存チェーンとして複数のレビューリクエストにするほうが理想的だろう
    レビューフィードバックに応じて、それらのコミットの一つまたは全部に対して一連の変更を加えることもできる。人々が更新をレビューするとき、fix-it コミットとその変更を対応する元の変更へ頭の中でマッピングするのではなく、各部分がどう進化したかを見られるほうがよい
    だから interdiff は本当に素晴らしい。小さなコミットが多い場合でも大きなコミットでも、単一コミットのレビューリクエストでも複数コミットでも、もっと多くの人が使うべきだ

    • 本当に最高だ。実はこの記事の第2部では、こうしたツールに至るまでの歴史的・政治的文脈も扱う予定だ
      2013年ごろ、Glasgow Haskell Compiler は、冗談のように言われた「バグレポーターで .patch ファイルを読む」方式から Phabricator の利用へ移行した。理由はいくつかあったが、当時は stacked diff が理由ではなかった。GitHub はレビュー機能があまりに貧弱で、side-by-side diff すらなかったからだ。その理由だけでも完全に対象外で、ほかにも理由があった
      しかし、コードレビュー用ツールへチームを移したのはそれが初めてではなかった。2009年の最初の職場は Houston の一室に集まったとても小さく結束の強いエンジニアチームで、他の人に自分のコードをレビューしてもらい、彼らが書いたものを読むことでコードベースをより深く理解できるはずだと思っていた
      そこで入社後の最初の数か月、マネージャーに頼み込んで ReviewBoard を導入してもらい、みんな本当に気に入っていた
      つまり RB には感謝しているということだ。今でも時々よい思い出として浮かぶ。そのおかげでコードレビューはほとんど初日から自分のキャリアの非常に大きな部分になり、今でももっとできると思っている
  • 全体として、コードレビュー優先で rebase 中心の Gerrit のようなシステムのほうが、コードをずっとレビューしやすいと感じていた
    最もよい点の一つは、複数パッチを積み上げる機能を標準でサポートしているため、人々がより小さくレビューしやすいパッチを作るようになることだ
    GitHub のコードレビューは、質の悪い後付け機能のように感じられる。フォーラムスレッドのように見える無駄の多い UI や、rebase をまたいで追跡できない点などがそうだ

    • Gerrit でコミットスタックを push するとき、惜しい点が一つある。個々のコミットではなく、スタック全体 について話すための中央の場所がない
      こうした「大きな絵」でありながら技術的でもある議論は、あまりにも頻繁にイシュートラッカーで行われてしまう。だが、どこに置くべきなのかもわからない。このスタックはあまりに一時的で、次の push で完全に変わってしまうかもしれない
  • こうした戦略を主張するのは何度か聞いたことがあるが、納得はしていない。自分が関わるほとんどのプロジェクトでは、feature branch は単一コミットに squash してマージし、ブランチ履歴は消している
    筆者が説明したケースなら、リファクタリング、新しい API、更新をそのまま 3 つのコミットにするだろう
    自分にとって確実に良い実践だったのは、長生きするブランチを避けることだ。こうした多段階コミットのシナリオは、たいていそこから生まれる。誰かが機能を数日、ひどいと数週間作業してから、一気に投げ込みたがるような状況のことだ
    自分は毎日、あるいは1日に何度も main に移すほうをずっと好む。そのための方法の一つは機能フラグを使って、作業途中のコミットでも問題なく取り込めるようにすることだ。システムがきちんと構成されていれば、開発・ステージング環境で有効にしてテストできる利点もある。blue/green デプロイにも一歩近づく
    大きなコミットをもっと簡単にレビューする方法は望んでいない。チームに、小さな変更を早く、頻繁にコミットするよう強制したい。全員が同意しないことは理解している

    • stacked diff を好む人たちは、サイズに関係なく変更をより早く統合しやすくなると言う
      その理由の一つは、GitHub の PR と違って、スタックの一部だけを取り込めるからだ。記事の例でいえば、「小さなリファクタリング」diff の準備ができていれば、「新しい API」と「API 利用者のマイグレーション」diff を一緒に取り込まなくても先に入れられる
      ブランチではなく コミット中心 にすると、長生きするブランチよりも各コミット全体が小さくなる効果がある
    • feature branch を単一コミットに squash してブランチ履歴を消すのはひどい
      そうすると git blamegit bisect が事実上役に立たなくなる
      リグレッションがあれば、git bisect は単一のパッチまで絞り込める。だから特定機能については、8000 行のパッチ 1 つよりも、160 行のパッチ 50 個が git の履歴にあるほうがよい
      あるコード行が怪しく見えたら、git blame や連続した git blame コマンドで、8000 行のコミットではなく、詳しいコミットメッセージの付いた 160 行のコミットにたどり着いてほしい
      元のコミット順も保持されるべきだ。数年後に個々のコミットメッセージを順番に読むだけでも、元の設計を理解する助けになることがある。もちろん元のパッチセットは依存関係の順に構成され、各段階でコンパイルできるなど、機能実装とは別の開発段階が必要になる。コードは論理的な段階で提示されるべきだ
  • 興味深い。職場では、筆者がコミットを書くやり方で PR を作り、最後には実際に squash-and-merge している
    ただ、このやり方だと前の PR を変えるたびに後ろの PR を rebase しなければならない。かなり面倒だし、「force-push 禁止」のルールにも引っかかるし、エンジニアが習得するのにも時間がかかり、GitHub UI 上の既存のコードレビューコメントを壊しがちだ。それでも 2、3 個の PR くらいなら何とか機能する
    自分たちのフローでは、コミットは作業単位というより保存ポイントに近い
    stash もよく使うし、Emacs の undo-tree-mode もよく使う。するとソースコード履歴を追う方法が 4 つになるが、重複しているようでいて実際にはうまく回っている
    Git でこれを扱う 使い勝手 はかなり悪い。Phabricator のほうがまだ良かったが、それでも不必要に難しかった。もしかすると新しい構成管理ツールなら、コミットやブランチより高いレベルの概念を第一級でサポートできるのかもしれないし、そうすると逆にもっと使いにくくなるのかもしれない

    • コミットを PR のように使っている。だから PR 依存のせいで物事が複雑になる
      Git より良いツールがあればいいか? もちろん、自分も欠点が少なくてもっとユーザーフレンドリーなツールが欲しい。だが当面の対処として、コミットをコミットとして扱ってみてはどうだろう。わざわざ自分で難しくしなくてもいい
      GitHub が人々に PR 色の眼鏡をかけさせた責任がどれほど大きいのか気になる
    • jj, sapling, mercurial を見てみるとよい
  • ブログ記事は良かったし、コードレビューがどうあるべきかを実際に考えている人たちがいるのを見られてうれしい
    それぞれ長所と短所のある 4 つのコードレビューシステムを多く使ってきた: Critique(Google 社内)、Gerrit(Google でも使ったが外部版と同じ)、GitHub、そして自分が作った CodeApprove だ
    Critique は圧倒的に最高だったが、それが可能だったのは Google の monorepo と独自の構成管理システム、カスタム lint/test ツールに完全に最適化されていたからだ。CodeApprove はその長所をできるだけ GitHub に持ち込むよう設計したが、実際にそこまで近づくのは難しい
    Gerrit はレビュアー体験の面では 2 番目に良かったが、作者の立場ではずっと嫌いだった。正しいやり方より間違えるやり方のほうが多いように見えたし、UI も特別美しくはない
    GitHub は作者には非常に親しみやすく、自分たちが考える通りに動く。コードを書き、フィードバックを受け、さらにコードを書くという流れだ。PR の最後で squash and merge すれば、筆者が言う履歴の問題はない
    しかしレビュアーやチームにはあまり親切ではない。増分 diff が強調されず、diff と会話が別タブにあり、force push と rebase が履歴を壊す。コメントは "outdated" として消え、diff 画面の外にあるファイルにはコメントできず、大きなファイルはデフォルトで隠されるなど、問題が多い。GitHub がこれをあまり気にしていないのは明らかで、もしかすると自分の知らない何かを知っているのかもしれない
    結局いちばんもどかしいのは、多くのチームが構成管理プラットフォーム内蔵のコードレビューツールをそのまま受け入れていることだ。ノートPCに標準搭載された IDE をそのまま使うようなものだ。今はもっと良い選択肢がたくさんある。CodeApprove のほかに自分が気に入っているのは GitContext、Reviewable、Graphite で、そのほかにも優れた選択肢を 6 つは挙げられる。デフォルトを受け入れるべきではない

    • GitHub がレビュアーやチームに優しくないことが問題だ
      レビュアーやメンテナーは、コントリビューターよりずっと希少だ。ワークフローと UI は レビュー処理量 を最適化すべきだと思う
      挙げられていた他の 3 つのツールは使ったことがないので、自分の主張は一般論だ