1P by GN⁺ | ★ favorite | 댓글 1개
  • Copybara는 Google 내부에서 쓰이는 도구로, 여러 저장소 사이에서 소스 코드를 변환하고 이동해 confidential 저장소와 public 저장소를 동기화하는 사례에 쓰임
  • 하나의 저장소를 권위 있는 저장소로 선택해 단일 진실 공급원을 유지하지만, 기여는 어느 저장소에서도 받을 수 있고 릴리스도 어느 저장소에서든 만들 수 있음
  • 주요 사용 사례는 반복적인 코드 이동이며, confidential 저장소에서 public 저장소로 일부 코드를 가져오거나 public 저장소 변경을 authoritative 저장소로 가져오는 흐름을 지원함
  • Copybara는 상태를 별도 서버가 아니라 대상 저장소의 커밋 메시지 라벨에 저장하는 stateless 방식이라, 여러 사용자나 서비스가 같은 설정과 저장소에서 같은 결과를 얻을 수 있음
  • 현재 지원 저장소 유형은 Git이며 Mercurial 읽기는 실험적 기능이고, 확장 가능한 구조로 맞춤 origin과 destination을 추가할 수 있음

Copybara가 해결하는 문제

  • Copybara는 저장소 간 소스 코드 이동과 변환을 위한 도구임
  • 소스 코드가 여러 저장소에 존재해야 하는 경우가 있으며, Copybara는 이런 저장소 사이에서 코드를 변환하고 이동할 수 있게 함
  • 대표 사례는 confidential 저장소public 저장소를 동기화해서 유지하는 프로젝트임
  • 가장 흔한 사용 방식은 한 저장소에서 다른 저장소로 코드를 반복적으로 옮기는 것임
  • 새 저장소로 코드를 한 번만 옮기는 용도로도 사용할 수 있음

권위 저장소와 기여 흐름

  • Copybara는 저장소 중 하나를 authoritative repository로 선택해야 함
    • 항상 하나의 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.gitmaster를 사용함
    • destination은 git.destination으로 file:///tmp/foo를 사용함
    • destination_filesthird_party/copybara/**를 대상으로 하고 README_INTERNAL.txt는 제외함
    • core.replacecore.move로 BUILD 파일 경로 치환과 디렉터리 이동을 수행함
  • 실행 예시는 bare Git 저장소를 만든 뒤 copybara copy.bara.sky를 실행하는 방식임

상태 저장 방식과 저장소 지원

  • Copybara의 주요 특징 중 하나는 stateless 구조임
  • 더 정확히는 상태를 대상 저장소에 저장함
    • 저장 위치는 커밋 메시지의 라벨
  • 이 방식으로 여러 사용자나 서비스가 같은 설정과 저장소 조합을 사용해 같은 결과를 얻을 수 있음
  • 현재 지원되는 저장소 유형은 Git
  • Mercurial 저장소에서 읽는 기능은 가능하지만 아직 실험적
  • 확장 가능한 아키텍처를 통해 거의 모든 사용 사례에 맞는 bespoke origin과 destination을 추가할 수 있음
  • 다른 저장소 유형의 공식 지원은 향후 추가될 예정임

설치와 빌드

  • 시작하기 가장 쉬운 방법은 사전 빌드 바이너리가 포함된 주간 snapshot release를 사용하는 것임
  • 미릴리스 버전을 쓰려면 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 이상에서 실행해야 함
    • .bazelrcrun --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 의존성을 위한 편의 매크로가 제공됨
  • WORKSPACEhttp_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: 실행 명령 변경, 기본값은 migrate
    • COPYBARA_CONFIG=copy.bara.sky: 설정 파일 경로 지정, 기본값은 루트의 copy.bara.sky
    • COPYBARA_WORKFLOW=default: 실행할 workflow 지정, 기본값은 default
    • COPYBARA_SOURCEREF='': sourceref 지정, 기본값 없음
    • COPYBARA_OPTIONS='': Copybara 옵션 지정, 기본값 없음
  • Git 설정과 SSH 자격 증명은 Docker 컨테이너에 공유할 수 있음
    • 예시는 ~/.gitconfig, ~/.ssh, SSH_AUTH_SOCK를 컨테이너에 마운트하는 방식임

문서와 문의

댓글과 토론

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

    • Gerrit/Rietveld에 Perforce 지원이 없는 이유 중 하나는 Google이 Piper에 저장된 코드 변경에 그 도구들을 쓰지 않기 때문임. 대신 Critique를 사용함
      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/가 가장 가까웠지만 여전히 빠진 부분이 많았음
    • Piper는 Perforce의 포크가 아님. Perforce와 API 호환은 되지만 완전히 다른 구현임
    • 그 저장소는 PR을 받아줌. 다만 내부에서 병합한 뒤 다시 외부로 내보내는 방식임
      내부 모노레포에 사는 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
    이 분야에 다른 도구가 또 있을까?

  • 여러 저장소가 약간의 코드를 공유하고 싶지만, 라이브러리로 분리하고 참조를 걸고 버전 릴리스를 발행하고 의존 저장소를 갱신하는 수고까지는 가치가 없을 때도 이게 편한가?
    예를 들어 공통 도메인 모델이 들어 있는 폴더를 하나의 주 저장소에서 다른 저장소들로 그냥 동기화하는 식으로 쓸 수 있는지 궁금함
    Go식으로 “의존성을 잔뜩 두는 것보다 약간 복사하는 게 낫다”는 철학에 가까운 용도임

    • 주로 외부 오픈소스 프로젝트를 내부 모노레포와 동기화하는 데 쓰임. 정책상 빌드 산출물보다 소스 코드 가져오기를 요구하지만 예외를 받을 수는 있음
      일부 프로젝트는 모노레포에서 개발되고 Copybara로 외부에 내보내짐
      우리 팀은 내부적으로 Starlark 규칙 집합의 버전 관리에도 사용함
    • 내부에는 모노레포가 있고 그중 일부를 세상에 오픈소스로 공개하고 싶을 때 쓰는 도구임. 그래도 코드는 계속 모노레포 안에 있어야 하니 이게 해법이 됨
      공개 저장소를 사내 비공개 저장소의 의존성으로 두면 개발 측면에서 꽤 골치 아픔. 그런 의존성이 트리처럼 늘어나면 정말 두통거리임
    • Copybara로 그런 일도 할 수는 있지만, 그렇게 쓰면 짜증 나고 지루할 가능성이 큼. 라이브러리를 분리하거나 파일 몇 개를 별도 저장소에 밀어 넣는 문제보다 더 귀찮을 수 있음
  • 꽤 오래 써 왔고, 주로 큰 프로젝트 안에서 만든 도구가 독립 릴리스할 만큼 커졌을 때 사용함
    코드를 내보내고 다시 가져오는 양방향 배포 전체를 할 만큼 강력하지만, 그런 건 너무 번거로워서 사양함
    나는 대체로 원래 저장소에서 폴더 하나를 떼어 내되 이력은 보존하는 단순한 일회성 내보내기에 씀. 이후 개발은 새 저장소로 옮김
    새 프로젝트 구조가 완전히 달라도 Git blame이 작동하니 만족함

    • 단방향 패턴이 실제로 Google 내부에서도 쓰는 방식임. 모노레포에서 GitHub로 바깥쪽 동기화를 함
      양방향은 지저분해지는데, 경로 재매핑, 파일 제외, 헤더 제거 같은 변환은 한 방향으로는 쉽지만 항상 깨끗하게 역변환할 수는 없기 때문임
      양쪽이 모두 갈라지면 Copybara의 기준선 추적이 헷갈리는 결과를 내기 시작함. 의미상 같은 커밋도 변환 뒤에는 서로 다른 SHA를 만들기 때문임
      알아둘 만한 점은 이력 “보존”이 진짜 이식이 아니라, 재작성된 커밋을 체리픽하는 방식이라는 것임. 파일 내용과 작성자 정보가 넘어가니 Git blame은 작동하지만 SHA는 새로 생김
      Copybara는 원래 SHA를 커밋 메시지 트레일러 GitOrigin-RevId에 넣어 두므로, 나중에 저장소 사이의 커밋을 대조해야 할 때 유용함
  • 52년 넘는 진보라니 :-)
    2026년 7월: Google copybara는 두 프로덕션 저장소 사이에서 코드를 옮길 수 있게 해줌
    1974년 3월: IBM COPY는 두 프로덕션 파티션 데이터 세트 사이에서 코드를 옮길 수 있게 해줌. 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 제공자/서버로 미러링하는 아주 단순한 방법이 있음

    • Copybara가 종료될 가능성은 정말 낮다고 봄. 알기로는 google3와 대규모 오픈소스 프로젝트 유지·벤더링 방식에서 꽤 핵심 도구
    • 맞음, Copybara는 한쪽 또는 양쪽 방향으로 변환을 하는 데 쓰는 도구에 가까움
      예를 들어 외부 bzl을 내부 Blaze BUILD 호환 형태로 바꾸거나, 외부 import와 내부 third_party식 import 사이를 바꾸는 등의 작업임
      순수 미러라면 Copybara는 지나치게 무거움
  • 좋다. 나도 약 5년 전에 중첩 Git 저장소와 스크립트로 비슷한 걸 만들어서 비공개·공개 저장소를 함께 다루는 목적을 달성했음
    내 셸 스크립트는 당연히 Google 규모는 아니었음

    • 나도 비슷했음. 처음엔 git subtree 래퍼일 줄 알았는데, 보니 훨씬 더 많은 일을 하는 것 같음
      예를 들어 동기화 중에 커밋 작성자 이메일을 바꾸는 기능도 있음