Google Copybara: การย้ายโค้ดระหว่าง repository
(github.com/google)- 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
- origin ใช้
- ตัวอย่างการรันคือสร้าง 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: เปลี่ยนคำสั่งที่รัน ค่าเริ่มต้นคือmigrateCOPYBARA_CONFIG=copy.bara.sky: ระบุ path ของไฟล์ config ค่าเริ่มต้นคือcopy.bara.skyที่ rootCOPYBARA_WORKFLOW=default: ระบุ workflow ที่จะรัน ค่าเริ่มต้นคือdefaultCOPYBARA_SOURCEREF='': ระบุ sourceref ไม่มีค่าเริ่มต้นCOPYBARA_OPTIONS='': ระบุ option ของ Copybara ไม่มีค่าเริ่มต้น
- สามารถแชร์การตั้งค่า Git และ SSH credential ให้ Docker container ได้
- ตัวอย่างคือ mount
~/.gitconfig,~/.ssh,SSH_AUTH_SOCKเข้า container
- ตัวอย่างคือ mount
เอกสารและการติดต่อสอบถาม
- เอกสารยังอยู่ระหว่างดำเนินการ
- แหล่งข้อมูลที่มีให้มีดังนี้
- ส่งคำถามได้ที่ mailing list
- หากต้องการดูข้อผิดพลาดของ Bazel test โดยไม่ต้อง
catไฟล์ log สามารถเพิ่มtest --test_output=streamedใน~/.bazelrcได้
1 ความคิดเห็น
ความเห็นจาก 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
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/ คือสิ่งที่ใกล้เคียงที่สุด แต่ก็ยังขาดอีกหลายอย่าง
โปรเจ็กต์โอเพนซอร์สอย่าง 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
มีเครื่องมืออื่นในสายนี้อีกไหม?
หลังจากนั้นก็ถูกรวมเข้าไปใน Git ตัวหลัก
https://manpages.debian.org/testing/git-man/git-subtree.1.en...
https://docs.github.com/en/get-started/using-git/about-git-s...
แบบนี้จะสะดวกไหมในกรณีที่หลายรีโพอยากแชร์โค้ดกันนิดหน่อย แต่ยังไม่คุ้มจะต้องแยกเป็นไลบรารี ใส่ reference ออก version release แล้วคอยอัปเดตรีโพที่พึ่งพาอยู่?
เช่น อยากใช้แบบซิงก์โฟลเดอร์ที่มี common domain model จากรีโพหลักไปยังรีโพอื่น ๆ ตรง ๆ ได้หรือเปล่า
เป็นการใช้งานที่ใกล้กับแนวคิดแบบ Go ว่า “มี dependency มาก ๆ สู้ก็อปปี้ไว้หน่อยยังดีกว่า”
บางโปรเจ็กต์พัฒนาอยู่ใน monorepo แล้วใช้ Copybara ส่งออกไปภายนอก
ทีมของเรายังใช้มันภายในสำหรับจัดการเวอร์ชันของชุดกฎ Starlark ด้วย
ถ้าทำให้รีโพสาธารณะเป็น dependency ของรีโพ private ภายในบริษัท มันจะปวดหัวพอสมควรในแง่การพัฒนา และถ้า dependency แบบนี้แตกกิ่งเป็นต้นไม้ขึ้นมาเมื่อไร ยิ่งปวดหัวหนัก
ใช้มาค่อนข้างนานแล้ว ส่วนใหญ่จะใช้ตอนที่เครื่องมือที่สร้างอยู่ภายในโปรเจกต์ใหญ่โตพอจะปล่อยแยกเป็นอิสระได้
มันทรงพลังพอจะทำ การปล่อยแบบสองทาง ทั้งกระบวนการได้ ตั้งแต่ส่งโค้ดออกไปแล้วดึงกลับมาอีกครั้ง แต่แบบนั้นยุ่งยากเกินไปเลยขอผ่าน
โดยมากฉันใช้มันสำหรับการส่งออกแบบครั้งเดียวที่เรียบง่าย คือแยกโฟลเดอร์หนึ่งออกจากรีโพเดิมโดยยังคงประวัติไว้ แล้วหลังจากนั้นก็ย้ายการพัฒนาต่อไปที่รีโพใหม่
ถึงโครงสร้างโปรเจกต์ใหม่จะแตกต่างไปทั้งหมด
Git blameก็ยังทำงานได้ เลยถือว่าน่าพอใจแบบสองทางจะเริ่มเละ เพราะการแปลงอย่างการรีแมปพาธ การตัดไฟล์ออก หรือการลบเฮดเดอร์ ทำได้ง่ายในทิศทางเดียว แต่ไม่ได้ย้อนกลับได้อย่างสะอาดเสมอไป
ถ้าทั้งสองฝั่งเริ่มแยกทางกัน 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 อื่น
ตัวอย่างเช่น แปลง
bzlภายนอกให้เข้ากับ BlazeBUILDภายใน หรือแปลงระหว่าง external import กับ import แบบthird_partyภายในถ้าเป็นการมิเรอร์ล้วน ๆ Copybara ถือว่าหนักเกินไป
ดีเลย ผมเองก็เคยทำอะไรคล้ายกันเมื่อราว 5 ปีก่อนด้วย nested Git repositories และสคริปต์ เพื่อให้จัดการทั้งรีโพ private และ public ไปพร้อมกันได้
แน่นอนว่าสคริปต์เชลล์ของผมไม่ได้อยู่ในระดับ สเกลของ Google
git subtreeแต่ดูแล้วมันทำอะไรได้มากกว่านั้นเยอะเช่น มีความสามารถในการเปลี่ยน อีเมลผู้เขียนคอมมิต ระหว่างการซิงก์ด้วย