การรวมหรือผสาน — คือการกระทำในการรวมสองสาขาใน Git โดยนำการเปลี่ยนแปลงจากสาขาหนึ่งไปยังอีกสาขาหนึ่ง ในการพัฒนาสมัยใหม่ การรวมเป็นวิธีมาตรฐานในการรวมสาขาคุณสมบัติเข้ากับสาขาหลักของโครงการ ตามข้อมูล GitHub Octoverse 2024 มีการรวมมากกว่า 15 ล้านครั้งต่อวัน Merge เป็นกลไกสำคัญของการทำงานร่วมกันที่ช่วยให้รวมความพยายามของนักพัฒนาหลายคนเป็นผลิตภัณฑ์เดียว
ประเด็นสำคัญ
Merge ใน Git คือการดำเนินการรวมประวัติการพัฒนาสองรายการขึ้นไปเป็นหนึ่งเดียว เมื่อนักพัฒนารวมสาขา Git จะค้นหาบรรพบุรุษร่วม (base commit) โดยอัตโนมัติและสร้างคอมมิตการรวมใหม่ที่มีการเปลี่ยนแปลงจากทั้งสองสาขา Three-way merge คืออัลกอริทึมมาตรฐานที่เปรียบเทียบสามสถานะ: บรรพบุรุษร่วม สาขาแรก และสาขาที่สอง
กระบวนการรวมเริ่มต้นด้วยคำสั่ง git merge Git จะกำหนดจุดที่สาขาแยกออกจากกันและใช้การเปลี่ยนแปลงตามลำดับจากสาขาต้นทางไปยังสาขาปลายทาง หากการเปลี่ยนแปลงไม่ขัดแย้ง Git จะดำเนินการ fast-forward หรือสร้าง merge commit ขึ้นอยู่กับการตั้งค่า Fast-forward เป็นสถานการณ์ที่สาขาปลายทางเพียงแค่ย้ายไปยังคอมมิตของสาขาต้นทาง
# สลับไปยังสาขาปลายทางและรวม
git checkout main
git merge feature/payment-module
# รวมกับ no-fast-forward อย่างชัดเจน
git merge --no-ff feature/payment-module
# ยกเลิกการรวมหากข้อขัดแย้งซับซ้อนเกินไป
git merge --abort
แฟล็ก --no-ff (no fast-forward) บังคับให้สร้าง merge commit แม้ว่า fast-forward จะเป็นไปได้ สิ่งนี้เก็บรักษาข้อมูลว่าการเปลี่ยนแปลงถูกทำในสาขาที่แยกต่างหาก หลายทีมชอบวิธีนี้เพื่อรักษาประวัติการแตกสาขาอย่างชัดเจน
Git มีกลยุทธ์หลักสามประการในการรวมสาขา ซึ่งแต่ละอย่างเหมาะสำหรับสถานการณ์เฉพาะ การเลือกกลยุทธ์ขึ้นอยู่กับวัฒนธรรมของทีมและข้อกำหนดด้านความสะอาดของประวัติโครงการ
| กลยุทธ์ | ผลลัพธ์ | เมื่อใดควรใช้ |
|---|---|---|
| Standard merge | merge commit + ประวัติทั้งหมด | ทีมที่ให้ความสำคัญกับประวัติที่สมบูรณ์ |
| Squash merge | หนึ่งคอมมิต ประวัติถูกบีบอัด | สาขาคุณสมบัติที่มีคอมมิตเล็กจำนวนมาก |
| Rebase merge | ประวัติเชิงเส้น ไม่มี merge commit | สาขาคุณสมบัติส่วนตัว ก่อนสร้าง PR |
Standard merge สร้าง merge commit ที่มีพ่อแม่สองคน ประวัติทั้งหมดถูกเก็บรักษาไว้ แต่กราฟการแตกสาขาจะซับซ้อนมากขึ้น Squash merge รวมคอมมิตทั้งหมดของสาขาคุณสมบัติเป็นหนึ่งเดียวและใช้บนสาขาปลายทาง — ประวัติกลายเป็นเชิงเส้นและสะอาด แต่ข้อมูลเกี่ยวกับขั้นตอนกลางจะสูญหาย
Rebase แม้จะไม่ใช่การรวมที่สมบูรณ์ แต่ให้ผลลัพธ์เดียวกัน — การเปลี่ยนแปลงจากสาขาหนึ่งถูกย้ายไปไว้อีกสาขาหนึ่ง ความแตกต่างคือประวัติถูกเขียนใหม่: คอมมิตของสาขาคุณสมบัติถูกสร้างขึ้นใหม่บนคอมมิตล่าสุดของสาขาปลายทาง สิ่งนี้ให้ประวัติที่เป็นเชิงเส้นอย่างสมบูรณ์ แต่ต้องใช้ force push เมื่อส่ง
ข้อขัดแย้งในการรวมเกิดขึ้นเมื่อบรรทัดเดียวกันของไฟล์ถูกเปลี่ยนแปลงในสองสาขา Git ไม่สามารถระบุโดยอัตโนมัติว่าควรเก็บเวอร์ชันใดและต้องการการแทรกแซงของนักพัฒนา ข้อขัดแย้งจะแสดงในไฟล์โดยใช้เครื่องหมายพิเศษ: <<<<<<<, =======, >>>>>>>
กระบวนการแก้ไขข้อขัดแย้งประกอบด้วยหลายขั้นตอน ขั้นแรก นักพัฒนาเปิดไฟล์ที่มีข้อขัดแย้งและเลือกการเปลี่ยนแปลงที่ต้องการด้วยตนเอง สิ่งสำคัญคือไม่เพียงแค่เลือกเวอร์ชันใดเวอร์ชันหนึ่ง แต่ต้องเข้าใจตรรกะของการเปลี่ยนแปลงทั้งสองและตัดสินใจอย่างถูกต้อง หลังจากแก้ไขไฟล์ เครื่องหมายข้อขัดแย้งจะถูกลบออก และการเปลี่ยนแปลงจะถูกเพิ่มไปยัง staging area ผ่าน git add
# ดูรายการไฟล์ที่มีข้อขัดแย้ง
git status
# เริ่ม mergetool (เช่น VS Code, IntelliJ)
git mergetool
# หลังจากแก้ไขข้อขัดแย้งทั้งหมด
git add .
git merge --continue
# หรือยกเลิกการรวมทั้งหมด
git merge --abort
การใช้เครื่องมือรวมแบบภาพช่วยเร่งการแก้ไขข้อขัดแย้งได้อย่างมาก VS Code, IntelliJ IDEA และ GitKraken มีอินเทอร์เฟซสามแผง: สาขาปัจจุบัน สาขาที่เข้ามา และผลลัพธ์ เครื่องมือ git mergetool จะเปิดโปรแกรมแก้ไขที่กำหนดค่าไว้โดยอัตโนมัติสำหรับแต่ละไฟล์ที่มีข้อขัดแย้ง
วิธีที่ดีที่สุดในการหลีกเลี่ยงข้อขัดแย้งที่ซับซ้อนคือการซิงโครไนซ์สาขาคุณสมบัติกับสาขาหลักเป็นประจำ หากนักพัฒนารวม main เข้ากับสาขาของตัวเองวันละครั้ง ข้อขัดแย้งจะมีขนาดเล็กและแก้ไขได้ง่าย การสะสมการเปลี่ยนแปลงเป็นเวลาหนึ่งสัปดาห์รับประกันข้อขัดแย้งที่ซับซ้อนที่มีความเสี่ยงสูงต่อข้อผิดพลาด
Rebase และ merge เป็นสองวิธีในการรวมการเปลี่ยนแปลง และการเลือกระหว่างพวกเขามักก่อให้เกิดการถกเถียงในทีม Rebase ย้ายคอมมิตจากสาขาหนึ่งไปไว้อีกสาขาหนึ่ง โดยเขียนประวัติใหม่ Merge สร้าง merge commit ใหม่ เก็บรักษาประวัติการแตกสาขา แต่ละวิธีมีข้อดีและข้อจำกัดของตัวเอง
Rebase เหมาะสมเมื่อนักพัฒนากำลังทำงานในสาขาคุณสมบัติท้องถิ่นของตัวเองและต้องการประวัติเชิงเส้นที่สะอาดก่อนสร้าง Pull Request หลังจาก rebase คอมมิตทั้งหมดจะถูกจัดเรียงตามลำดับโดยไม่มี merge commit ที่ไม่จำเป็น อย่างไรก็ตาม rebase ต้องใช้ force push และไม่สามารถใช้กับสาขาที่มีหลายคนทำงานพร้อมกัน
กฎทองของ Git: อย่าใช้ rebase กับคอมมิตที่ถูกพุชไปยังพื้นที่เก็บข้อมูลที่ใช้ร่วมกันแล้ว สิ่งนี้รับประกันว่าประวัติในสาขาที่ใช้ร่วมกันจะไม่เปลี่ยนแปลงและนักพัฒนาคนอื่นจะไม่พบคอมมิตที่ซ้ำกันหรือสูญหาย ในการรวมสาขาคุณสมบัติเข้ากับสาขาหลัก ให้ใช้ merge ผ่าน Pull Request
กระบวนการรวมที่ถูกต้องคือรากฐานของการพัฒนาที่มีเสถียรภาพ ในการทำงานเป็นทีมสมัยใหม่ การรวมไม่ได้ทำผ่านคอนโซล แต่ทำผ่าน Pull Request บน GitHub หรือ Merge Request ใน GitLab PR ผ่านการตรวจสอบโค้ด การตรวจสอบ CI อัตโนมัติ และหลังจากนั้นจึงถูกรวมเข้ากับสาขาหลัก
แนวปฏิบัติแรก — รวมหลังจากผ่านการตรวจสอบทั้งหมดแล้วเท่านั้น ไพพ์ไลน์ CI ต้องสร้างโครงการ รันการทดสอบ และตรวจสอบคุณภาพโค้ด หากการตรวจสอบอย่างน้อยหนึ่งรายการล้มเหลว การรวมจะถูกบล็อก แพลตฟอร์มสมัยใหม่ (GitHub, GitLab) มีการป้องกันในตัว: branch protection rules จะบล็อกการรวมโดยอัตโนมัติเมื่อ CI ล้มเหลว
แนวปฏิบัติที่สอง — อย่ารวมโค้ดที่เสียหาย ก่อนการรวม นักพัฒนาต้องตรวจสอบว่าการเปลี่ยนแปลงของตนไม่ทำให้บิลด์เสียหายหรือทำให้ฟังก์ชันการทำงานที่มีอยู่ถดถอย การทดสอบอัตโนมัติและการตรวจสอบโค้ดมีไว้เพื่อจุดประสงค์นี้
แนวปฏิบัติที่สาม — ทำความสะอาดสาขาคุณสมบัติหลังการรวม สาขาที่ถูกรวมแล้วควรถูกลบ สิ่งนี้ป้องกันความสับสนและความรกรุงรังในพื้นที่เก็บข้อมูล GitHub จะเสนอให้ลบสาขาโดยอัตโนมัติหลังจากรวม PR และการตั้งค่าพื้นที่เก็บข้อมูลสามารถกำหนดค่าให้ลบอัตโนมัติได้
คำถามที่พบบ่อย
Merge คือการรวมสองสาขา Git เข้าด้วยกัน การเปลี่ยนแปลงจากสาขาหนึ่งถูกถ่ายโอนไปยังอีกสาขาหนึ่งผ่านการรวมสามทาง (three-way merge) ผลลัพธ์ถูกบันทึกใน merge commit ใหม่ที่มีคอมมิตพ่อแม่สองตัว Merge commit เก็บรักษาข้อมูลเกี่ยวกับสาขาที่ถูกรวม
Merge สร้าง merge commit ใหม่ เก็บรักษาประวัติการแตกสาขา Rebase เขียนประวัติใหม่โดยย้ายคอมมิตไปไว้อีกสาขาหนึ่งโดยไม่สร้าง merge commit Rebase ให้ประวัติเชิงเส้นแต่ต้องใช้ force push Merge ปลอดภัยกว่าสำหรับสาขาที่ใช้ร่วมกัน rebase เหมาะกว่าสำหรับสาขาส่วนตัว
เปิดไฟล์ที่มีข้อขัดแย้ง ค้นหาเครื่องหมาย <<<<<<<, ======= และ >>>>>>> เลือกการเปลี่ยนแปลงที่ต้องการและลบเครื่องหมาย เพิ่มไฟล์ผ่าน git add และเสร็จสิ้นการรวมผ่าน git merge --continue ใช้ git mergetool สำหรับการแก้ไขแบบภาพใน VS Code หรือ IntelliJ IDEA
Pull Request (หรือ Merge Request) เป็นสิ่งจำเป็นเมื่อรวมสาขาคุณสมบัติเข้ากับสาขาหลักของโครงการ PR ผ่านการตรวจสอบโค้ดโดยเพื่อนร่วมงานและการตรวจสอบ CI อัตโนมัติ นี่คือมาตรฐานของการพัฒนาสมัยใหม่ การพุชโดยตรงไปยังสาขาหลักถูกห้ามในโครงการส่วนใหญ่
Squash merge รวมคอมมิตทั้งหมดของสาขาคุณสมบัติเป็นหนึ่งเดียวก่อนรวม สิ่งนี้ให้ประวัติที่สะอาดของสาขาหลักโดยไม่มีคอมมิตร่างกลาง ใช้ squash merge เมื่อสาขาคุณสมบัติมีคอมมิตยูทิลิตี้จำนวนมาก (wip, fixes) และไม่จำเป็นต้องเก็บขั้นตอนกลางทั้งหมดในประวัติ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม