การรวมประวัติการแก้ไข
คำสั่ง hg merge
การรวมประวัติการแก้ไข คือการรวมเซ็ตการแก้ไขสองอันใน repository เป็นเซ็ตการแก้ไขเดียว เรียกว่าmerge changeset หรือจะพูดง่ายๆว่าเป็นการรวมกิ่งสองสิ่ง (ซึ่งโดยปกติจะเป็นเซ็ตการแก้ไขที่ส่วนยอดของ repository) เป็นกิ่งเดียว
วิธีการรวมประวัตินั้นค่อนข้างง่าย โดยปกติคุณมักจะต้องการรวมประวัติของส่วนปลายของ repository เข้ามาในไดเร็คทอรี่สำหรับใช้ทำงานของคุณ
เมื่อคุณใช้คำสั่ง hg merge Mercurial จะทำการรวมการแก้ไขต่างๆจากส่วนปลายเข้าไปในไดเร็คทอรี่ของคุณ; หลังจากการรวมประวัติ เซ็ตการแก้ไขเวอร์ชั่นปลายนี้จะกลายเป็นบรรพบุรุษที่สองของไดเร็คทอรี่สำหรับใช้ทำงาน
ขั้นตอนแรกของการรวมประวัติคือการหาเซ็ตการแก้ไขที่เป็น 'บรรพบุรุษ' ของทั้งสองเวอร์ชั่นเสียก่อน (ในที่นี้คือ rev 1) โดยการค้นหาจะทำกับทั้ง repository และเปรียบเทียบแบบไฟล์ต่อไฟล์
ถ้าไฟล์ถูกแก้ไขทั้งใน repository คุณและ repository อื่น Mercurial จะใช้โปรแกรมการรวมโค้ด เพื่อรวมเนื้อหาที่ถูกแก้ไขจาก repository อื่นเข้ามาไว้ในเนื้อหาของไดเร็คทอรี่ของคุณ กรณีที่มีการแก้ไขที่มีความขัดแย้งคุณจะต้องแก้ไขความขัดแย้งนี้เองผ่านโปรแกรมดังกล่าว
หลังจากรวมเนื้อหาแล้ว คุณจะต้องคอมมิทการแก้ไขด้วย การคอมมิทนี้จะสร้าง merge changeset ใหม่ (rev 4 ในตัวอย่าง) ถือเป็นการบันทึกผลลัพธ์ของการรวมประวัติการแก้ไขและเนื้อหาอย่างถาวรในไดเร็คทอรี่สำหรับใช้ทำงานของคุณ
Mercurial จะไม่อนุญาติให้คุณทำการรวมประวัติครั้งใหม่จนกว่าคุณจะทำการคอมมิท เพราะว่า Mercurial จำเป็นต้องใช้ประวัติการคอมมิทนี้สำหรับการรวมประวัติครั้งต่อๆไปในอนาคต
และเหมือนเช่นเคย เซ็ตการแก้ไขที่สร้างจากการคอมมิทจะกลายเป็นบรรพบุรุษของไดเร็คทอรี่สำหรับใช้ทำงาน ซึ่งจะมีบรรพบุรุษแค่อันเดียว (parent 1)
ตัวช่วยเหลือ: http://www.selenic.com/mercurial/hg.1.html#merge
หน้าที่เกี่ยวข้อง: บทเรียนการรวมประวัติการแก้ไขจาก repository อื่น, ThaiResolveConflict
รายละเอียดทางเทคนิค
การแตกกิ่งและการรวมกิ่ง
ไดเร็คทอรี่สำหรับใช้ทำงานจริงๆแล้วก็เหมือนกิ่งๆหนึ่ง ซึ่งหมายความว่าผู้ใช้แต่ละคนก็กำลังทำงานอยู่บนกิ่งของตัวเอง เมื่อ Mercurial สร้างเนื้อหาของไฟล์ในไดเร็คทอรี่สำหรับใช้ทำงาน Mercurial จะจำว่าดึงเนื้อหามาจากเซ็ตการแก้ไขเวอร์ชั่นไหน ทั้งนี้เพื่อที่ Mercurial จะได้กำหนดบรรพบุรุษที่ถูกต้องสำหรับเซ็ตการแก้ไขที่จะถูกคอมมิท
ในการรวมกิ่งสองกิ่งด้วยกัน คุณจะต้องดึงประวัติการแก้ไขเวอร์ชั่นยอดจากที่อื่นมาไว้ใน repository ของคุณ อัพเดทเนื้อหาในไดเร็คทอรี่ของคุณและทำการรวมเนื้อหา จากนั้นจึงคอมมิทผลลัพธ์หลังรวมเนื้อหาเสร็จ เซ็ตการแก้ไข ที่เกิดจากการคอมมิทนี้จะมีบรรพบุรุษสองอัน
การรวมประวัติแบบกราฟ
การรวมกราฟแบบ directed acyclic graphs (DAGs) -- โดยกราฟนี้เทียบเท่ากับแผนภูมิแสดงลำดับเครือญาติ ของการแก้ไขต่างๆ -- สองอันจะต้องมีการตรวจสอบว่า node จากทั้งสองกราฟตรงกันหรือไม่เสียก่อน การเปรียบเทียบเฉพาะ เนื้อหาของแต่ละ node (หรือแฮชของเนื้อหา) อย่างเดียวนั้นไม่เพียงพอเพราะว่าการตรวจสอบนี้ไม่คำนึงถึงประวัติ การแก้ไข
Mercurial แก้ปัญหานี้โดยการใช้ nodeid ในการตรวจสอบเพราะ nodeid บ่งบอกทั้งเนื้อหาของไฟล์และตำแหน่งของ node จากรากของ repository การรวมประวัติจึงทำได้ อย่างง่ายดาย เพียงแค่ตรวจสอบว่า nodeid ที่อยู่ในกราฟ A อยู่ในกราฟ B หรือเปล่า และ nodeid ที่อยู่ในกราฟ B อยู่ในกราฟ A หรือเปล่า ถ้าไม่อยู่ Mercurial จะทำการเพิ่ม node เข้าไปใน revlog
การรวมมานิเฟสต์
สำหรับการรวมมานิเฟสต์ Mercurial จะทำการเปรียบเทียบมานิเฟสต์ทั้งสองเป็นอันดับแรก จากนั้นจะดูว่าไฟล์ไหนบ้างที่จะต้องถูกเพิ่ม ลบ และรวมเนื้อหา
สำหรับแต่ละไฟล์ที่ต้องมีการรวมเนื้อหา Mercurial จะทำการรวมกราฟและรวมเนื้อหาที่ขัดแย้งกันตามที่ได้อธิบายมาก่อนหน้า และในการรวมเนื้อหาของแต่ละไฟล์นั้น Mercurial จะใช้ DAGs สำหรับไฟล์นั้นๆ ไม่ใช่ DAGs ในระดับเซ็ตการแก้ไข ดังที่ได้แสดงในผังด้านล่างนี้:
M M1 M2 AB |`-------v M2 ทำสำเนามาจาก M (กิ่งหลัก) aB AB ไฟล์ A ถูกแก้ไขในกิ่งหลัก |`---v AB' ไฟล์ B ถูกแก้ไขใน M2 | aB / | M1 ทำสำเนาจาก M | ab/ | M1 แก้ไขไฟล์ B | ab' | M1 รวมประวัติจาก M2 ทำให้การการแก้ไขในไฟล์ B เกิดขัดแย้งกัน | | A'B' M2 แก้ไขไฟล์ A `---+--.| | a'B' M2 รวมประวัติการแก้ไขจากกิ่งหลัก ทำให้การแก้ไขในไฟล์ A เกิดขัดแย้งกัน `--.| ??? ขึ้นอยู่กับว่าเราเลือกบรรพบุรุษอันไหน เราจะต้องทำการ รวมเนื้อหาในไฟล์ A, ไฟล์ B, หรือทั้งคู่ด้วยมือ ซึ่งทำได้ไม่ยากถ้าเรารวมทีละไฟล์
ผลลัพธ์คือเวอร์ชั่นของเนื้อหาที่ถูกรวมเข้าด้วยกันในไดเร็คทอรี่สำหรับใช้ทำงานที่รอการคอมมิท
การรวมประวัติระหว่าง repository
หนึ่งในฟีเจอร์หลักของ Mercurial คือความสามารถที่จะรวมประวัติการแก้ไขจาก repository ต่างๆ แบบแยกศูนย์ (decentralized) โดยแต่ละ repository สามารถเป็นได้ทั้งเซิร์ฟเวอร์สำหรับอ่าน อย่างเดียวหรือเป็น client ด้วยก็ได้ เมื่อ client ดึงประวัติการแก้ไขจากเซิร์ฟเวอร์ กิ่งทั้งหมดที่ไม่มีอยู่ใน repository จะถูกดึงมารวมในกราฟประวัติการแก้ไขของตัวเอง โดยการดึงประวัติ นี้จะเกิดขึ้นในสองขั้นตอน:
- หารากของ repository ใหม่
ขั้นตอนนี้เริ่มโดยการหาส่วนยอด (head) ใหม่จากนั้นจึงทำการหาประวัติย้อนหลังจากยอดเหล่านี้ไปจนถึง node ที่ไม่มีอยู่ใน repository โดย node เหล่านี้คือรากของกลุ่มการแก้ไข (changegroup) ซึ่งก็คือเซ็ตของการแก้ไขทั้งหมดที่เริ่มจากรากเหล่านี้นั่นเอง Mercurial พยายามทำการค้นหา node เหล่านี้อย่างมีประสิทธิภาพที่สุดเท่าที่จะทำได้ในเชิงของ bandwidth และ round-trips
- ดึงกลุ่มการแก้ไข
- หลังจากที่หารากใหม่ได้แล้ว Mercurial จะทำการดึงประวัติการแก้ไขในกลุ่มการแก้ไขมาในการโอนข้อมูลครั้งเดียวโดยการโอนข้อมูลจะทำการจัดเรียงส่วนต่าง (delta) ของเซ็ตการแก้ไข มานิเฟสต์ และไฟล์ต่างๆ และเนื่องจาก Mercurial สามารถเพิ่มส่วนต่างที่ถูกบีบอัดระหว่างการโอนเข้าไปใน repository ทันทีโดยไม่ต้องขยาย จึงทำให้การดึงข้อมูลทำได้อย่างรวดเร็ว
(ลองดู WireProtocol สำหรับรายละเอียดเพิ่มเติม)
หลังจาก Mercurial ดึงประวัติการแก้ไขจาก repository อื่นเข้ามาแล้ว การทำการรวมประวัติและเนื้อหาก็ทำได้ตามที่ได้อธิบายด้านบน
หมายเหตุ
is not allowed, unless the merged descendant is a named branch. Does anyone know why?