TT Lab
ブログ

한국어 English 日本語 中文

はじめる
ブログ

ブログ

オープンされた45件のPRを一度に点検した:マージ状態5種類とコンフリクト3件、クローンなしのリベース

番外:マージされたPRではなく、オープンされたPRを手入れする手順です。この記事に登場するPRはすべて2026-11-13基準の「進行中」です。 実際はGitHubのPR・チェック履歴とドキュメント、各プロジェクトのコントリビューション規約の原文、コントリビューション台帳の照会生データと実測記録から取得しました。時刻は韓国時間です。

目次

一言まとめ

対象 アップストリームプロジェクトでオープンされている45件のPR。10月中旬から下旬にかけて作成したもので、すべてドラフトではありません。自身のレポジトリおよび所属するコミュニティのレポジトリの古いPR 7件は別枠でカウントします
照会 gh pr view --json mergeable,mergeStateStatus,reviewDecision PRごとに1回
分布 BLOCKED 24 · UNSTABLE 9 · CLEAN 7 · BEHIND 3 · DIRTY 2。最初の照会ではDIRTY 3、UNKNOWN 4
処理 コンフリクト3件のうち1件は新しいベースの上にリベースして解消。2件は書き直す必要があるため進行中
열린 PR 45건의 병합 상태를 한 번에 조회했다 2026-11-13 재조회 · gh pr view --json mergeStateStatus ① 상태별 건수: 충돌은 DIRTY 뿐이다 BLOCKED 24 리뷰 대기 UNSTABLE 9 검사 미통과 CLEAN 7 병합 가능 BEHIND 3 뒤처짐 DIRTY 2 충돌 ② 충돌 원인 셋과 처리(첫 조회의 DIRTY 는 3건) 이웃 줄이 고쳐짐 dynamo#16465 · 문서 2개 새 main 위로 재기준 +15/−4 그대로 · 해소 문서를 통째로 다시 씀 dcgm-exporter#760 새 문서에 맞춰 다시 쓰기 새 판 4.9.0 미실측 · 진행 중 주 버전 개편(v3) catwalk#676 새 형식으로 다시 쓰기 새 Go 도구로 빌드 · 진행 중 BEHIND 3건은 충돌이 아니다: 기준 브랜치만 앞서 있다 첫 조회의 UNKNOWN 4건은 다시 조회해야 값이 나온다
図:オープンされた45件のPRのマージ状態分布とコンフリクト3件の原因・処理

1. なぜ点検するのか:オープンされたPRはそのまま放置しても古くなる

PRを提出した日にはコンフリクトもなくテストも通過します。しかし、レビューを待つ数週間の間、ベースブランチは動き続けます。他の人が同じファイルを修正し、ドキュメント構造が変わり、テストを実行するランナーの環境が変わります。私たちのPRは一文字も変わっていないのに、ある日「コンフリクト」の表示が付いたり、通過していたテストが失敗に変わったりします。

メンテナーの視点から見ると、コンフリクトしたPRはレビューできないPRです。レビューの順番が回ってきたときにコンフリクトが発生していると、その順番をそのまま見送ることになります。そのため、オープンされたPRが数十件に増えてからは、通知が来たときだけでなく、全体を一度に照会して状態ごとに分けて確認することにしました。

この記事は2026-11-13の早朝に行ったその点検の記録です。1〜6話とは異なり、マージされたPR 1件を追うのではなく、オープンされた複数のPRを手入れする手順を扱います。結果が出ていないPRであるため、どれも「受け入れられた」とは記載していません。

2. 照会:状態値5種類とUNKNOWN

まずオープンされたPRのリストを作成し(gh search prs --author <계정> --state open)、PRごとに次のコマンドを1回ずつ実行しました。

gh pr view <번호> --repo <소유자>/<저장소> --json mergeable,mergeStateStatus,reviewDecision

mergeable はコンフリクトの有無だけを教えてくれますが(MERGEABLE·CONFLICTING·UNKNOWN), mergeStateStatus )は「今マージボタンを押すことができるか」をより細かく分類します。GitHubのGraphQLドキュメントが示す意味と、今回該当した件数は次のとおりです。

値 ドキュメントの意味(要旨) 件数 私たちが読み取った方法
BLOCKED マージがブロックされている 24 大部分がレビュー待ち。レビュー判定は「要レビュー」17、判定なし5、承認1、変更要求1
UNSTABLE マージは可能だが通過状態になっていないテストがある 9 テスト履歴を開いて原因が私たちの変更によるものかから確認
CLEAN マージ可能かつテストも通過 7 私たちがやるべきことはない。承認まで得ているものはそのうち1件
BEHIND PRブランチがベースより遅れている 3 コンフリクトではない。ベースブランチが先行しているだけ
DIRTY マージコミットをクリーンに作成できない 2 コンフリクト。原因をPR単位まで追跡

ここで2つのことを学びました。

最初の照会の UNKNOWN は結果ではありません。 最初の照会で4件が UNKNOWN になりました。GitHubのRESTドキュメントでは、この値が空である場合、マージ可能かどうかを計算するバックグラウンドタスクが始まったばかりであるため、時間を置いて再リクエストするよう案内しています。実際に4分ほど経ってから同じコマンドで再照会したところ、3件は BLOCKED、1件は UNSTABLE になりました。長い間照会されていなかったPRほど最初の照会でこの値が出力されるため、一括点検スクリプトは UNKNOWN だけを集めてもう一度照会させる必要があります。

CLEAN は「間もなくマージされる」という意味ではありません。 の7件は技術的な障害がないということを意味しているにすぎず、マージはメンテナーが決定します。逆に BLOCKED の24件も大部分は修正すべき点があるからではなく、レビューの順番を待っている状態でした。45件の中で私たちが手を加えなければならないのは、 DIRTY と、 UNSTABLE のうち原因がこちら側にあるものだけです。 UNSTABLE の9件の理由は一件ごとに異なるため、この記事では分けていません。

テスト失敗の原因が私たちの変更ではない場合もありました。前日の11-12に見かけた containers/kubernetes-mcp-server#1518 は、レビュアー1名の承認を得た状態でブラウザテストが失敗に変わっていました。同じテストが古いベースでのみ失敗しており、テストランナーのイメージが変更されたことが原因のようでした。変更内容はそのままにして新しいベースの上にリベースしました。その後、2回目の承認が付き、今回の照会では CLEAN でした。このPRも進行中です。

3. コンフリクト3件の原因はそれぞれ異なっていた

最初の照会の DIRTY は3件でした。コンフリクトが発生したという事実だけでは何をすべきか分からないため、3件すべてにおいてどのPRがマージされたことでコンフリクトが生じたのかまで突き止めました。原因が異なっていたため、対応も異なりました。

私たちのPR コンフリクトを引き起こしたマージ そのマージの規模 原因 処理
ai-dynamo/dynamo#16465 ドキュメント4個、+15/−4 #17229, 11-06 04:34 29ファイル、+97/−3068 私たちが修正した行の隣の行が修正された 新しいベースの上にリベース。解消
NVIDIA/dcgm-exporter#760 ドキュメント1個、+16/−7 #768, 11-07 03:45 961ファイル、+161632/−27808 修正した段落が含まれていたドキュメントが丸ごと書き直された 新しいドキュメントに合わせて書き直す必要がある。進行中
charmbracelet/catwalk#676 ファイル3個、+63/−0 #611, 10-29 23:22 73ファイル、+39578/−18179 メジャーバージョンの刷新によりモジュールパスと設定フォーマットが変更された 新しいフォーマットで書き直す必要がある。進行中

隣接する行が修正された場合。 dynamoのPRは、非推奨となった機能のドキュメント4箇所に不足していた非推奨表記を追加する変更です。その間にアップストリームが関連する統合コードを削除するPRをマージし、同じドキュメント2つのすぐ隣の行を修正しました。リベースする前にまず確認したのは「私たちの変更がまだ必要か」でした。新しいベースブランチの4つのファイルを開いて確認したところ、非推奨表記は依然として抜けていました。そのため、新しいベースのファイルに同じ変更を再度適用し、変更量は+15/−4のままでした。再照会したところ、コンフリクトが解消されてレビュー待ち(BLOCKED)に戻りました。

ドキュメントが丸ごと書き直された場合。 dcgm-exporterのPRは、デバッグダンプを出力する手順の段落を修正したものです。しかし、新しいバージョン(4.9.0)をリリースするPRの1つが961ファイルを変更し、そのドキュメントを丸ごと書き直していました。このPRは作成されてから30分でマージされたため、事前に知る方法もありませんでした。新しいドキュメントでは私たちが修正した段落が消えており、ダンプを配置する場所も変わっていました。リベースしただけで解決するコンフリクトではありません。新しいドキュメントに残っているコピーコマンドの1行が新しいイメージでも失敗するかをまず測定しなければなりませんが、新しいバージョンはまだ測定できていません(未実測)。測定した上で1行のPRとして書き直すか、問題が消えていればクローズするのが適切です。

メジャーバージョンが刷新された場合。 catwalkのPRは、プロバイダー設定を追加する変更です。その間にv3がマージされ、モジュールパスと設定ファイルのフォーマットが変更されました。以前のフォーマットのファイルをそのままリベースすることはできず、新しいフォーマットで書き直して新しいバージョンのツールでビルドしてみる必要があります。これも進行中です。

BEHIND はコンフリクトではありません。 3件はベースブランチが先行しているだけであり、マージコミットはクリーンに作成されます。今回は手をつくしませんでした。コンフリクトがないため、レビューが始まる前に急いでリベースする理由はないと判断しました。レビューが始まった後の強制プッシュを嫌うプロジェクトもあるため、不要なリベースは控える方が無難です。

3件を振り返ってみると、コンフリクトは「私たちの変更と他人の変更が重なった程度」ではなく、「私たちの変更が依拠していた基盤がどれほど変わったか」によって分かれました。隣接する行程度であればリベースすれば済みますが、段落やフォーマットが消えてしまった場合は変更自体を再検討する必要があります。

4. クローンなしのリベース:Git Data APIとSSH署名

数十個のリポジトリをすべてダウンロードした上でリベースするのは負担になります。ドキュメント数行を修正するPRのために数GBのレポジトリを取得するのも無駄です。そのため、リベースはレポジトリをダウンロードせず、GitHubのGit Data APIで行います。ローカルではコミットを作成もせず、ブランチも切り替えません。手順は次のとおりです。

  1. フォークのデフォルトブランチをアップストリームに合わせます。新しいベースコミットがフォークに存在してこそ、その上にコミットを作成できます。
  2. 新しいベースから変更するファイルのみを取得し、同じ変更を再度適用して、実行可能なテストを実行します。
  3. ファイルごとにblobを作成し(POST git/blobs)、新しいベースのツリーを base_tree に指定してツリーを作成します(POST git/trees).
  4. )。コミットオブジェクトの本文を直接組み立ててSSHキーで署名します。
  5. 署名を付与してコミットを作成し(POST git/commits)、レスポンスの verification.verified が真であるかを確認します。
  6. 真である場合にのみ、PRブランチのrefを新しいコミットに移動します。移動の対象は自身のフォークのブランチのみです。

4番で署名する対象は、gitがコミットを保存するときに使用する文字列そのものです。

tree <새 트리 SHA>
parent <새 기준 커밋 SHA>
author <이름> <메일> <epoch 초> +0900
committer <이름> <메일> <epoch 초> +0900

<커밋 메시지>
ssh-keygen -Y sign -n git -f <개인 키 파일> <위 내용을 담은 파일>

ここで直面した課題を記録しておきます。

最も高い代償を払って学んだのはファイルモードです。最初に作成したツールは、アップロードするファイルのモードを 100644 に固定していました。10-31 に containers/podman-compose#1585 をリベースしたところ、実行ファイルだったスクリプトが通常のファイルに変更され、統合テスト 30 件が PermissionError で失敗しました。内容は 1 文字も違わなかったため、diff の本文だけを見ていても気づけない変更でした。翌日、ツールが基準ツリーのモードに従うように修正し、同じ内容でコミットを再作成しました。それ以降は、署名ツールを使用した後に必ず以下を確認するようにしています。この PR も進行中です。

gh pr diff <번호> --repo <소유자>/<저장소> | grep -n 'mode'

何も出力されないのが正常です。 old mode 100755 と new mode 100644 が表示された場合は、意図しない変更です。

5. 投稿しなかったもの:プロジェクトごとに異なる要件

確認ついでに、登録だけしてあったissueの中で PR につなげられるものがあるかも確認しました。結論は「今投稿するものはない」でした。パッチを作れなかったからではなく、プロジェクトのルールで順序が定められていたためです。

投稿したものも 1 件あります。KubeVirt の virt-operator がいかなる証明書も破棄していないにもかかわらず、「古い CA を破棄する」というログを繰り返し出力する問題を修正した kubevirt/kubevirt#19889 です。KubeVirt の AI コントリビューションポリシーでは、AI が生成したコードのすべての行を投稿前に確認して理解することを求め、ツールの使用を明記することを推奨しています。そのため、コミットに Assisted-by トレーラーを追加し、 ドラフト PR として投稿しました。人間が diff を最後まで読んだ後にレビュー待ちの状態に変更します。この PR も進行中であり、マージされ次第、別の記事として書きます。

6. Mac で実行できないテストを測定する方法

上記の KubeVirt の変更の単体テストは、Mac では実行できませんでした。テストが依存するパッケージが Linux 専用パッケージに依存しているためです。「テストは CI が実行してくれるだろう」と投稿する代わりに、次の方法で直接測定しました。

  1. Mac で Linux 用のテストバイナリのみをクロスコンパイルします。リポジトリの vendor ディレクトリのみを使用するため、新しくダウンロードするものはありません。
  2. そのバイナリを TT Lab クラスターの一時 Pod に入れて実行するだけです。Pod はノードにすでにプルされているイメージを使用し、すべてのケイパビリティを破棄し、root 以外のユーザーとして、サービスアカウントトークンなしで、メモリ上限 1Gi で起動します。終了すると削除されます。
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GOTOOLCHAIN=local GOPROXY=off \
  GOFLAGS="-mod=vendor -buildvcs=false" go test -c -o <시험 바이너리> <패키지 경로>
対象 結果
新規作成したテスト 2 件、修正前のコード 0 成功、2 失敗
新規作成したテスト 2 件、修正後のコード 2 成功
CA バンドル関連のテスト 27 件中 27 件成功
パッケージ全体(順序をシャッフルして 3 回) 160 件中 160 件成功、約 0.53 秒
隣接する apply パッケージ全体 219 件中 219 件成功

環境は Linux カーネル 7.0、x86_64、Go 1.26.6 です。修正前の症状も測定しました。KubeVirt v1.9.0 がインストールされた TT Lab クラスターでリーダー operator のログを 24 分間カウントしたところ、同一の行が 711 行ありました。調整 237 回ごとに CA バンドルセットにつき 1 行ずつ出力される回数と一致します。

ここにも罠が 1 つありました。最初に作成したテストは 修正前のコードでも成功しました。テスト環境のデフォルトロガーが情報レベルのログをフィルターして除外したため、「ログが出力されてはならない」というテストが、ログがフィルターされたおかげで成功したのです。テスト内でログの詳細レベルを引き上げ、終了時に元に戻すように修正して初めて、修正前のコードで 2 件とも失敗しました。新しいテストは修正前のコードで失敗することをまず確認しなければならないという原則を飛ばしていたら、何も検証できないテストを投稿してしまうところでした。

7. 学んだこと:オープンな PR を管理するコツ

ティティの一言。 図書館に「この本を買ってください」というメモをたくさん挟んでおいたのですが、しばらくしてから行ってみると、あるメモは棚番号が変わっていて書き直さなければならず、別のメモは司書の先生のハンコを先にもらってこなければならないとのことでした。そのため、今ではメモを挟んだら忘れずに、たまにまとめて取り出して、まだ正しいメモかどうかを読み返しています。

リンク

すべての資料は 2026-11-13 に閲覧しました。

ログインするといいねできます

コメント

まだコメントはありません。

ログインするとコメントできます