Merge คือการดำเนินการใน Git ที่รวมการเปลี่ยนแปลงจาก Branch หนึ่งไปยังอีก Branch หนึ่ง สร้าง commit การรวม (merge commit) Git รองรับหลายกลยุทธ์: fast-forward (ประวัติเชิงเส้น), three-way merge (สร้าง merge commit) และ squash merge (บีบอัด commit ทั้งหมดเป็นหนึ่งเดียว) ตามข้อมูลจาก git-scm.com, 2025 merge ยังคงเป็นกลไกการรวมโค้ดที่ใช้มากที่สุดในการพัฒนา Git แบบทีม
ประเด็นสำคัญ
Merge (การรวม) เป็นการดำเนินการพื้นฐานใน Git ที่รวมการเปลี่ยนแปลงจาก Branch หนึ่ง (ต้นทาง) ไปยังอีก Branch หนึ่ง (เป้าหมาย) ผลลัพธ์ของการรวม Branch เป้าหมายจะได้รับ commit ทั้งหมดจาก Branch ต้นทางที่ยังไม่มีอยู่ในนั้น ขึ้นอยู่กับสถานการณ์ Git สามารถดำเนินการ merge ได้สามวิธีที่แตกต่างกัน
คุณค่าหลักของ merge คือการรักษาประวัติ: merge commit บันทึกข้อเท็จจริงของการรวม Branch เก็บรักษาข้อมูลเกี่ยวกับว่าเมื่อใดและ Branch ใดถูกรวมเข้าด้วยกัน สิ่งนี้อำนวยความสะดวกในการตรวจสอบการเปลี่ยนแปลง การค้นหาการถดถอย และการเข้าใจลำดับเวลาการพัฒนา ในโปรเจกต์ขนาดใหญ่ merge commit เป็นวิธีมาตรฐานของการรวมโค้ด
ตาม GitLab Flow merge commit ถูกใช้ใน 73% ของทีมที่ทำงานกับ Git วิธีการทางเลือก (rebase, squash) เป็นที่นิยมของทีมที่เน้นประวัติเชิงเส้น การเลือกกลยุทธ์ขึ้นอยู่กับขนาดทีม ความถี่ของการเผยแพร่ และข้อตกลงที่ยอมรับในโปรเจกต์
Merge จำเป็นเมื่อนักพัฒนาเสร็จสิ้นการทำงานบนฟีเจอร์และต้องการรวมเข้ากับ develop หรือ main สถานการณ์ทั่วไป: นักพัฒนาสร้างฟีเจอร์ Branch จาก develop ทำงานบนนั้นเป็นเวลาหลายวัน และในช่วงเวลานั้นมี commit ใหม่จากสมาชิกทีมคนอื่นปรากฏใน develop ก่อนการรวม ต้องรวมการเปลี่ยนแปลงเข้าด้วยกัน — และใช้ merge สำหรับสิ่งนี้
หากไม่มี merge เป็นไปไม่ได้ที่จะทำงานร่วมกันบน โค้ดเบสเดียว ใน Git ทุกครั้งที่นักพัฒนาสองคนทำการเปลี่ยนแปลงพร้อมกันบนโค้ดเบสเดียว Branch ของพวกเขาจะแยกออกจากกัน Merge เป็นวิธีเดียวที่จะนำการเปลี่ยนแปลงเหล่านี้กลับมารวมกันโดยไม่สูญเสียข้อมูล
Git รองรับ merge สามประเภท แต่ละประเภทออกแบบมาสำหรับสถานการณ์ของตัวเอง การเลือกประเภทการรวมส่งผลต่อประวัติ commit ความสะดวกในการย้อนกลับ และความสามารถในการอ่าน log
Fast-forward เกิดขึ้นเมื่อ Branch เป้าหมายไม่มี commit ใหม่ตั้งแต่การสร้าง Branch ต้นทาง ในกรณีนี้ Git เพียงเลื่อนตัวชี้ Branch เป้าหมายไปข้างหน้า ไปยัง commit ล่าสุดของ Branch ต้นทาง ประวัติยังคงเป็นเชิงเส้นโดยไม่มี merge commit
# Fast-forward merge: develop ไม่เปลี่ยนแปลงตั้งแต่สร้างฟีเจอร์
git checkout develop
git merge feature/new-login
# ผลลัพธ์: ตัวชี้ develop เลื่อนไปยังจุดสิ้นสุดของฟีเจอร์
# ไม่มีการสร้าง merge commit
Fast-forward สะดวกสำหรับ Branch อายุสั้น ที่นักพัฒนาทำงานคนเดียว แต่วิธีนี้มีข้อเสีย: ข้อมูลที่ Branch มีอยู่หายไป — commit ทั้งหมดดูเหมือนว่าทำโดยตรงใน develop
Three-way merge ดำเนินการเมื่อทั้งสอง Branch มี commit ใหม่หลังจากจุดที่แยกออกจากกัน Git สร้าง merge commit แยกต่างหากที่มีพ่อแม่สองคน ซึ่งบันทึกข้อเท็จจริงของการรวม Branch วิธีนี้แนะนำสำหรับฟีเจอร์ Branch ในการพัฒนาแบบทีม
# บังคับ three-way merge ด้วยแฟล็ก --no-ff
git checkout develop
git merge --no-ff feature/new-login
# สร้าง merge commit พร้อมข้อความเริ่มต้น
# สามารถตั้งค่าข้อความของคุณเองผ่าน -m
git merge --no-ff feature/new-login -m "Merge feature/new-login into develop"
แฟล็ก --no-ff รับประกันการสร้าง merge commit แม้ว่า fast-forward จะเป็นไปได้ นี่เป็นแนวปฏิบัติที่ดีที่สุดสำหรับการรักษาข้อมูลการแตก Branch ในโปรเจกต์
Squash merge บีบอัด commit ทั้งหมดของ Branch ต้นทางเป็นหนึ่งเดียวและนำไปใช้กับเป้าหมาย ประวัติฟีเจอร์สูญหาย — commit เดียวที่มีการเปลี่ยนแปลงทั้งหมดเข้ามาใน Branch สิ่งนี้สะดวกเมื่อ commit โดยละเอียดในฟีเจอร์ Branch ไม่เพิ่มคุณค่าให้กับประวัติโดยรวม
# Squash merge: commit ทั้งหมดของฟีเจอร์ถูกบีบอัดเป็นหนึ่งเดียว
git checkout develop
git merge --squash feature/experimental
git commit -m "feat: experimental login flow (squashed)"
Squash เหมาะสำหรับร่าง, Branch ทดลอง และสถานการณ์ที่สำคัญต่อการรักษาประวัติที่สะอาด ข้อเสียคือสูญเสียการเชื่อมต่อกับ commit ดั้งเดิม ทำให้การย้อนกลับการเปลี่ยนแปลงแต่ละรายการยากขึ้น
Ours และ Theirs เป็นสองกลยุทธ์ merge พิเศษใน Git Ours ไม่สนใจการเปลี่ยนแปลงจาก Branch ต้นทางอย่างสมบูรณ์ เก็บเฉพาะสิ่งที่อยู่ในเป้าหมาย Theirs ในทางตรงกันข้าม ยอมรับเวอร์ชันของ Branch ต้นทางในข้อขัดแย้งใด ๆ กลยุทธ์เหล่านี้มีประโยชน์เมื่อรวมโค้ดปริมาณมากเมื่อทราบล่วงหน้าว่าเวอร์ชันใดควรมีชัย
กลไก merge ใน Git ขึ้นอยู่กับการเปรียบเทียบสามจุด: บรรพบุรุษร่วม (merge base), สถานะของ Branch ต้นทาง และสถานะของ Branch เป้าหมาย Git ค้นหา merge base — commit ล่าสุดที่เหมือนกันทั้งสอง Branch — และคำนวณว่ามีการเปลี่ยนแปลงอะไรเกิดขึ้นในแต่ละ Branch หลังจากการแยก
Git ใช้ อัลกอริทึมการรวมสามทาง ที่พิจารณาไม่เพียงแค่สองเวอร์ชันไฟล์ที่เปรียบเทียบ แต่ยังรวมถึงบรรพบุรุษร่วมของพวกมัน ด้วยเหตุนี้ Git จึงสามารถแก้ไขสถานการณ์ที่การเปลี่ยนแปลงใน Branch หนึ่งไม่ส่งผลกระทบต่อพื้นที่ที่ถูกแก้ไขของอีก Branch หนึ่งได้โดยอัตโนมัติ — แม้ว่าทั้งสองไฟล์จะถูกแก้ไขแล้วก็ตาม
พิจารณา สถานการณ์: นักพัฒนาสองคนทำงานบนไฟล์ต่างกันในฟีเจอร์ Branch เดียวกัน คนแรกเปลี่ยน LoginActivity.kt คนที่สองเปลี่ยน ProfileFragment.kt เมื่อพวกเขารวมการเปลี่ยนแปลง Git เห็นว่าการเปลี่ยนแปลงส่งผลต่อไฟล์ต่างกันและดำเนินการ merge โดยอัตโนมัติโดยไม่ต้องมีการแทรกแซงของมนุษย์
หากนักพัฒนาทั้งสองเปลี่ยน LoginActivity.kt แต่ในเมธอดต่างกัน — Git ก็จะจัดการโดยอัตโนมัติเช่นกัน รวมการเปลี่ยนแปลงทีละบรรทัด ข้อขัดแย้งเกิดขึ้นก็ต่อเมื่อทั้งสองเปลี่ยนบรรทัดเดียวกันหรือหากคนหนึ่งลบโค้ดที่อีกคนแก้ไข
ข้อขัดแย้งในการ merge เกิดขึ้นเมื่อ Git ไม่สามารถรวมการเปลี่ยนแปลงโดยอัตโนมัติเพราะทั้งสอง Branch แก้ไขบรรทัดเดียวกันต่างกัน ในกรณีนี้ Git ทำเครื่องหมายพื้นที่ที่ขัดแย้งในไฟล์และรอการแก้ไขด้วยตนเองจากนักพัฒนา
พื้นที่ที่ขัดแย้งถูก ทำเครื่องหมาย ด้วยเครื่องหมายพิเศษ: <<<<<<< HEAD แสดงโค้ดจาก Branch เป้าหมาย, ======= คือตัวแบ่ง, >>>>>>> source-branch แสดงโค้ดจาก Branch ต้นทาง นักพัฒนาต้องเลือกด้วยตนเองว่าจะเก็บเวอร์ชันใดหรือรวมเข้าด้วยกัน
# 1. เรียกใช้ merge และดูข้อขัดแย้ง
git merge feature/new-login
# ผลลัพธ์: CONFLICT (content): Merge conflict in LoginActivity.kt
# 2. ดูรายการไฟล์ที่มีข้อขัดแย้ง
git status
# both modified: src/ui/login/LoginActivity.kt
# 3. แก้ไขข้อขัดแย้ง: แก้ไขไฟล์ ลบเครื่องหมาย
# 4. เพิ่มไฟล์ที่แก้ไขแล้วและเสร็จสิ้น merge
git add src/ui/login/LoginActivity.kt
git merge --continue
# หรือ: git commit (ไม่มี --continue)
มี เครื่องมือ สำหรับแก้ไขข้อขัดแย้ง: git mergetool เปิดตัวรวมภาพ (Meld, Beyond Compare, VS Code) นักพัฒนาหลายคนชอบแก้ไขข้อขัดแย้งใน IDE — IntelliJ IDEA และ Android Studio มีเครื่องมือในตัวพร้อมการเปรียบเทียบสามแผงที่ทำให้กระบวนการนี้ง่ายขึ้นอย่างมาก
คำแนะนำ สำหรับการแก้ไขข้อขัดแย้ง: เข้าใจเสมอว่าแต่ละด้านของข้อขัดแย้งทำอะไร อย่าลบโค้ดของคนอื่นโดยไม่เข้าใจตรรกะของมัน และหากข้อขัดแย้งซับซ้อนเกินไป — ให้ผู้เขียนทั้งสอง Branch ร่วมกันแก้ไข
การเลือกระหว่าง Merge และ Rebase เป็นหนึ่งในการตัดสินใจทางสถาปัตยกรรมที่พบบ่อยที่สุดใน Git ทั้งสองวิธีรวมการเปลี่ยนแปลง แต่ทำต่างกัน: merge รักษาประวัติการแตก Branch, rebase เขียนประวัติใหม่ทำให้เป็นเชิงเส้น
หลายทีมใช้ วิธีแบบผสม: rebase เพื่ออัปเดตฟีเจอร์ Branch ด้วย develop (git rebase develop) จากนั้น merge ด้วยแฟล็ก --no-ff เพื่อบันทึกการรวม สิ่งนี้ให้ประวัติที่สะอาดภายในฟีเจอร์และจุดรวมที่มีข้อมูลในระดับ develop
คำถามที่พบบ่อย
ไม่มี --no-ff Git จะทำ fast-forward merge ถ้าเป็นไปได้ — เพียงเลื่อนตัวชี้ Branch มี --no-ff Git จะสร้าง merge commit เสมอ รักษาข้อมูลการแตก Branch แนะนำสำหรับฟีเจอร์ Branch ในการพัฒนาแบบทีม
ใช้ git mergetool หรือเครื่องมือในตัวของ IDE หากข้อขัดแย้งเกี่ยวข้องกับไฟล์หลายสิบไฟล์ — Branch อาจแยกออกจากกันมากเกินไป ในกรณีนี้ ให้หารือแผนการรวมกับทีม อาจแบ่งเป็นหลายขั้นตอน
ได้: git merge --abort ยกเลิก merge หากยังไม่เสร็จสมบูรณ์ (ข้อขัดแย้ง) หาก merge เสร็จสมบูรณ์แล้ว — ใช้ git reset --hard HEAD~1 หรือ git revert -m 1 <merge-commit> เพื่อการย้อนกลับที่ปลอดภัย
แนะนำ สำหรับการทำงานเป็นทีม merge commit บันทึกข้อเท็จจริงการรวม มีการอ้างอิงถึงทั้งสอง Branch และทำให้เข้าใจประวัติง่ายขึ้น สำหรับ Branch ส่วนตัวหรือทดลอง squash merge หรือ fast-forward สามารถยอมรับได้
Git ไม่สามารถ รวมไฟล์ไบนารีโดยอัตโนมัติ — มันเลือกเวอร์ชันใดเวอร์ชันหนึ่งทั้งหมด สำหรับไฟล์ไบนารี (รูปภาพ, .aab, .apk) แนะนำให้ลดการเปลี่ยนแปลงแบบขนานและใช้ Git LFS สำหรับไฟล์ขนาดใหญ่
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม