กลับไปที่บล็อก

Git sync fork กับ upstream: 3 วิธีที่ปลอดภัย

6 กันยายน 2569

TL;DR: รัน git fetch upstream && git merge upstream/main && git push origin main แล้ว fork ของคุณตามทัน นั่นคือเวิร์กโฟลว์ “git sync fork กับ upstream” ทั้งหมดในหนึ่งบรรทัด — ดึงการเปลี่ยนแปลงจากโปรเจกต์ที่คุณ fork มา แล้วพุชเข้าสำเนาของตัวเอง ถ้าชอบประวัติเป็นเส้นตรง ให้เปลี่ยน merge เป็น git rebase upstream/main แล้ว force-push และถ้าคุณยังไม่เคยต่อ remote ชื่อ upstream เลย ให้เริ่มที่ขั้นตอน 1 ด้านล่าง เพราะ remote ที่หายไปนี่คือสาเหตุอันดับหนึ่งของอาการ “fork ซิงก์ไม่ได้” ที่เหลือทั้งหมด — rebase ปุ่มซิงก์ของ GitHub และ branch ที่แยกกันจนพุชไม่ได้ — เป็นแค่รายละเอียดทับบนสามคำสั่งนี้

ซิงก์ fork กับ upstream หมายถึงอะไร?

fork คือสำเนาของ repository คนอื่นบน GitHub ของคุณ ต้นฉบับคือ upstream สำเนาของคุณคือ origin fork บน GitHub ไม่อัปเดตตัวเอง — เมื่อผู้ดูแล merge pull request สำเนาของคุณก็ยังค้างกับโค้ดเมื่อวาน การซิงก์ fork คือการดึง commit ใหม่จาก upstream เข้ามาใน fork เพื่อให้ branch ของคุณตรงกับสถานะปัจจุบันของโปรเจกต์หรืออย่างน้อยก็มีมันด้วย

เรื่องนี้สำคัญสองเหตุผล หนึ่ง คือการมีส่วนร่วม: ทุก pull request ที่เปิดจาก fork ที่ล้าสมัยจะแถบเสียงรบกวนมาด้วย และผู้ดูแลจะให้คุณอัปเดตก่อน merge สอง คือการ self-host หรือการศึกษา: ถ้าคุณรัน fork ใน production หรือแค่อ่านโค้ด fork ที่เก่าหนึ่งเดือนคือการแก้บั๊กหนึ่งเดือนที่คุณไม่มี

ซิงก์ fork กับ upstream จาก command line อย่างไร?

สามขั้นตอน: ประกาศ upstream ครั้งเดียว ดึงจากมัน แล้ว merge กับพุช การต่อสายนี้ถาวร — ครั้งหน้าคุณพิมพ์แค่ขั้น 2 กับ 3

ขั้นตอน 1 — เพิ่ม remote ชื่อ upstream (ครั้งเดียวต่อการ clone)

# ภายในสำเนา local ของ fork
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
git remote -v   # ยืนยัน: origin -> fork ของคุณ, upstream -> ต้นฉบับ

หา URL ที่ถูกต้องจากหน้า repository ต้นฉบับ: ปุ่ม Code สีเขียว ความผิดพลาดที่พบบ่อยคือชี้ remote ทั้งสองไปที่ fork ของตัวเอง — แล้ว “การซิงก์” จะเงียบ ๆ ไม่ทำอะไรเลย เพราะคุณดึงจากสำเนาที่เก่าเท่ากับของคุณพอดี

ขั้นตอน 2 — fetch แล้ว merge branch ของ upstream

git checkout main
git fetch upstream
git merge upstream/main
git push origin main

นี่คือคำตอบมาตรฐานของ “git sync fork กับ upstream ด้วย command line” ผลลัพธ์ปกติคือ fast-forward — main ของ fork คุณไม่มีอะไรใหม่ มันจึงไหลไปเทียบ upstream/main โดยไม่เกิด merge commit

ขั้นตอน 3 — ทำซ้ำตามต้องการ ไม่มีอะไรต้องจำเกิน git fetch upstream && git merge upstream/main && git push origin main ถ้าอยากรู้ว่าตกหล่นมาก่อน merge แค่ไหน ให้รัน git rev-list --count main..upstream/main หลัง fetch

ควร rebase หรือ merge ตอนซิงก์ fork?

ทั้งคู่พาโค้ดชุดเดียวกันเข้า fork ต่างกันที่ประวัติที่ทิ้งไว้ เลือกนโยบายเดียวต่อหนึ่ง repo แล้วยึดมั่น:

วิธีคำสั่งผลต่อประวัติเหมาะกับ
Mergegit merge upstream/mainเกิด merge commit เพิ่มเมื่อ branch แยกกันFeature branch ที่มี PR เปิดอยู่ — ไม่เขียนทับอะไรเลย
Rebasegit rebase upstream/mainCommit ของคุณถูกเล่นซ้ำไว้บนสุด ประวัติเป็นเส้นตรงรักษา main ของ fork ให้สะอาด; fork ที่แยกกันจนอยากรีเซ็ต
หน้า GitHubปุ่ม Sync branch / merge PRเหมือน mergeตามทันอย่างเร็วโดยไม่ต้องเปิด clone

รูปแบบ rebase ของการซิงก์:

git fetch upstream
git rebase upstream/main
git push --force-with-lease origin main

ต้อง force push เพราะ rebase เขียน commit ID ใหม่ — branch ฝั่ง remote ของ fork ไม่ได้สืบเชื้อสายจากของ local อีกต่อไป ให้เลือก --force-with-lease ทุกครั้งแทน --force: มันจะปฏิเสธถ้ามีคน (หรืออีกเครื่องของคุณ) พุชแทรกมาก่อน ซึ่งทำให้คำสั่งอันตรายกลายเป็นปลอดภัยโดยดีฟอลต์

กฎที่สมควรสักไว้ที่ข้อมือ: อย่า rebase branch ที่มี pull request เปิดอยู่ นอกจากคุณรู้ว่ากำลังทำอะไร — rebase เปลี่ยน commit ID และอาจทำให้ PR ที่เปิดอยู่หลุดจาก commit ของมัน ซิงก์ main ด้วย merge (หรือ rebase ก่อนเริ่มงานใหม่) แล้วเก็บ branch ของ PR ไว้นอกเรื่องนี้

ทำไม fork ของผมถึงซิงก์กับ upstream ไม่ได้?

สี่ผู้ต้องสงสัยประจำ เรียงตามลำดับที่เจอในเทอร์มินัลจริง:

  1. ไม่มี remote ชื่อ upstreamgit remote -v โชว์แค่ origin อาการ: git fetch upstream ล้มด้วยข้อความ 'upstream' does not appear to be a git repository วิธีแก้: ขั้นตอน 1 ด้านบน
  2. fetch แล้วแต่ไม่ merge — fetch อัปเดต upstream/main ใน repo local แต่ไม่แตะ branch ทำงานสักตัว อาการ: git log ยังดูเก่าทั้งที่ fetch สำเร็จ วิธีแก้: git merge upstream/main
  3. ประวัติแยกทาง — คุณ commit ลง main ของ fork และ upstream ก็เดินไปข้างหน้าเหมือนกัน git pull จะบ่นเรื่องประวัติไม่เกี่ยวข้องหรือบังคับ merge วิธีแก้ ถ้าคุณอยากให้ upstream ชนะ: git reset --hard upstream/main (ทิ้ง commit ที่มีเฉพาะใน main ของคุณ — เช็ก git stash list หรือสำรองเป็น branch ก่อน; ถ้า reset พลาดไปแล้ว ทางกู้คืนเหมือนกับใน git undo last commit: git reflog ยังจำยอดเก่าได้อยู่)
  4. push ถูกปฏิเสธเพราะไม่ใช่ fast-forward หลัง rebase — คุณ rebase แล้วพุชแบบปกติ วิธีแก้: git push --force-with-lease origin main

กรณีที่ห้าที่พบน้อย: repo ต้นทางถูกเปลี่ยนชื่อหรือลบไป ทำให้ URL จากขั้น 1 ตอบ 404 GitHub จะ redirect repo ที่เปลี่ยนชื่อ ความล้มเหลวถาวรมักแปลว่าถูกลบหรือปิดเป็น private — ไม่มีอะไรให้ซิงก์แล้ว

ซิงก์ fork จากเว็บ GitHub ได้ไหม?

ได้ ในหน้า fork ของคุณ รายการ branch จะมีปุ่ม Sync fork ทุกครั้งที่ branch ของคุณตกหล่น; กดหนึ่งที upstream ก็ไหลเข้ามา ด้านล่างของหน้า วิธีเดียวกันทำได้ผ่าน pull request: เปิด PR จาก upstream/main เข้า main ของ fork แล้ว merge

ข้อจำกัดของปุ่มอธิบายว่าเมื่อไรควรกลับไปใช้ CLI: มันทำได้แค่ fast-forward หรือ merge — rebase ไม่ได้ และปฏิเสธเด็ดขาดเมื่อ branch แยกกัน โดยบอกให้ทิ้ง commit หรือใช้ command line และมันซิงก์เฉพาะ branch ดีฟอลต์เท่านั้น ทุกอย่างที่เกินการตามทันง่าย ๆ สามคำสั่งด้านบนคือเครื่องมือ

ควรซิงก์ fork บ่อยแค่ไหน?

ก่อนเริ่มงานใหม่ทุกชิ้น คือคำตอบที่ซื่อสัตย์: แตก branch จาก main ที่สด แล้ว PR ที่คุณเปิดจะไม่เริ่มด้วยประโยค “อันนี้ทำจากเวอร์ชันสามสัปดาห์ก่อน” สำหรับ fork ที่คุณมีส่วนร่วมจริง การซิงก์ main รายวันหรือรายเซสชันใช้เวลาไม่กี่วินาที สำหรับ fork ที่แค่อ่านหรือ deploy ให้ซิงก์เมื่อ upstream ปล่อยของที่คุณอยากได้ — กดติดตาม release ของ repo ต้นฉบับแล้วซิงก์ตอนมีรุ่นใหม่ การซิงก์ถูกเพราะมันเป็นกิจวัตร; fork ที่ตกหล่นหกเดือนมักต้องผ่าตัด ไม่ใช่ merge นั่นแหละที่ทำให้ “ซิงก์ fork ให้หน่อย” กลายเป็นทั้งบ่าย

แผ่นสรุปคำสั่ง

# เซ็ตอัปครั้งเดียว
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git

# ซิงก์ประจำ (นโยบาย merge)
git fetch upstream && git merge upstream/main && git push origin main

# ซิงก์ประจำ (นโยบาย rebase, ประวัติเป็นเส้นตรง)
git fetch upstream && git rebase upstream/main && git push --force-with-lease origin main

# ผมตกหล่นมาก่อนแค่ไหน?
git fetch upstream && git rev-list --count main..upstream/main

# แยกกันจนแก้ไม่ได้ — ทำให้ main เหมือน upstream เป๊ะ (ทำลายข้อมูล)
git fetch upstream && git reset --hard upstream/main && git push --force-with-lease origin main

จำคำสั่งสองบรรทัดประจำวันไว้ในความจำกล้ามเนื้อ แล้ว fork ที่แยกทางจะเป็นเรื่องเล่าที่คุณได้อ่าน ไม่ใช่ปัญหาที่คุณต้องแก้ ถ้างานบ้าน Git ของคุณลุกลามไปถึงเซิร์ฟเวอร์ สรุปคำสั่ง journalctl ดูแลอีกครึ่งของการเก็บประวัติเครื่องให้อ่านรู้เรื่อง

— mrsaynothing

— mrsaynothing

บันทึกหน้างานเรื่อง AI, Linux และ self-hosted

คุยต่อโพสต์นี้บน dev.to dev.to ↗

รับวิธีแก้ฉบับถัดไปทางอีเมล

อีเมลหนึ่งฉบับต่อหนึ่งโพสต์ แก้เสร็จแล้วไปต่อ

self-hosted · ไม่มีบุคคลที่สาม · ยกเลิกได้ในคลิกเดียว

นี่คืออะไร?

ss vs netstat: คำสั่งดูพอร์ตบน Linux ควรใช้ตัวไหน

ถ้าอ่านแล้วชอบ — ผมสร้างงานแบบนี้เป็นอาชีพ จ้างผม