1 คะแนน โดย GN⁺ 4 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Copybara เป็นเครื่องมือที่ใช้ภายใน Google สำหรับแปลงและย้ายซอร์สโค้ดระหว่าง repository หลายแห่ง โดยใช้ในกรณีอย่างการซิงก์ repository แบบ confidential กับ repository แบบ public
  • เลือก repository หนึ่งเป็น repository ที่เป็นแหล่งอ้างอิงหลัก เพื่อรักษาแหล่งความจริงเดียวไว้ แต่สามารถรับ contribution จาก repository ใดก็ได้ และสร้าง release จาก repository ใดก็ได้เช่นกัน
  • กรณีใช้งานหลักคือการย้ายโค้ดซ้ำ ๆ โดยรองรับ flow เช่น นำโค้ดบางส่วนจาก confidential repository ไปยัง public repository หรือนำการเปลี่ยนแปลงจาก public repository กลับมายัง authoritative repository
  • Copybara เป็นแบบ stateless โดยไม่ได้เก็บสถานะไว้ใน server แยกต่างหาก แต่เก็บไว้ใน label ของ commit message ใน repository ปลายทาง ทำให้ผู้ใช้หรือ service หลายรายที่ใช้การตั้งค่าและ repository เดียวกันได้ผลลัพธ์เหมือนกัน
  • ประเภท repository ที่รองรับในปัจจุบันคือ Git ส่วนการอ่าน Mercurial เป็นฟีเจอร์เชิงทดลอง และด้วยโครงสร้างที่ขยายได้จึงสามารถเพิ่ม origin และ destination แบบกำหนดเองได้

ปัญหาที่ Copybara แก้ไข

  • Copybara เป็นเครื่องมือสำหรับย้ายและแปลงซอร์สโค้ดระหว่าง repository
  • มีบางกรณีที่ซอร์สโค้ดต้องอยู่ในหลาย repository และ Copybara ช่วยให้แปลงและย้ายโค้ดระหว่าง repository เหล่านี้ได้
  • ตัวอย่างสำคัญคือโปรเจกต์ที่ดูแล confidential repository และ public repository ให้ซิงก์กัน
  • วิธีใช้งานที่พบบ่อยที่สุดคือย้ายโค้ดจาก repository หนึ่งไปยังอีก repository หนึ่งแบบซ้ำ ๆ
  • สามารถใช้สำหรับย้ายโค้ดไปยัง repository ใหม่เพียงครั้งเดียวได้ด้วย

Repository หลักและ flow ของ contribution

  • Copybara ต้องเลือก repository หนึ่งจากทั้งหมดเป็น authoritative repository
    • เป็นเงื่อนไขเพื่อให้มี source of truth เพียงหนึ่งเดียวเสมอ
  • สามารถมี contribution ได้จาก repository ใดก็ได้
  • สามารถสร้าง release จาก repository ใดก็ได้เช่นกัน
  • หากเกิดการเปลี่ยนแปลงใน repository ที่ไม่ใช่แหล่งอ้างอิงหลัก Copybara สามารถแปลงการเปลี่ยนแปลงนั้นและย้ายไปยังตำแหน่งที่เหมาะสมใน repository หลักได้
    • ตัวอย่างคือการเปลี่ยนแปลงที่สร้างโดย contributor ใน public repository
    • merge conflict จะจัดการเหมือนกับการจัดการการเปลี่ยนแปลงเก่าใน repository หลัก

ตัวอย่างการใช้งาน

  • ตัวอย่างการใช้งาน Copybara มีดังนี้
    • นำโค้ดบางส่วนจาก confidential repository ไปยัง public repository
    • นำโค้ดจาก public repository ไปยัง confidential repository
    • นำการเปลี่ยนแปลงจาก non-authoritative repository ไปยัง authoritative repository
  • ตัวอย่างการตั้งค่ากำหนด origin และ destination ด้วย core.workflow
    • origin ใช้ git.github_origin โดยใช้ master ของ https://github.com/google/copybara.git
    • destination ใช้ git.destination โดยใช้ file:///tmp/foo
    • destination_files กำหนดเป้าหมายเป็น third_party/copybara/** และยกเว้น README_INTERNAL.txt
    • ใช้ core.replace และ core.move เพื่อแทนที่ path ของไฟล์ BUILD และย้าย directory
  • ตัวอย่างการรันคือสร้าง bare Git repository แล้วรัน copybara copy.bara.sky

วิธีเก็บสถานะและการรองรับ repository

  • หนึ่งในจุดเด่นของ Copybara คือโครงสร้างแบบ stateless
  • กล่าวให้แม่นยำกว่านั้นคือเก็บสถานะไว้ใน repository ปลายทาง
    • ตำแหน่งที่เก็บคือ label ใน commit message
  • วิธีนี้ทำให้ผู้ใช้หรือ service หลายรายที่ใช้ชุดการตั้งค่าและ repository เดียวกันได้ผลลัพธ์เหมือนกัน
  • ประเภท repository ที่รองรับในปัจจุบันคือ Git
  • ฟีเจอร์อ่านจาก Mercurial repository ใช้งานได้ แต่ยังเป็นแบบ ทดลอง
  • ด้วย architecture ที่ขยายได้ สามารถเพิ่ม origin และ destination แบบ bespoke ให้เหมาะกับแทบทุกกรณีใช้งานได้
  • การรองรับ repository ประเภทอื่นอย่างเป็นทางการจะเพิ่มในอนาคต

การติดตั้งและ build

  • วิธีเริ่มต้นที่ง่ายที่สุดคือใช้ snapshot release รายสัปดาห์ที่มี binary ที่ build ไว้ล่วงหน้า
    • release ถูกสร้างโดยอัตโนมัติ
    • ไม่มีการรับประกันเรื่องการทดสอบด้วยมือ ความเข้ากันได้ของ version หรือความถูกต้อง
    • เลือก release ได้ที่ https://github.com/google/copybara/releases
  • หากต้องการใช้ version ที่ยังไม่ release ต้อง build จาก HEAD
    • ต้องติดตั้ง JDK 11
    • ต้องติดตั้ง Bazel
    • clone source ด้วย git clone https://github.com/google/copybara.git
    • build ด้วย bazel build //java/com/google/copybara
    • uberjar ที่รันได้สร้างด้วย bazel build //java/com/google/copybara:copybara_deploy.jar
    • รันทดสอบได้ด้วย bazel test //...
  • บาง test ต้องติดตั้งเครื่องมือพื้นฐาน เช่น Mercurial, Quilt
    • หาก Pull Request ไม่เกี่ยวข้องกับ module นั้น สามารถข้าม test เหล่านั้นได้
    • CI จะรัน test ทั้งหมด
  • บน Arch Linux สามารถใช้ package aur/copybara-git ได้

ใช้ Copybara ที่ build ไว้ล่วงหน้าใน Bazel

  • สามารถใช้ snapshot release รายสัปดาห์ใน Bazel ได้
  • Copybara ถูกจัดเตรียมเป็น class file version 65.0 ดังนั้นต้องรันบน Java Runtime 21 ขึ้นไป
    • ต้องเพิ่ม run --java_runtime_version=remotejdk_21 ใน .bazelrc
  • ดาวน์โหลด release artifact ด้วย http_jar
    • ใน 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

Build source เป็น external Bazel repository

  • มี macro อำนวยความสะดวกสำหรับ dependency ของ Copybara
  • เพิ่ม http_archive ใน WORKSPACE และเติมค่า {{ sha256sum }} กับ {{ commit }}
  • จากนั้นโหลดและเรียก macro ต่อไปนี้
    • copybara_repositories()
    • copybara_maven_repositories()
    • copybara_go_repositories()
  • ภายใน workspace สามารถ build และรันด้วย bazel run @com_github_google_copybara//java/com/google/copybara -- <args...>

การใช้ Docker

  • วิธี build และรัน Copybara ด้วย Docker ยังเป็นแบบ ทดลอง ในปัจจุบัน
  • build ด้วย docker build --rm -t copybara .
  • รันจาก root ของโค้ดปลายทางในรูปแบบ docker run -it -v "$(pwd)":/usr/src/app copybara help
  • สามารถใช้ environment variable แทน argument ตอนรัน container ได้
    • COPYBARA_SUBCOMMAND=migrate: เปลี่ยนคำสั่งที่รัน ค่าเริ่มต้นคือ migrate
    • COPYBARA_CONFIG=copy.bara.sky: ระบุ path ของไฟล์ config ค่าเริ่มต้นคือ copy.bara.sky ที่ root
    • COPYBARA_WORKFLOW=default: ระบุ workflow ที่จะรัน ค่าเริ่มต้นคือ default
    • COPYBARA_SOURCEREF='': ระบุ sourceref ไม่มีค่าเริ่มต้น
    • COPYBARA_OPTIONS='': ระบุ option ของ Copybara ไม่มีค่าเริ่มต้น
  • สามารถแชร์การตั้งค่า Git และ SSH credential ให้ Docker container ได้
    • ตัวอย่างคือ mount ~/.gitconfig, ~/.ssh, SSH_AUTH_SOCK เข้า container

เอกสารและการติดต่อสอบถาม

  • เอกสารยังอยู่ระหว่างดำเนินการ
  • แหล่งข้อมูลที่มีให้มีดังนี้
  • ส่งคำถามได้ที่ mailing list
  • หากต้องการดูข้อผิดพลาดของ Bazel test โดยไม่ต้อง cat ไฟล์ log สามารถเพิ่ม test --test_output=streamed ใน ~/.bazelrc ได้

1 ความคิดเห็น

 
GN⁺ 4 시간 전
ความเห็นจาก Hacker News
  • โพสต์นี้ขึ้นมาพอดีหลังจากที่ฉันเพิ่งเปิดซอร์ส แพตช์รองรับ Perforce ที่ทำไว้เพื่อใช้ในสตูดิโอพัฒนาเกมของตัวเอง เลยรู้สึกน่าสนุกดี
    เมื่อคิดว่าการใช้งานหลักของ Copybara คือการกระจายโค้ดภายใน Google และโค้ดนั้นอยู่ใน Piper ซึ่งเกี่ยวข้องกับ Perforce ก็ถือว่าค่อนข้างน่าแปลกที่มันไม่มีการรองรับ Perforce และมีเพียงการรองรับ Git ที่มีความหมายจริงจัง
    ก่อนจะทำ PR ฉันไปดูประวัติ Git แล้วเห็นการแสดงผล Gerrit Change-ID เยอะมาก เลยกังวลว่าอาจมีระบบรีวิวโค้ด Gerrit ที่ไหนสักแห่งที่ฉันเข้าไม่ถึง และ PR ของฉันอาจไม่ถูกอัปสตรีม
    น่าเสียดายเหมือนกันที่ไม่มี Gerrit/Rietveld สำหรับ Perforce แต่ก็จะหวังทุกอย่างพร้อมกันคงไม่ได้
    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 ไม่เจอเลย และก็แปลกใจที่เครื่องมือรีวิว PR ที่ค่อนข้างอ่อนของ GitHub กลับเป็นที่ยอมรับของคนส่วนใหญ่ ถ้าใครรู้จักเครื่องมือที่ใกล้เคียงกันก็อยากฟัง
      ตอนออกจาก Google เมื่อหลายปีก่อน ฉันหามาอย่างละเอียดพอสมควร และ https://codeapprove.com/ คือสิ่งที่ใกล้เคียงที่สุด แต่ก็ยังขาดอีกหลายอย่าง
    • Piper ไม่ใช่ฟอร์กของ Perforce มันแค่ เข้ากันได้กับ API ของ Perforce แต่เป็นคนละ implementation กันโดยสิ้นเชิง
    • รีโพนั้นรับ PR เพียงแต่จะรวมเข้าภายในก่อนแล้วค่อยส่งออกกลับมาภายนอก
      โปรเจ็กต์โอเพนซอร์สอย่าง gVisor หรือ Bazel ที่อยู่ใน internal monorepo ก็มีความต่างกันเล็กน้อย แต่โดยรวมแล้วดำเนินการคล้ายกัน
  • เครื่องมืออีกตัวที่น่าสนใจในพื้นที่นี้คือฝั่ง 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
    มีเครื่องมืออื่นในสายนี้อีกไหม?

  • แบบนี้จะสะดวกไหมในกรณีที่หลายรีโพอยากแชร์โค้ดกันนิดหน่อย แต่ยังไม่คุ้มจะต้องแยกเป็นไลบรารี ใส่ reference ออก version release แล้วคอยอัปเดตรีโพที่พึ่งพาอยู่?
    เช่น อยากใช้แบบซิงก์โฟลเดอร์ที่มี common domain model จากรีโพหลักไปยังรีโพอื่น ๆ ตรง ๆ ได้หรือเปล่า
    เป็นการใช้งานที่ใกล้กับแนวคิดแบบ Go ว่า “มี dependency มาก ๆ สู้ก็อปปี้ไว้หน่อยยังดีกว่า”

    • โดยหลักแล้วใช้เพื่อซิงก์ โปรเจ็กต์โอเพนซอร์สภายนอก เข้ากับ internal monorepo นโยบายกำหนดให้นำซอร์สโค้ดเข้ามามากกว่าผลลัพธ์จากการ build แต่ก็ขอยกเว้นได้
      บางโปรเจ็กต์พัฒนาอยู่ใน monorepo แล้วใช้ Copybara ส่งออกไปภายนอก
      ทีมของเรายังใช้มันภายในสำหรับจัดการเวอร์ชันของชุดกฎ Starlark ด้วย
    • มันเป็นเครื่องมือสำหรับเวลาที่ภายในมี monorepo อยู่ แล้วอยากเปิดบางส่วนของมันออกไปเป็นโอเพนซอร์สให้โลกภายนอก แต่โค้ดก็ยังต้องอยู่ใน monorepo ต่อไป ดังนั้นนี่จึงเป็นทางออก
      ถ้าทำให้รีโพสาธารณะเป็น dependency ของรีโพ private ภายในบริษัท มันจะปวดหัวพอสมควรในแง่การพัฒนา และถ้า dependency แบบนี้แตกกิ่งเป็นต้นไม้ขึ้นมาเมื่อไร ยิ่งปวดหัวหนัก
    • จะใช้ Copybara ทำแบบนั้นก็ได้ แต่ถ้าใช้ในลักษณะนั้นมีโอกาสสูงที่จะทั้งน่าหงุดหงิดและน่าเบื่อ อาจยุ่งยากยิ่งกว่าการแยกไลบรารีหรือย้ายไฟล์ไม่กี่ไฟล์ไปไว้ในรีโพแยกเสียอีก
  • ใช้มาค่อนข้างนานแล้ว ส่วนใหญ่จะใช้ตอนที่เครื่องมือที่สร้างอยู่ภายในโปรเจกต์ใหญ่โตพอจะปล่อยแยกเป็นอิสระได้
    มันทรงพลังพอจะทำ การปล่อยแบบสองทาง ทั้งกระบวนการได้ ตั้งแต่ส่งโค้ดออกไปแล้วดึงกลับมาอีกครั้ง แต่แบบนั้นยุ่งยากเกินไปเลยขอผ่าน
    โดยมากฉันใช้มันสำหรับการส่งออกแบบครั้งเดียวที่เรียบง่าย คือแยกโฟลเดอร์หนึ่งออกจากรีโพเดิมโดยยังคงประวัติไว้ แล้วหลังจากนั้นก็ย้ายการพัฒนาต่อไปที่รีโพใหม่
    ถึงโครงสร้างโปรเจกต์ใหม่จะแตกต่างไปทั้งหมด Git blame ก็ยังทำงานได้ เลยถือว่าน่าพอใจ

    • แพตเทิร์นทางเดียว แบบนั้นนี่แหละที่ใน Google ก็ใช้กันจริง ซิงก์ออกจากโมโนรีโพไปยัง GitHub
      แบบสองทางจะเริ่มเละ เพราะการแปลงอย่างการรีแมปพาธ การตัดไฟล์ออก หรือการลบเฮดเดอร์ ทำได้ง่ายในทิศทางเดียว แต่ไม่ได้ย้อนกลับได้อย่างสะอาดเสมอไป
      ถ้าทั้งสองฝั่งเริ่มแยกทางกัน Copybara จะเริ่มติดตาม baseline ได้สับสน เพราะคอมมิตที่มีความหมายเหมือนกัน พอผ่านการแปลงแล้วก็จะได้ SHA คนละตัว
      สิ่งที่ควรรู้คือการ “เก็บ” ประวัติไว้ ไม่ใช่การย้ายมาทั้งดุ้นจริง ๆ แต่เป็นการ cherry-pick คอมมิตที่ถูกเขียนใหม่ขึ้นมา เนื้อหาไฟล์กับข้อมูลผู้เขียนถูกย้ายมาด้วย ดังนั้น Git blame จึงยังใช้ได้ แต่ SHA จะถูกสร้างใหม่
      Copybara จะเก็บ SHA ต้นฉบับไว้ใน commit message trailer GitOrigin-RevId จึงมีประโยชน์เมื่อภายหลังต้องเทียบคอมมิตข้ามรีโพ
  • ความก้าวหน้ากว่า 52 ปีเลยนะ :-)
    กรกฎาคม 2026: Google copybara ช่วยให้ย้ายโค้ดระหว่างรีโพโปรดักชันสองตัวได้
    มีนาคม 1974: IBM COPY ช่วยให้ย้ายโค้ดระหว่าง production partition data set สองชุดได้ 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 เพื่อจัดโมเดลแบบ hub-and-spoke ให้รีโพสาธารณะสามารถอยู่ภายในโมโนรีโพภายในที่ใหญ่กว่าได้ มันใช้งานได้ แต่ต้องมีการอ้อมค่อนข้างเยอะ
    https://dagster.io/blog/monorepos-the-hub-and-spoke-model-an...

  • ถ้าต้องการแค่ซิงก์รีโพโดยไม่มีการ exclude หรือแปลงอะไร ผมคงไม่ใช้มัน แม้ตอนนี้อาจจะเหมาะ แต่ถ้ามันถูกเก็บเข้ากรุหรือยุติไปแบบ kaniko หรือผลิตภัณฑ์/เครื่องมือ Google อีกหลายตัว ก็น่าจะลำบาก
    ใน GitLab มีวิธีที่ง่ายมากสำหรับ มิเรอร์ จาก GitLab ไปยัง GitHub หรือผู้ให้บริการ/เซิร์ฟเวอร์ Git อื่น

    • ผมมองว่าโอกาสที่ Copybara จะถูกยุติมีน้อยมาก เท่าที่รู้มันเป็น เครื่องมือแกนหลัก พอสมควรในวิธีที่ google3 ใช้ดูแลและ vendor โปรเจกต์โอเพนซอร์สขนาดใหญ่
    • ใช่ Copybara ดูจะเป็นเครื่องมือสำหรับทำ การแปลง ในทิศทางเดียวหรือทั้งสองทิศทางมากกว่า
      ตัวอย่างเช่น แปลง bzl ภายนอกให้เข้ากับ Blaze BUILD ภายใน หรือแปลงระหว่าง external import กับ import แบบ third_party ภายใน
      ถ้าเป็นการมิเรอร์ล้วน ๆ Copybara ถือว่าหนักเกินไป
  • ดีเลย ผมเองก็เคยทำอะไรคล้ายกันเมื่อราว 5 ปีก่อนด้วย nested Git repositories และสคริปต์ เพื่อให้จัดการทั้งรีโพ private และ public ไปพร้อมกันได้
    แน่นอนว่าสคริปต์เชลล์ของผมไม่ได้อยู่ในระดับ สเกลของ Google

    • ผมก็คล้ายกัน ตอนแรกนึกว่ามันคงเป็นแค่ตัวห่อ git subtree แต่ดูแล้วมันทำอะไรได้มากกว่านั้นเยอะ
      เช่น มีความสามารถในการเปลี่ยน อีเมลผู้เขียนคอมมิต ระหว่างการซิงก์ด้วย