1 điểm bởi GN⁺ 4 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Copybara là công cụ được sử dụng nội bộ tại Google để chuyển đổi và di chuyển mã nguồn giữa nhiều kho lưu trữ, được dùng trong các trường hợp đồng bộ kho lưu trữ confidential và kho lưu trữ public
  • Có thể chọn một kho lưu trữ làm kho lưu trữ có thẩm quyền để duy trì một nguồn chân lý duy nhất, nhưng vẫn có thể nhận đóng góp từ bất kỳ kho nào và tạo bản phát hành từ bất kỳ kho nào
  • Trường hợp sử dụng chính là di chuyển mã lặp lại, hỗ trợ luồng lấy một phần mã từ kho confidential sang kho public hoặc đưa thay đổi từ kho public vào kho authoritative
  • Copybara sử dụng cách tiếp cận stateless, lưu trạng thái không phải trên máy chủ riêng mà trong nhãn của thông điệp commit ở kho đích, nên nhiều người dùng hoặc dịch vụ có thể nhận được cùng kết quả với cùng cấu hình và kho lưu trữ
  • Loại kho lưu trữ hiện được hỗ trợ là Git; khả năng đọc Mercurial là tính năng thử nghiệm, và kiến trúc có thể mở rộng để thêm origin và destination tùy biến

Vấn đề mà Copybara giải quyết

  • Copybara là công cụ để di chuyển và chuyển đổi mã nguồn giữa các kho lưu trữ
  • Có những trường hợp mã nguồn cần tồn tại ở nhiều kho lưu trữ, và Copybara cho phép chuyển đổi cũng như di chuyển mã giữa các kho đó
  • Trường hợp tiêu biểu là dự án cần duy trì đồng bộ giữa kho lưu trữ confidentialkho lưu trữ public
  • Cách dùng phổ biến nhất là lặp lại việc chuyển mã từ kho này sang kho khác
  • Công cụ này cũng có thể dùng để chuyển mã một lần sang kho mới

Kho lưu trữ có thẩm quyền và luồng đóng góp

  • Copybara yêu cầu chọn một trong các kho lưu trữ làm authoritative repository
    • Đây là điều kiện để luôn tồn tại một source of truth duy nhất
  • Có thể đóng góp từ bất kỳ kho lưu trữ nào
  • Cũng có thể tạo bản phát hành từ bất kỳ kho lưu trữ nào
  • Khi thay đổi phát sinh ở kho không có thẩm quyền, Copybara có thể chuyển đổi thay đổi đó và đưa nó đến vị trí phù hợp trong kho có thẩm quyền
    • Ví dụ là thay đổi do contributor trong kho public tạo ra
    • Xung đột hợp nhất được xử lý giống như cách xử lý các thay đổi cũ trong kho có thẩm quyền

Ví dụ sử dụng

  • Các ví dụ dùng Copybara bao gồm
    • Đưa một phần mã từ kho confidential sang kho public
    • Đưa mã từ kho public vào kho confidential
    • Đưa thay đổi từ kho non-authoritative vào authoritative repository
  • Cấu hình ví dụ định nghĩa origin và destination bằng core.workflow
    • origin dùng git.github_origin với nhánh master của https://github.com/google/copybara.git
    • destination dùng git.destination với file:///tmp/foo
    • destination_files nhắm tới third_party/copybara/** và loại trừ README_INTERNAL.txt
    • core.replacecore.move được dùng để thay thế đường dẫn tệp BUILD và di chuyển thư mục
  • Ví dụ chạy là tạo một kho Git bare rồi chạy copybara copy.bara.sky

Cách lưu trạng thái và hỗ trợ kho lưu trữ

  • Một trong những đặc điểm chính của Copybara là kiến trúc stateless
  • Nói chính xác hơn, trạng thái được lưu trong kho lưu trữ đích
    • Vị trí lưu là nhãn trong thông điệp commit
  • Với cách này, nhiều người dùng hoặc dịch vụ có thể dùng cùng một cấu hình và cùng tập hợp kho lưu trữ để nhận được cùng kết quả
  • Loại kho lưu trữ hiện được hỗ trợ là Git
  • Có thể đọc từ kho Mercurial nhưng đây vẫn là tính năng thử nghiệm
  • Nhờ kiến trúc mở rộng được, có thể thêm origin và destination dạng bespoke cho gần như mọi trường hợp sử dụng
  • Hỗ trợ chính thức cho các loại kho lưu trữ khác sẽ được bổ sung trong tương lai

Cài đặt và build

  • Cách dễ nhất để bắt đầu là dùng snapshot release hằng tuần có sẵn binary dựng sẵn
    • Bản phát hành được tạo tự động
    • Không có kiểm thử thủ công, không đảm bảo tương thích phiên bản hay độ chính xác
    • Có thể chọn bản phát hành tại https://github.com/google/copybara/releases
  • Nếu muốn dùng phiên bản chưa phát hành, cần build từ HEAD
    • Cần cài JDK 11
    • Cần cài Bazel
    • Sao chép mã nguồn bằng git clone https://github.com/google/copybara.git
    • Build bằng bazel build //java/com/google/copybara
    • File uberjar thực thi được tạo bằng bazel build //java/com/google/copybara:copybara_deploy.jar
    • Có thể chạy test bằng bazel test //...
  • Một số test yêu cầu cài các công cụ nền như Mercurial và Quilt
    • Nếu Pull Request không liên quan đến các mô-đun đó thì có thể bỏ qua các test tương ứng
    • CI sẽ chạy toàn bộ test
  • Trên Arch Linux, có thể dùng gói aur/copybara-git

Dùng Copybara dựng sẵn trong Bazel

  • Có thể dùng snapshot release hằng tuần trong Bazel
  • Copybara được cung cấp với class file version 65.0, nên phải chạy trên Java Runtime 21 trở lên
    • Cần thêm run --java_runtime_version=remotejdk_21 vào .bazelrc
  • Tải artifact phát hành bằng http_jar
    • Trong WORKSPACE, dùng load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_jar")
    • Trong MODULE.bazel, dùng http_jar = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_jar")
  • Trong WORKSPACE hoặc MODULE.bazel, điền chỗ [version] để chỉ định copybara_deploy.jar
  • Trong tệp BUILD, khai báo java_binary và dùng com.google.copybara.Main làm main class
  • Ví dụ chạy là bazel run //tools:copybara -- migrate copy.bara.sky

Build mã nguồn như kho Bazel bên ngoài

  • Có cung cấp macro tiện lợi cho các dependency của Copybara
  • Thêm http_archive vào WORKSPACE và điền các giá trị {{ sha256sum }}{{ commit }}
  • Sau đó load và gọi các macro sau
    • copybara_repositories()
    • copybara_maven_repositories()
    • copybara_go_repositories()
  • Trong workspace, có thể build và chạy bằng bazel run @com_github_google_copybara//java/com/google/copybara -- <args...>

Sử dụng Docker

  • Cách build và chạy Copybara bằng Docker hiện vẫn là thử nghiệm
  • Build bằng docker build --rm -t copybara .
  • Chạy từ thư mục gốc của mã đích theo dạng docker run -it -v "$(pwd)":/usr/src/app copybara help
  • Có thể dùng biến môi trường thay cho tham số khi chạy container
    • COPYBARA_SUBCOMMAND=migrate: thay đổi lệnh chạy, mặc định là migrate
    • COPYBARA_CONFIG=copy.bara.sky: chỉ định đường dẫn tệp cấu hình, mặc định là copy.bara.sky ở thư mục gốc
    • COPYBARA_WORKFLOW=default: chỉ định workflow cần chạy, mặc định là default
    • COPYBARA_SOURCEREF='': chỉ định sourceref, mặc định không có
    • COPYBARA_OPTIONS='': chỉ định các tùy chọn Copybara, mặc định không có
  • Có thể chia sẻ cấu hình Git và thông tin xác thực SSH với container Docker
    • Ví dụ là mount ~/.gitconfig, ~/.ssh, SSH_AUTH_SOCK vào container

Tài liệu và liên hệ

1 bình luận

 
Ý kiến trên Hacker News
  • Thật thú vị là bài này xuất hiện đúng lúc ngay sau khi tôi mã nguồn mở bản vá hỗ trợ Perforce mà tôi làm để dùng ở studio phát triển game
    Xét việc mục đích chính của Copybara là phân phối mã nội bộ của Google, và số mã đó nằm trong Piper có liên quan đến Perforce, thì việc không có hỗ trợ Perforce mà chỉ có hỗ trợ Git đáng kể là điều khá bất ngờ
    Trước khi tạo PR, tôi xem lịch sử Git thì thấy rất nhiều dấu Gerrit Change-ID, nên cũng lo là có một hệ thống review mã Gerrit nào đó mà tôi không thể truy cập và PR của tôi sẽ không được đưa upstream
    Việc không có Gerrit/Rietveld cho Perforce cũng đáng tiếc, nhưng không thể đòi hỏi mọi thứ được
    https://github.com/google/copybara/pull/347

    • Một trong những lý do Gerrit/Rietveld không có hỗ trợ Perforce là vì Google không dùng các công cụ đó cho những thay đổi mã được lưu trong Piper. Thay vào đó họ dùng Critique
      https://abseil.io/resources/swe-book/html/ch19.html
      https://read.engineerscodex.com/p/how-google-takes-the-pain-...
      Tôi vẫn chưa tìm được công cụ bên ngoài nào tốt ngang Critique, và thật ngạc nhiên khi công cụ review PR còn khá yếu của GitHub lại được đa số chấp nhận. Nếu ai biết công cụ nào ở mức tương tự thì tôi rất muốn nghe
      Khi rời Google vài năm trước, tôi đã tìm khá kỹ, và https://codeapprove.com/ là thứ gần nhất, nhưng vẫn còn thiếu khá nhiều
    • Piper không phải là bản fork của Perforce. Nó tương thích API với Perforce, nhưng là một triển khai hoàn toàn khác
    • Kho đó có nhận PR. Chỉ là họ sẽ hợp nhất ở nội bộ trước rồi lại đẩy ngược ra bên ngoài
      Các dự án mã nguồn mở như gVisor hay Bazel sống trong monorepo nội bộ cũng thường vận hành gần như vậy, dù có khác đôi chút tùy dự án
  • Một công cụ thú vị khác trong lĩnh vực này là Rust dùng công cụ tên Josh để đồng bộ commit
    https://josh-project.dev
    Cũng có một bài blog từ phía Rust
    https://blog.rust-lang.org/inside-rust/2026/06/04/how-josh-h...
    Meta trước đây từng có một công cụ mã nguồn mở tên fbshipit, nhưng theo kho công khai thì họ không còn dùng nữa
    https://github.com/facebookarchive/fbshipit
    Còn công cụ nào khác trong mảng này không?

  • Điều này có tiện khi nhiều kho muốn chia sẻ một ít mã, nhưng lại không đáng để tách thành thư viện, thêm tham chiếu, phát hành phiên bản, rồi cập nhật các kho phụ thuộc không?
    Ví dụ, liệu có thể dùng nó để đơn giản đồng bộ một thư mục chứa mô hình miền dùng chung từ một kho chính sang các kho khác không?
    Đây là kiểu nhu cầu gần với triết lý Go rằng “thà sao chép một chút còn hơn mang theo cả đống phụ thuộc”

    • Chủ yếu nó được dùng để đồng bộ dự án mã nguồn mở bên ngoài với monorepo nội bộ. Chính sách yêu cầu nhập mã nguồn thay vì sản phẩm build, nhưng vẫn có thể xin ngoại lệ
      Một số dự án được phát triển trong monorepo rồi dùng Copybara để xuất ra bên ngoài
      Nhóm của chúng tôi cũng dùng nó nội bộ để quản lý phiên bản cho một bộ quy tắc Starlark
    • Đây là công cụ dùng khi bên trong có monorepo và bạn muốn công khai mã nguồn mở một phần của nó ra thế giới. Nhưng mã vẫn phải tiếp tục nằm trong monorepo, nên đây là lời giải
      Nếu để kho công khai làm dependency của kho riêng nội bộ thì xét về mặt phát triển sẽ khá phiền. Khi các dependency như vậy bắt đầu mọc thành cây thì thực sự rất đau đầu
    • Có thể làm việc đó bằng Copybara, nhưng nếu dùng theo kiểu đó thì nhiều khả năng sẽ thấy bực và chán. Nó có thể còn phiền hơn cả việc tách thư viện ra hoặc đẩy vài file sang một kho riêng
  • Tôi đã dùng khá lâu rồi, chủ yếu khi một công cụ được tạo ra trong một dự án lớn phát triển đủ lớn để phát hành độc lập
    Nó đủ mạnh để xử lý toàn bộ quy trình phân phối hai chiều gồm xuất mã rồi nhập lại, nhưng việc đó quá phiền phức nên tôi tránh
    Tôi chủ yếu dùng nó cho các lần xuất một chiều đơn giản: tách một thư mục khỏi kho lưu trữ gốc nhưng vẫn giữ lịch sử. Sau đó việc phát triển được chuyển sang kho lưu trữ mới
    Tôi hài lòng vì Git blame vẫn hoạt động ngay cả khi cấu trúc dự án mới hoàn toàn khác

    • Mẫu một chiều đó thực ra cũng là cách Google dùng nội bộ. Họ đồng bộ ra ngoài từ monorepo lên GitHub
      Hai chiều thì trở nên lộn xộn, vì các phép biến đổi như ánh xạ lại đường dẫn, loại trừ tệp, xóa header thì theo một chiều khá dễ nhưng không phải lúc nào cũng có thể đảo ngược sạch sẽ
      Khi cả hai bên đều tiếp tục phân nhánh, việc theo dõi baseline của Copybara bắt đầu cho ra kết quả khó hiểu. Các commit có cùng ý nghĩa nhưng sau biến đổi lại tạo ra SHA khác nhau
      Điều đáng biết là việc “giữ” lịch sử không phải là di chuyển nguyên bản, mà là cherry-pick các commit đã được viết lại. Nội dung tệp và thông tin tác giả được mang sang nên Git blame vẫn hoạt động, nhưng SHA thì được tạo mới
      Copybara lưu SHA gốc trong trailer của thông điệp commit là GitOrigin-RevId, nên rất hữu ích khi sau này cần đối chiếu commit giữa các kho lưu trữ
  • Hơn 52 năm tiến bộ cơ à :-)
    Tháng 7 năm 2026: Google copybara cho phép chuyển mã giữa hai kho lưu trữ production
    Tháng 3 năm 1974: IBM COPY cho phép chuyển mã giữa hai tập dữ liệu phân vùng production. OS/MVT và OS/VS2 TSO Data Utilities COPY, FORMAT, LIST, MERGE User's Guide and Reference https://www.computinghistory.org.uk/downloads/8987

  • Ở Dagster, chúng tôi đã dùng Copybara để dựng một mô hình hub-spoke cho phép kho lưu trữ công khai tồn tại bên trong một monorepo nội bộ lớn hơn, và nó có hoạt động, nhưng cần khá nhiều cách xử lý vòng vo
    https://dagster.io/blog/monorepos-the-hub-and-spoke-model-an...

  • Nếu chỉ cần đồng bộ kho lưu trữ mà không có loại trừ hay biến đổi, có lẽ tôi sẽ không dùng nó. Có thể hiện tại vẫn ổn, nhưng sẽ rắc rối nếu nó bị đưa vào diện lưu trữ hoặc ngừng phát triển như kaniko hay nhiều sản phẩm/công cụ khác của Google
    GitLab có một cách rất đơn giản để mirror từ GitLab sang GitHub hoặc nhà cung cấp/máy chủ Git khác

    • Tôi cho rằng khả năng Copybara bị ngừng là thực sự rất thấp. Theo tôi biết thì nó là một công cụ cốt lõi trong cách google3 bảo trì và vendor các dự án mã nguồn mở quy mô lớn
    • Đúng vậy, Copybara gần giống một công cụ để thực hiện biến đổi theo một hoặc cả hai chiều hơn
      Ví dụ như chuyển bzl bên ngoài sang dạng tương thích với Blaze BUILD nội bộ, hoặc chuyển đổi giữa import bên ngoài và import kiểu third_party nội bộ
      Nếu chỉ mirror thuần túy thì Copybara là quá nặng
  • Hay đấy. Khoảng 5 năm trước tôi cũng đã tự làm thứ gì đó tương tự bằng các kho Git lồng nhau và script để đạt mục đích quản lý đồng thời kho riêng tư và công khai
    Shell script của tôi tất nhiên không ở quy mô Google

    • Tôi cũng vậy. Ban đầu tôi tưởng nó chỉ là một wrapper cho git subtree, nhưng hóa ra nó làm được nhiều việc hơn hẳn
      Chẳng hạn như nó còn có tính năng đổi email tác giả commit trong lúc đồng bộ nữa