Google Copybara: リポジトリ間でのコード移動
(github.com/google)- Copybara は Google 内部で使われているツールで、複数のリポジトリ間でソースコードを変換・移動し、confidential リポジトリと public リポジトリを同期する用途で使われる
- 1つのリポジトリを 権威あるリポジトリ として選び、単一の信頼できる情報源を維持しつつ、どのリポジトリからでもコントリビューションを受け付けられ、どのリポジトリからでもリリースを作成できる
- 主なユースケースは反復的なコード移動で、confidential リポジトリから public リポジトリへ一部のコードを持ち出したり、public リポジトリの変更を authoritative リポジトリへ取り込んだりする流れをサポートする
- Copybara は状態を別サーバーではなく対象リポジトリの コミットメッセージラベル に保存する stateless 方式のため、複数のユーザーやサービスが同じ設定とリポジトリで同じ結果を得られる
- 現在サポートされているリポジトリ種別は Git で、Mercurial の読み取りは実験的機能。拡張可能な構造により、カスタムの origin と destination を追加できる
Copybara が解決する問題
- Copybara はリポジトリ間でのソースコードの移動と変換のためのツール
- ソースコードを複数のリポジトリに存在させる必要がある場合があり、Copybara はそのようなリポジトリ間でコードを変換・移動できるようにする
- 代表的なケースは、confidential リポジトリ と public リポジトリ を同期して維持するプロジェクト
- 最も一般的な使い方は、あるリポジトリから別のリポジトリへコードを繰り返し移すこと
- 新しいリポジトリへコードを一度だけ移す用途にも使える
権威リポジトリとコントリビューションの流れ
- Copybara では、リポジトリの1つを authoritative repository として選ぶ必要がある
- 常に1つの source of truth が存在するようにするための条件
- コントリビューションはどのリポジトリからでも可能
- リリースもどのリポジトリからでも作成できる
- 非権威リポジトリで変更が発生した場合、Copybara がその変更を変換して権威リポジトリの適切な場所へ移動できる
- 例としては、public リポジトリの contributor が作成した変更
- マージコンフリクトは、権威リポジトリ内で古い変更を処理する場合と同じ方法で扱う
使用例
- Copybara の使用例には次のものが含まれる
- confidential リポジトリのコードの一部を public リポジトリへ持ち出す
- public リポジトリのコードを confidential リポジトリへ取り込む
- non-authoritative リポジトリの変更を authoritative リポジトリへ取り込む
- 例の設定では
core.workflowで origin と destination を定義する- origin は
git.github_originでhttps://github.com/google/copybara.gitのmasterを使う - destination は
git.destinationでfile:///tmp/fooを使う destination_filesはthird_party/copybara/**を対象とし、README_INTERNAL.txtは除外するcore.replaceとcore.moveで BUILD ファイルのパス置換とディレクトリ移動を行う
- origin は
- 実行例は、bare Git リポジトリを作成した後に
copybara copy.bara.skyを実行する方式
状態保存方式とリポジトリ対応
- Copybara の主な特徴の1つは stateless な構造であること
- より正確には、状態は対象リポジトリに保存される
- 保存場所はコミットメッセージの ラベル
- この方式により、複数のユーザーやサービスが同じ設定とリポジトリの組み合わせを使って同じ結果を得られる
- 現在サポートされているリポジトリ種別は Git
- Mercurial リポジトリからの読み取り機能は利用できるが、まだ 実験的
- 拡張可能なアーキテクチャにより、ほぼすべてのユースケースに合う bespoke な origin と destination を追加できる
- 他のリポジトリ種別の正式サポートは今後追加される予定
インストールとビルド
- 始める最も簡単な方法は、事前ビルド済みバイナリを含む週次の snapshot release を使うこと
- リリースは自動生成される
- 手動テスト、バージョン互換性、正確性の保証はない
- リリースは
https://github.com/google/copybara/releasesから選ぶ
- 未リリース版を使うには HEAD からビルドする必要がある
- JDK 11 のインストールが必要
- Bazel のインストールが必要
git clone https://github.com/google/copybara.gitでソースをクローンbazel build //java/com/google/copybaraでビルド- 実行可能な uberjar は
bazel build //java/com/google/copybara:copybara_deploy.jarで生成 - テストは
bazel test //...で実行可能
- 一部のテストでは Mercurial や Quilt のような基盤ツールのインストールが必要
- Pull Request が該当モジュールに関連しない場合は、そのテストをスキップしてもよい
- CI はすべてのテストを実行する
- Arch Linux では
aur/copybara-gitパッケージを利用できる
Bazel で事前ビルド済み Copybara を使う
- 週次 snapshot release を Bazel で利用できる
- Copybara は class file version 65.0 で提供されるため、Java Runtime 21 以上で実行する必要がある
.bazelrcにrun --java_runtime_version=remotejdk_21を追加する必要がある
http_jarで release artifact をダウンロードするWORKSPACEではload("@bazel_tools//tools/build_defs/repo:http.bzl", "http_jar")を使うMODULE.bazelではhttp_jar = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_jar")を使う
WORKSPACEまたはMODULE.bazelで[version]の箇所を埋め、copybara_deploy.jarを指定する- BUILD ファイルでは
java_binaryを宣言し、com.google.copybara.Mainを main class として使う - 実行例は
bazel run //tools:copybara -- migrate copy.bara.sky
外部 Bazel リポジトリとしてソースをビルド
- Copybara 依存関係のための便利なマクロが提供されている
WORKSPACEにhttp_archiveを追加し、{{ sha256sum }}と{{ commit }}の値を埋める- その後、次のマクロをロードして呼び出す
copybara_repositories()copybara_maven_repositories()copybara_go_repositories()
- ワークスペース内で
bazel run @com_github_google_copybara//java/com/google/copybara -- <args...>によりビルドと実行ができる
Docker の使用
- Docker で Copybara をビルド・実行する方法は現在 実験的
- ビルドは
docker build --rm -t copybara .で行う - 実行は対象コードのルートで
docker run -it -v "$(pwd)":/usr/src/app copybara helpの形で行う - コンテナ実行引数の代わりに環境変数を使える
COPYBARA_SUBCOMMAND=migrate: 実行コマンドを変更、デフォルトはmigrateCOPYBARA_CONFIG=copy.bara.sky: 設定ファイルのパスを指定、デフォルトはルートのcopy.bara.skyCOPYBARA_WORKFLOW=default: 実行する workflow を指定、デフォルトはdefaultCOPYBARA_SOURCEREF='': sourceref を指定、デフォルト値なしCOPYBARA_OPTIONS='': Copybara オプションを指定、デフォルト値なし
- Git 設定と SSH 認証情報は Docker コンテナに共有できる
- 例として
~/.gitconfig、~/.ssh、SSH_AUTH_SOCKをコンテナにマウントする方法がある
- 例として
ドキュメントと問い合わせ
- ドキュメントはまだ作業中
- 提供されている資料は次のとおり
- 質問は mailing list で受け付けている
- Bazel のテストエラーをログファイルの
catなしで見るには、~/.bazelrcにtest --test_output=streamedを追加できる
1件のコメント
Hacker Newsのコメント
ちょうど自分がゲーム開発スタジオで使うために作った Perforce対応パッチをオープンソースとして公開した直後にこの記事が出たので面白かった
Copybaraの主な用途がGoogle内部のコード配布であり、そのコードがPerforceに関連するPiperにあることを考えると、Perforce対応がなく、Git対応だけが実質的にあるのはかなり意外だった
PRを作る前にGit履歴を見たところ、Gerrit Change-IDの表示が多かったので、どこか自分がアクセスできないGerritコードレビューシステムがあり、自分のPRはアップストリームされないのではないかと心配にもなった
Perforce向けのGerrit/Rietveldがない点も残念だが、すべてを望むことはできない
https://github.com/google/copybara/pull/347
https://abseil.io/resources/swe-book/html/ch19.html
https://read.engineerscodex.com/p/how-google-takes-the-pain-...
外部ツールでCritiqueほど良いものはまだ見つけられておらず、GitHubの貧弱なPRレビュー機能が多くの人に受け入れられているのは驚き。似たレベルのツールを知っている人がいれば聞いてみたい
数年前にGoogleを離れるときにかなり入念に探し、https://codeapprove.com/が最も近かったが、それでも欠けている部分は多かった
内部モノレポに置かれているgVisorやBazelのようなオープンソースプロジェクトも、多少の違いはあるが、おおむね似た運用になっている
この領域の別の興味深いツールとして、Rustはコミット同期に Josh というツールを使っている
https://josh-project.dev
Rust側のブログ記事もある
https://blog.rust-lang.org/inside-rust/2026/06/04/how-josh-h...
Metaには以前fbshipitというオープンソースツールがあったが、公開リポジトリによると、もう使われていないらしい
https://github.com/facebookarchive/fbshipit
この分野にほかのツールはまだあるだろうか?
その後Git本体にマージされた
https://manpages.debian.org/testing/git-man/git-subtree.1.en...
https://docs.github.com/en/get-started/using-git/about-git-s...
複数のリポジトリで少しだけコードを共有したいが、ライブラリとして切り出して参照を張り、バージョンリリースを発行し、依存するリポジトリを更新する手間をかけるほどの価値はない場合にも、これは便利なのだろうか?
例えば、共通のドメインモデルが入っているフォルダを、1つの主リポジトリからほかのリポジトリへ単に 同期する、といった使い方ができるのか気になる
Go流に「依存関係を大量に持つより、少しコピーするほうがよい」という哲学に近い用途
一部のプロジェクトはモノレポで開発され、Copybaraで外部にエクスポートされる
うちのチームでは内部的にStarlarkルールセットのバージョン管理にも使っている
公開リポジトリを社内の非公開リポジトリの依存関係にすると、開発面ではかなり面倒になる。そうした依存関係がツリー状に増えていくと、本当に頭痛の種になる
かなり長く使ってきており、主に大きなプロジェクト内で作ったツールが単独リリースできるほど大きくなったときに使っている
コードをエクスポートして再び取り込む双方向デプロイ全体を行えるほど強力だが、それは面倒すぎるので避けている
私はたいてい、元のリポジトリからフォルダを1つ切り出しつつ履歴は保持する、単純な一回限りのエクスポートに使っている。その後の開発は新しいリポジトリへ移す
新しいプロジェクト構造がまったく違っていても
Git blameが動くので満足している双方向は厄介になる。パスの再マッピング、ファイルの除外、ヘッダー削除のような変換は一方向なら簡単だが、常にきれいに逆変換できるとは限らないからだ
両側がどちらも分岐すると、Copybara のベースライン追跡はややこしい結果を出し始める。意味的には同じコミットでも、変換後には互いに異なる SHA が生成されるためだ
知っておくべき点は、履歴の「保持」は本当の移植ではなく、書き換えられたコミットをチェリーピックする方式だということ。ファイル内容と作者情報は引き継がれるので
Git blameは動くが、SHA は新しく生成されるCopybara は元の SHA をコミットメッセージのトレーラー
GitOrigin-RevIdに入れておくので、後でリポジトリ間のコミットを照合する必要があるときに便利52年を超える進歩とは :-)
2026年7月: Google copybara は、2つの本番リポジトリ間でコードを移動できるようにしてくれる
1974年3月: IBM COPY は、2つの本番パーティションデータセット間でコードを移動できるようにしてくれた。OS/MVT および OS/VS2 TSO Data Utilities COPY, FORMAT, LIST, MERGE User's Guide and Reference https://www.computinghistory.org.uk/downloads/8987
Dagster では、公開用リポジトリがより大きな内部モノレポの中に存在できるようにハブ・アンド・スポークモデルを構成するために Copybara を使っており、動作はしたが、かなり多くの回り道的な処理が必要だった
https://dagster.io/blog/monorepos-the-hub-and-spoke-model-an...
除外や変換なしにリポジトリ同期だけが必要なら、あえて使わないと思う。今は合っているかもしれないが、kaniko や多くの Google 製品・ツールのようにアーカイブ化されたり終了したりすると困る可能性がある
GitLab には、GitLab から GitHub や他の Git プロバイダー/サーバーへミラーリングする非常に単純な方法がある
たとえば外部の
bzlを内部の BlazeBUILD互換の形に変えたり、外部 import と内部のthird_party式 import の間で変換したりする作業だ純粋なミラーなら Copybara は重すぎる
いいね。私も約5年前に、ネストした Git リポジトリとスクリプトで似たようなものを作り、非公開・公開リポジトリを一緒に扱う目的を達成した
私のシェルスクリプトは、当然ながらGoogle 規模ではなかった
git subtreeのラッパーだと思ったが、見てみるとはるかに多くのことをしているようだたとえば同期中にコミット作者のメールアドレスを変更する機能もある