2.6 バージョン管理とソース管理
概要と動機
バージョン管理は、コードベースの記録のシステムだと考えてください。誰が、いつ、なぜ変更したかを含め、すべての変更を捉え、多くの人が互いを上書きせずに同じソフトウェアで作業できるようにします。大きな組織にとって、それは単なるバックアップよりはるかに大きなものです。協働、継続的インテグレーション(CI)、監査、リリース管理のすべてが拠って立つ基盤です。ブランチ、リポジトリの構造、コミットの規律についての選択が、チームがどれだけ速く、どれだけ安全に動けるかを形づくります。
大きなチームにとって、ソースの管理は、実のところ規模における調整の問題です。何百人ものエンジニアが共有のコードに変更をプッシュするとき、マージを小さく保ち、メインラインをリリース可能に保ち、履歴を読める状態に保つ戦略が必要です。継続的に統合するチームはなめらかに流れます。ブランチを何週間も乖離させるチームは、一つの統合の危機から次へとよろめきます。リポジトリの構造、一つの大きなリポジトリか多数かも、チームがコードを共有し調整する仕方を形づくります。
企業や政府の設定は、トレーサビリティ、アクセス制御、保持という要求をさらに加えます。変更が、監査のために承認された作業項目にリンクされる必要があるかもしれません。シークレットが履歴に入ってはなりません。リポジトリへのアクセスは、セキュリティの境界を尊重しなければなりません。ここでは、バージョン管理の実践は組織の統制の枠組みの一部となり、シークレットの漏洩や監査できない履歴といった間違いは、深刻な結果を招きえます。
主要原則
- 小さな変更を頻繁に統合します。長い乖離はマージの苦痛の根源です。
- メインラインを常にリリース可能に保ちます。
- 履歴はドキュメントです。理由を理解しなければならない将来の読み手のためにコミットを書きます。
- シークレットは決してコミットしません。履歴に届いたシークレットはすべて漏洩したものとして扱います。
- 規律だけに頼らず、衛生の徹底(フック、CIチェック)を自動化します。
- リポジトリの構造(モノ対ポリ)は、流行ではなく、チームが実際にコードをどう共有し調整するかで選びます。
- トレーサビリティのため、変更をその根拠(作業項目、チケット、決定)にリンクします。
推奨事項
短命なブランチによるトランクベース開発を好む
トランクベース開発に傾いてください。共有のメインラインへ頻繁に、数週間ではなく数時間か数日で測られる短命な機能ブランチを使って統合します。短いブランチはマージを小さく、統合を継続的に保ち、その習慣は高いデリバリー性能と強く関連しています。作業がまだ終わっていないときは、長寿命のブランチに駐車しないでください。代わりに、フィーチャーフラグ、つまり未完成の作業を隠すランタイムのスイッチを使って、安全にマージします。長寿命のリリースブランチは、本物の複数バージョンのサポートのために取っておき、それが抱える保守コストを承知で臨みます。
リリースの頻度に合うブランチモデルを選ぶ
ブランチモデルを、実際のリリースの仕方に合わせます。継続的にデプロイするなら、最小限のブランチによるトランクベース開発がよく役立ちます。顧客にバージョン付きのリリースを出荷したり、複数のライブのバージョンを同時にサポートしたりするなら、リリースブランチとバックポートが必要かもしれません。リリースのモデルが本当に要求するのでなければ、多くの長寿命ブランチを伴う重いモデルは避けてください。マージと保守のオーバーヘッドが増えるからです。
モノレポとポリレポを意図して決める
チームがコードを大いに共有し、プロジェクトをまたぐ原子的な変更を必要とし、統一されたツールと可視性を望むときは、多くのプロジェクトを保持する単一のリポジトリであるモノレポに手を伸ばします。その代わり、スケールしたビルドツールとアクセス制御の必要性を受け入れます。チームとサービスが本当に独立していて、隔離されたアクセスとリリースサイクルを望み、リポジトリをまたぐ原子的な変更を必要としないときは、プロジェクトやサービスごとの別々のリポジトリであるポリレポに手を伸ばします。その代わり、リポジトリをまたぐ変更を調整するコストを受け入れます。どちらも規模で機能します。絶え間ない摩擦を生むのは、結合のパターンに対して誤った選択をすることです。
コミットの衛生とコンベンショナルコミットを徹底する
変更が何かだけでなく、なぜ行われたかを説明するコミットメッセージを求めます。コンベンショナルコミットのような規約を採用して、メッセージを構造化し機械で解析可能にし、変更履歴とバージョニングを自動化できるようにします。コミットを原子的に、一つの論理的な変更ごとに保ち、履歴が二分探索可能で、元に戻しやすいようにします。記憶に頼るのではなく、フックとCIチェックにメッセージ形式と基本的な衛生を徹底させます。
大きなバイナリと生成されたコードを通常の履歴から外す
大きなバイナリ資産をメインの履歴に直接コミットしてはいけません。すべてのクローンを永遠に肥大させるからです。代わりに、大容量ファイルのストレージの仕組みや成果物リポジトリを使います。原則として、生成されたコードのコミットも避け、ビルドで生成します。生成された成果物をどうしてもコミットしなければならないときは、隔離して明確に印を付け、レビューや差分を汚さないようにします。
シークレットがリポジトリに入るのを決して許さない
自動のシークレットスキャンをコミット前フックとCIに置き、認証情報が着地する前にブロックされるようにします。エンジニアに適切なシークレット管理システムを与え、そもそも認証情報をハードコードする必要がないようにします。そして、履歴に届いたシークレットは漏洩したものとして扱い、すぐにローテーションします。シークレットがプッシュされてクローンされてしまうと、履歴から取り除くのは困難で信頼できません。
アクセス制御とトレーサビリティを確立する
リポジトリへのアクセスを、セキュリティの境界と最小権限を尊重するように設定します。コミットやプルリクエストを作業項目にリンクし、すべての変更がその根拠までたどれるようにします。これは日々のエンジニアリングの文脈と監査の両方に役立ちます。主要なブランチを必須のチェックとレビューで保護し、合意したゲートを通らなければ何もマージされないようにします。
トレードオフ: 長所と短所
| 選択 | 長所 | 短所 |
|---|---|---|
| トランクベース開発 | 継続的インテグレーション。小さなマージ。高い流れ | フィーチャーフラグと規律が必要。隔離が少ない |
| 長寿命の機能ブランチ | 作業中のものの強い隔離 | 苦痛なマージ。遅れる統合。乖離 |
| モノレポ | プロジェクトをまたぐ原子的な変更。共有ツール。可視性 | スケールしたビルドツールが必要。既定ではアクセス制御が粗い |
| ポリレポ | 独立したリリース。隔離されたアクセス。リポジトリごとの単純なツール | リポジトリをまたぐ変更が困難。バージョン調整のオーバーヘッド |
| コンベンショナルコミット | 自動の変更履歴とバージョニング。一貫した履歴 | 前もっての規約。徹底が必要 |
ここでの大きなトレードオフは、統合の頻度と隔離です。長寿命のブランチは、作業が単独で離れているので、より安全に感じられますが、まさにその隔離が、後で高価なマージと統合の驚きを引き起こします。トランクベース開発は、その隔離の感覚を、継続的で安い統合と引き換えに手放し、フィーチャーフラグと規律を持ち込むよう求めます。モノレポとポリレポの決定は、プロジェクトをまたぐ容易さとチームの独立を取引します。コードが実際にどれだけ密に結合しているかに合うほうを選んでください。
チームで議論すべき問い
保護されたメインラインにマージされる前に、どのチェックが通らなければならず、そのメインラインは本当に常にリリース可能ですか。 本章はリリース可能なメインラインを中核の原則として扱い、壊れたコードやレビューされていないコードが全員の依存するブランチに届く、保護されていないメインラインをアンチパターンと呼びます。大きなチームでは、赤いメインラインは全員を一度にブロックするので、必須とするゲートは、個人のものではなく共有の安全特性です。証拠を持ち込んでください。ブランチ保護が今日実際に何を徹底しているか、メインラインが現在どれだけ頻繁に壊れているか。必須の集合、通るテスト、セキュリティスキャン、レビューを決め、メインラインを、願望ではなく方針によってリリース可能にします。そのゲートこそが、多くの人が恐れずに継続的に統合できるようにするものです。
コンベンショナルコミットの採用は、それが自動化するものを考えて、チームにとって規約のオーバーヘッドに見合いますか。 本章は、構造化され機械で解析可能なコミットメッセージを、変更履歴とバージョニングを自動化できるからこそ推奨し、履歴が二分探索可能で元に戻せるよう、原子的なコミットを求めています。トレードオフは本物です。前もっての規約を払い、徹底が必要な代わりに、生成されるリリースノートと信頼できる履歴を得ます。今日手作業でしていることのシグナルを持ち込んでください。変更履歴を手書きしていたり、どのコミットが回帰を持ち込んだかを探し回っていたりすること。頻繁にリリースしたり複数のバージョンを保守したりするなら、自動化は通常元が取れ、めったにリリースを切らないなら、より軽い規約で十分かもしれません。フォーマットを記憶に頼らず、フックとCIに徹底させてください。
モノレポのツールであれ、リポジトリをまたぐ調整であれ、リポジトリの構造が要求する運用コストを受け入れましたか。 本章は、モノレポもポリレポも規模で機能し、絶え間ない摩擦を生むのは結合のパターンに誤った選択をすることだと述べています。モノレポにはスケールしたビルドツールとより細かいアクセス制御が必要で、ポリレポでは、リポジトリをまたぐ変更が、バージョンのずれのリスクを伴う調整のプロジェクトになります。具体的なシグナルを持ち込んでください。変更がプロジェクトの境界をどれだけ頻繁にまたぐか、そしてビルドとアクセスのツールが今ある構造を支えられるか。プロジェクトをまたぐ原子的な変更が一般的なら、モノレポのツールに投資し、チームとサービスが本当に独立しているなら、リポジトリをまたぐ調整のコストを意図して受け入れます。要点は、構造をコードが実際にどれだけ密に結合しているかに合わせ、その構造が必要とするツールに資金を出すことです。
生きた認証情報が今、忙しいリポジトリにコミットされたら、どれだけ速く検出でき、ローテーションは願望ではなく実際に自動ですか。 本章は履歴に届いたシークレットを漏洩したものとして扱い、後から取り除くのは困難で信頼できないと警告しており、予防と速いローテーションだけが本当の防御です。大きなチームでは、露出が積み重なります。共有のリポジトリにプッシュされたシークレットは、数分のうちに数十台のマシンにクローンされ、CIのキャッシュにミラーされるので、遅い人間の対応は侵害を保証します。相反する考慮は摩擦です。積極的なコミット前のスキャンと強制的なローテーションは、人々を遅くし、誤検知を生むので、統制を切るのではなく調整しなければなりません。証拠を持ち込んでください。シークレットスキャンがコミット前フックとCIの両方で動いているか、既知の漏洩を検出してローテーションするまでの平均時間、エンジニアがハードコードの誘惑を取り除くシークレット管理システムを持っているか。企業や政府の設定では、これをインシデントのプロセスと保持の規則に結びつけてください。監査可能な履歴にある漏洩した認証情報は、セキュリティのイベントであり、コンプライアンスのイベントでもあり、規制当局は誰が知っていて、どれだけ速く行動したかを問うからです。
ブランチは本当に短命ですか。そうでない所で、未完成の作業がフィーチャーフラグの陰に隠されず、ブランチに駐車されているのはなぜですか。 本章は、長い乖離がマージの苦痛の根源なので、トランクベース開発に強く傾き、フィーチャーフラグを、未完成の作業を何週間も隔離する代わりに安全にマージできる仕組みとして提示しています。大きなチームでは、これは個人の好みではなく調整の特性です。何週間も生きるブランチは、誰かがいずれ折り合いをつけなければならない現実の私的なフォークになり、その調整のコストは人数とともに増えます。相反する考慮は、フィーチャーフラグにも独自のコストがあることです。ランタイムの複雑さ、組み合わせのテスト、退役させなければならない古いフラグ。データを持ち込んでください。ブランチの寿命の実際の分布、統合が衝突や驚きを生む頻度、今存在する長寿命ブランチの数とその理由。大きな、あるいは規制された組織では、リリースの全体像も加えてください。本物の複数バージョンのサポートは、規律あるバックポートを伴う長寿命のリリースブランチを正当化しえて、それは日々の機能の作業をメインラインから外して駐車するのとは別の決定だからです。
履歴のあらゆる変更を、適切なセキュリティの境界の中で作者と根拠までたどれますか。そしてそれは監査に耐えますか。 本章は、アクセス制御、最小権限、変更を作業項目にリンクすることを、任意の仕上げではなく、組織の統制の枠組みの一部として扱っています。大きなチームでは、トレーサビリティが、不透明なコミットの流れを、インシデントやコンプライアンスのレビューの間に推論できるものに変え、アクセスの境界が、一つの侵害されたアカウントが決して触れてはならないコードに届くのを防ぎます。相反する考慮は開発者の速度です。必須の作業項目のリンク、細かい権限、必須のレビューは、小さく動きの速いチームなら省いて当然の儀式を加えます。証拠を持ち込んでください。保護されたブランチが、主張するチェックとレビューを実際に求めているか、コミットが承認された作業項目を実際に参照しているか、アクセスが今、実際のセキュリティの境界とどう対応しているか。企業や政府の文脈では、これを分類、保持、監査の義務に結びつけてください。監査できない履歴や広すぎるアクセスの付与は、プログラムを止めたり認定を落としたりしうる指摘になるからです。
セクター別の視点
スタートアップ。 速度と生存が勝ちます。リポジトリを一つ使い、トランクベースで作業し、短命なブランチを一日に数回マージし、未完成の作業は長いブランチではなく、単純なフィーチャーフラグの陰に隠します。公開リポジトリで漏洩した鍵は、被害を封じ込めるセキュリティチームのない会社を沈めかねないので、最初のコミットからシークレットスキャンを有効にしてください。凝ったブランチモデルや重いプロセスは省きます。保護されたmainブランチと意味のあるコミットメッセージが、速く動くのに十分な規律です。
小規模事業者。 専任のプラットフォームやDevOpsの専門家はおらず予算も厳しいので、管理された既定を、作るのではなく買ってください。ホスト型のGitプロバイダーは、ブランチ保護、必須のレビュー、シークレットスキャンを最初から提供するので、保守できないサーバーを自前でホストする代わりに、それらに頼ります。決定をデータ衛生として枠づけてください。どのリポジトリが機微な設定を保持しているかを把握し、認証情報をプロバイダーのシークレットマネージャーに置き、本当に必要な少数のルールをプラットフォームに徹底させます。
大企業。 難しい問題は、多数のチームにわたる一貫性です。グループがそれぞれ再発明するのをやめるよう、ブランチ保護、コミット規約、シークレットスキャンを組織全体の方針として標準化し、モノレポとポリレポの選択を結合のパターンごとに意図して行い、それが要求するスケールしたビルドツールやリポジトリをまたぐ調整に資金を出します。コードオーナーシップのルールで変更を適切なレビュアーにルーティングし、トレーサビリティのためにコミットを作業項目にリンクし、バージョン管理の衛生を、個人の習慣の問題ではなく、オーナーと指標を伴う統治された統制として扱います。
政府。 調達規則、透明性、公的な説明責任が設定全体を形づくります。すべてのコミットに承認された作業項目の参照を求め、分類の境界ごとにアクセスを管理し、文書化されたインシデントのプロセスのもとで、シークレットスキャンと即時のローテーションを必須にします。拠点がすべて一度にはアップグレードできない所では、長寿命のリリースブランチと規律あるバックポートで複数のデプロイされたバージョンをサポートし、認定、情報公開、監督の要請に慌てずに答えられるよう、履歴を監査可能に保ち、保持します。
事例
スタートアップ。 3人のスタートアップは、習慣と必要から、トランクベースで作業し、短命なブランチを一日に数回mainにマージし、半分できた機能を単純なフラグの陰に隠します。公開リポジトリで漏洩したAPIキーは、被害を封じ込めるセキュリティチームのない会社を沈めかねないので、最初のコミットからCIでシークレットスキャンを有効にします。一つのリポジトリ、保護されたmainブランチ、意味のあるコミットメッセージが、自分たちの履歴につまずくことなく速く動くのに十分な規律を与えます。
大企業。 大手のテクノロジー企業が、何百ものサービスと共有ライブラリを持つモノレポを運用しています。スケールしたビルドツールとコードオーナーシップのルールが、各変更を適切なレビュアーにルーティングします。一つのコミットで、共有ライブラリとすべての利用者を原子的に一度に更新でき、分散したリポジトリを悩ますバージョンのずれの問題を回避します。フィーチャーフラグを伴うトランクベース開発がメインラインをリリース可能に保ち、シークレットスキャンがリポジトリ全体でコミット時に認証情報をブロックします。
政府。 国の防衛関連の契約者は、厳格なトレーサビリティを守っています。すべてのコミットが承認された作業項目を参照しなければなりません。ブランチ保護は、通るセキュリティスキャンと独立したレビューを求め、アクセスは分類の境界ごとに厳しく管理されます。シークレットスキャンは必須で、露出した認証情報はインシデントのプロセスのもとで即座にローテーションされます。すべてが一度にはアップグレードできない拠点にまたがる複数のデプロイされたバージョンを、長寿命のリリースブランチが支え、セキュリティ修正は規律をもってバックポートされます。
ビジネスケース: 動機、ROI、TCO
健全なソース管理は、採用するのはほぼ無料で、それなしで済ますのは高価です。トランクベース開発と継続的インテグレーションは、高いソフトウェアデリバリー性能と最も強く関連する実践の一つで、それはさらに、より良い組織の成果と相関しています。きれいで追跡可能な履歴は、インシデントの診断と監査の充足にかかる時間を削り、規律あるブランチ管理は、統合の危機とマージのマラソンという、繰り返し発生する予算外のコストを省きます。
最大の偏ったリスクは、バージョン管理の中のシークレットです。一つの漏洩した認証情報が、どんなツールへの投資もはるかに上回るコストの侵害を引き起こしえ、履歴はそのような漏洩を残り続けさせます。予防は安く、後始末は安くありません。まずい構造の選択は、慢性的な摩擦として現れます。リポジトリをまたぐすべての変更が調整のプロジェクトになるか、モノレポのすべてのビルドがボトルネックになります。リーダーシップに論拠を示すには、ブランチ戦略をデリバリー指標とインシデント診断の時間に結びつけ、シークレットスキャンとアクセス制御を、高コストの侵害と監査のリスクに対する低コストの統制として枠づけてください。
アンチパターンと落とし穴
- 長寿命の乖離したブランチ: 苦痛で危険な統合イベントにマージされる、何週間もの隔離された作業。
- 履歴の中のシークレット: クローンに永遠に残り、露出したらローテーションが必要になるハードコードされた認証情報。
- 大きなバイナリをメインの履歴にコミットする: すべてのクローンを恒久的に肥大させ、すべての操作を遅くすること。
- 意味のないコミットメッセージ: 「fix」「wip」「changes」は、ドキュメントとしての履歴の価値を破壊します。
- 生成されたコードを手書きのようにコミットする: 雑音の多い差分、マージの衝突、信頼できる唯一の情報源についての混乱。
- 結合に合わないリポジトリ構造: 密に結合したコードのためのポリレポ、あるいはスケールしたツールのないモノレポ。
- 保護されていないメインライン: 必須のチェックがなく、壊れたコードやレビューされていないコードが全員の依存するブランチに届くこと。
成熟度モデル
- レベル1、開始: 場当たり的で反応的です。ブランチは即興で、ブランチは何週間も生き、コミットメッセージは「fix」や「wip」で、シークレットスキャンはなく、統合はマージの危機から次へとよろめきます。
- レベル2、発展: 基本的な実践は現れますが、チームごとに異なります。ブランチモデルとメッセージの規約は一部にありますが、ブランチはまだ長く生き、徹底は部分的で、シークレットスキャンはまばらで、リポジトリの構造は選ばれたのではなく引き継がれたものです。
- レベル3、標準化: 実践は文書化され、組織全体で徹底されています。短いブランチによるトランクベース開発、保護されて常にリリース可能なメインライン、徹底されたコミット規約、フックとCIの両方でのシークレットスキャン、最小権限のアクセス、そして意図したモノレポまたはポリレポの選択。
- レベル4、管理: ソースの実践がデータで測定され、制御されています。ブランチの寿命、統合の頻度、メインラインの破損率、漏洩したシークレットを検出してローテーションするまでの平均時間、変更と作業項目のトレーサビリティを、合意されたベースラインに対して追跡し、数字がずれたときは、次のインシデントを待たずに行動します。
- レベル5、オーケストレーション: 実践は継続的に改善され、組織全体に統合されています。ブランチ、リポジトリの構造、ツールはチームとコードの結合の変化に応じて適応し、自動化が衛生を端から端まで徹底し、バージョン管理のデータが、組織全体のデリバリー、セキュリティ、リスクの判断に反映されます。
議論のためのアイデア
- チームのブランチの寿命は実際に短いですか。そうでないなら、継続的インテグレーションを何が妨げていますか。
- モノレポかポリレポかの選択は、コードが実際にどれだけ結合しているかに合っていますか。
- 今日、大きなバイナリと生成された成果物をどう扱っていて、それはどんなコストになっていますか。
- 生きた認証情報が今コミットされたら何が起こり、どれだけ速く検出してローテーションできますか。
- あなたの文脈で、コミットメッセージとトレーサビリティの規律を、どこまで徹底する価値がありますか。
- フィーチャーフラグはブランチ戦略をどう変え、どんな新しいリスクを持ち込みますか。
要点
- 短命なブランチで頻繁に統合します。長い乖離は、避けようとしたはずの苦痛を引き起こします。
- メインラインをリリース可能に保ち、必須のチェックで保護します。
- シークレットを履歴に入れてはいけません。自動でスキャンし、入ったらすぐにローテーションします。
- モノレポかポリレポかは、実際の結合と調整のニーズで選びます。
- コミット履歴を、意味があり、規約に沿った、原子的なコミットを伴うドキュメントとして扱います。
参考文献とさらなる読み物
- Nicole Forsgren, Jez Humble, Gene Kim, Accelerate: The Science of Lean Software and DevOps
- Jez Humble and David Farley, Continuous Delivery
- Scott Chacon and Ben Straub, Pro Git
- Paul Hammant and others, writings on trunk-based development
- Conventional Commits specification (as a reference standard)
- Martin Fowler, articles on branching patterns and continuous integration