การรวมประวัติการแก้ไข

คำสั่ง 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 จะถูกดึงมารวมในกราฟประวัติการแก้ไขของตัวเอง โดยการดึงประวัติ นี้จะเกิดขึ้นในสองขั้นตอน:

  1. หารากของ repository ใหม่
    • ขั้นตอนนี้เริ่มโดยการหาส่วนยอด (head) ใหม่จากนั้นจึงทำการหาประวัติย้อนหลังจากยอดเหล่านี้ไปจนถึง node ที่ไม่มีอยู่ใน repository โดย node เหล่านี้คือรากของกลุ่มการแก้ไข (changegroup) ซึ่งก็คือเซ็ตของการแก้ไขทั้งหมดที่เริ่มจากรากเหล่านี้นั่นเอง Mercurial พยายามทำการค้นหา node เหล่านี้อย่างมีประสิทธิภาพที่สุดเท่าที่จะทำได้ในเชิงของ bandwidth และ round-trips

  2. ดึงกลุ่มการแก้ไข
    • หลังจากที่หารากใหม่ได้แล้ว Mercurial จะทำการดึงประวัติการแก้ไขในกลุ่มการแก้ไขมาในการโอนข้อมูลครั้งเดียวโดยการโอนข้อมูลจะทำการจัดเรียงส่วนต่าง (delta) ของเซ็ตการแก้ไข มานิเฟสต์ และไฟล์ต่างๆ และเนื่องจาก Mercurial สามารถเพิ่มส่วนต่างที่ถูกบีบอัดระหว่างการโอนเข้าไปใน repository ทันทีโดยไม่ต้องขยาย จึงทำให้การดึงข้อมูลทำได้อย่างรวดเร็ว

(ลองดู WireProtocol สำหรับรายละเอียดเพิ่มเติม)

หลังจาก Mercurial ดึงประวัติการแก้ไขจาก repository อื่นเข้ามาแล้ว การทำการรวมประวัติและเนื้อหาก็ทำได้ตามที่ได้อธิบายด้านบน

หมายเหตุ

is not allowed, unless the merged descendant is a named branch. Does anyone know why?


CategoryCommand CategoryThai

ThaiMerge (last edited 2009-05-19 19:31:02 by localhost)