== การรวมประวัติการแก้ไข == ''คำสั่ง hg merge'' '''การรวมประวัติการแก้ไข''' คือการรวมเซ็ตการแก้ไขสองอันใน [[ThaiRepository|repository]] เป็นเซ็ตการแก้ไขเดียว เรียกว่า[[ThaiMergeChangeset|merge changeset]] หรือจะพูดง่ายๆว่าเป็นการรวม[[ThaiBranch|กิ่ง]]สองสิ่ง (ซึ่งโดยปกติจะเป็นเซ็ตการแก้ไขที่[[ThaiHead|ส่วนยอด]]ของ repository) เป็นกิ่งเดียว วิธีการรวมประวัตินั้นค่อนข้างง่าย โดยปกติคุณมักจะต้องการรวมประวัติของ[[ThaiTip|ส่วนปลาย]]ของ repository เข้ามาใน[[ThaiWorkingDirectory|ไดเร็คทอรี่สำหรับใช้ทำงาน]]ของคุณ {{{#!dot digraph { rankdir = LR node [shape=record] rev0 [label="{{ p1 | p2} | rev 0:838e}"]; rev1 [label="{{ p1 | p2} | rev 1:34ef}"]; rev2 [label="{{ p1 | p2} | rev 2:4563}"]; rev3 [label="{{ p1 | p2} | rev 3:fe56 (tip)}"]; workingdir [label="{{ p1 | p2} | working directory}"]; rev0 -> rev1:p1 [dir=back, label="parent"] rev1 -> rev2:p1 [dir=back] rev1 -> rev3:p1 [dir=back] rev2 -> workingdir:p1 [dir=back] label = "before merge" } }}} เมื่อคุณใช้คำสั่ง {{{hg merge}}} Mercurial จะทำการรวมการแก้ไขต่างๆจากส่วนปลายเข้าไปในไดเร็คทอรี่ของคุณ; หลังจากการรวมประวัติ เซ็ตการแก้ไขเวอร์ชั่นปลายนี้จะกลายเป็นบรรพบุรุษที่สองของไดเร็คทอรี่สำหรับใช้ทำงาน {{{#!dot digraph { rankdir = LR node [shape=record] rev0 [label="{{ p1 | p2} | rev 0:838e}"]; rev1 [label="{{ p1 | p2} | rev 1:34ef}"]; rev2 [label="{{ p1 | p2} | rev 2:4563}"]; rev3 [label="{{ p1 | p2} | rev 3:fe56 (tip)}"]; workingdir [label="{{ p1 | p2} | working directory}"]; rev0 -> rev1:p1 [dir=back] rev1 -> rev2:p1 [dir=back] rev1 -> rev3:p1 [dir=back] rev2 -> workingdir:p1 [dir=back, label="parent 1"] rev3 -> workingdir:p2 [dir=back, color=red, label="parent 2"] label = "after merge" } }}} ขั้นตอนแรกของการรวมประวัติคือการหาเซ็ตการแก้ไขที่เป็น 'บรรพบุรุษ' ของทั้งสองเวอร์ชั่นเสียก่อน (ในที่นี้คือ rev 1) โดยการค้นหาจะทำกับทั้ง repository และเปรียบเทียบแบบไฟล์ต่อไฟล์ ถ้าไฟล์ถูกแก้ไขทั้งใน repository คุณและ repository อื่น Mercurial จะใช้[[ThaiMergeProgram|โปรแกรมการรวมโค้ด]] เพื่อรวมเนื้อหาที่ถูกแก้ไขจาก repository อื่นเข้ามาไว้ในเนื้อหาของไดเร็คทอรี่ของคุณ กรณีที่มี[[ThaiConflict|การแก้ไขที่มีความขัดแย้ง]]คุณจะต้องแก้ไขความขัดแย้งนี้เองผ่านโปรแกรมดังกล่าว หลังจากรวมเนื้อหาแล้ว คุณจะต้อง[[ThaiCommit|คอมมิท]]การแก้ไขด้วย การคอมมิทนี้จะสร้าง merge changeset ใหม่ (rev 4 ในตัวอย่าง) ถือเป็นการบันทึกผลลัพธ์ของการรวมประวัติการแก้ไขและเนื้อหาอย่างถาวรในไดเร็คทอรี่สำหรับใช้ทำงานของคุณ {{{#!dot digraph { rankdir = LR node [shape=record] rev0 [label="{{ p1 | p2} | rev 0:838e}"]; rev1 [label="{{ p1 | p2} | rev 1:34ef}"]; rev2 [label="{{ p1 | p2} | rev 2:4563}"]; rev3 [label="{{ p1 | p2} | rev 3:fe56}"]; rev4 [label="{{ p1 | p2} | rev 4:ac98 (tip)}", color=red]; workingdir [shape=record, label="{{ p1 | p2} | working directory}"]; rev0 -> rev1:p1 [dir=back] rev1 -> rev2:p1 [dir=back] rev1 -> rev3:p1 [dir=back] rev2 -> rev4:p1 [dir=back, color=red] rev3 -> rev4:p2 [dir=back, color=red] rev4 -> workingdir:p1 [dir=back, color=red] label = "after commit" } }}} Mercurial จะไม่อนุญาติให้คุณทำการรวมประวัติครั้งใหม่จนกว่าคุณจะทำการคอมมิท เพราะว่า Mercurial จำเป็นต้องใช้ประวัติการคอมมิทนี้สำหรับการรวมประวัติครั้งต่อๆไปในอนาคต และเหมือนเช่นเคย เซ็ตการแก้ไขที่สร้างจากการคอมมิทจะกลายเป็นบรรพบุรุษของไดเร็คทอรี่สำหรับใช้ทำงาน ซึ่งจะมีบรรพบุรุษแค่อันเดียว (parent 1) ตัวช่วยเหลือ: http://www.selenic.com/mercurial/hg.1.html#merge หน้าที่เกี่ยวข้อง: [[ThaiTutorialMerge|บทเรียนการรวมประวัติการแก้ไขจาก repository อื่น]], [[ThaiResolveConflict]] === รายละเอียดทางเทคนิค === ==== การแตกกิ่งและการรวมกิ่ง ==== ไดเร็คทอรี่สำหรับใช้ทำงานจริงๆแล้วก็เหมือนกิ่งๆหนึ่ง ซึ่งหมายความว่าผู้ใช้แต่ละคนก็กำลังทำงานอยู่บนกิ่งของตัวเอง เมื่อ Mercurial สร้างเนื้อหาของไฟล์ในไดเร็คทอรี่สำหรับใช้ทำงาน Mercurial จะจำว่าดึงเนื้อหามาจากเซ็ตการแก้ไขเวอร์ชั่นไหน ทั้งนี้เพื่อที่ Mercurial จะได้กำหนด[[ThaiParent|บรรพบุรุษ]]ที่ถูกต้องสำหรับเซ็ตการแก้ไขที่จะถูกคอมมิท ในการรวมกิ่งสองกิ่งด้วยกัน คุณจะต้องดึงประวัติการแก้ไขเวอร์ชั่นยอดจากที่อื่นมาไว้ใน repository ของคุณ อัพเดทเนื้อหาในไดเร็คทอรี่ของคุณและทำการรวมเนื้อหา จากนั้นจึงคอมมิทผลลัพธ์หลังรวมเนื้อหาเสร็จ เซ็ตการแก้ไข ที่เกิดจากการคอมมิทนี้จะมีบรรพบุรุษสองอัน ==== การรวมประวัติแบบกราฟ ==== การรวมกราฟแบบ directed acyclic graphs (D``AGs) -- โดยกราฟนี้เทียบเท่ากับแผนภูมิแสดงลำดับเครือญาติ ของการแก้ไขต่างๆ -- สองอันจะต้องมีการตรวจสอบว่า node จากทั้งสองกราฟตรงกันหรือไม่เสียก่อน การเปรียบเทียบเฉพาะ เนื้อหาของแต่ละ node (หรือแฮชของเนื้อหา) อย่างเดียวนั้นไม่เพียงพอเพราะว่าการตรวจสอบนี้ไม่คำนึงถึงประวัติ การแก้ไข Mercurial แก้ปัญหานี้โดยการใช้ [[ThaiNodeid|nodeid]] ในการตรวจสอบเพราะ nodeid บ่งบอกทั้งเนื้อหาของไฟล์และตำแหน่งของ node จากรากของ repository การรวมประวัติจึงทำได้ อย่างง่ายดาย เพียงแค่ตรวจสอบว่า nodeid ที่อยู่ในกราฟ A อยู่ในกราฟ B หรือเปล่า และ nodeid ที่อยู่ในกราฟ B อยู่ในกราฟ A หรือเปล่า ถ้าไม่อยู่ Mercurial จะทำการเพิ่ม node เข้าไปใน [[ThaiRevlog|revlog]] ==== การรวมมานิเฟสต์ ==== สำหรับการรวม[[ThaiManifest|มานิเฟสต์]] Mercurial จะทำการเปรียบเทียบมานิเฟสต์ทั้งสองเป็นอันดับแรก จากนั้นจะดูว่าไฟล์ไหนบ้างที่จะต้องถูกเพิ่ม ลบ และรวมเนื้อหา สำหรับแต่ละไฟล์ที่ต้องมีการรวมเนื้อหา Mercurial จะทำการรวมกราฟและรวมเนื้อหาที่ขัดแย้งกันตามที่ได้อธิบายมาก่อนหน้า และในการรวมเนื้อหาของแต่ละไฟล์นั้น Mercurial จะใช้ D``AGs สำหรับไฟล์นั้นๆ ไม่ใช่ D``AGs ในระดับเซ็ตการแก้ไข ดังที่ได้แสดงในผังด้านล่างนี้: {{{ 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 [[ThaiPull|ดึงประวัติการแก้ไข]]จากเซิร์ฟเวอร์ กิ่งทั้งหมดที่ไม่มีอยู่ใน repository จะถูกดึงมารวมในกราฟประวัติการแก้ไขของตัวเอง โดยการดึงประวัติ นี้จะเกิดขึ้นในสองขั้นตอน: 1. หารากของ repository ใหม่ * ขั้นตอนนี้เริ่มโดยการหาส่วนยอด (head) ใหม่จากนั้นจึงทำการหาประวัติย้อนหลังจากยอดเหล่านี้ไปจนถึง node ที่ไม่มีอยู่ใน repository โดย node เหล่านี้คือรากของ'''กลุ่มการแก้ไข (changegroup)''' ซึ่งก็คือเซ็ตของการแก้ไขทั้งหมดที่เริ่มจากรากเหล่านี้นั่นเอง Mercurial พยายามทำการค้นหา node เหล่านี้อย่างมีประสิทธิภาพที่สุดเท่าที่จะทำได้ในเชิงของ bandwidth และ round-trips 2. ดึงกลุ่มการแก้ไข * หลังจากที่หารากใหม่ได้แล้ว Mercurial จะทำการดึงประวัติการแก้ไขในกลุ่มการแก้ไขมาในการโอนข้อมูลครั้งเดียวโดยการโอนข้อมูลจะทำการจัดเรียงส่วนต่าง (delta) ของเซ็ตการแก้ไข มานิเฟสต์ และไฟล์ต่างๆ และเนื่องจาก Mercurial สามารถเพิ่มส่วนต่างที่ถูกบีบอัดระหว่างการโอนเข้าไปใน repository ทันทีโดยไม่ต้องขยาย จึงทำให้การดึงข้อมูลทำได้อย่างรวดเร็ว (ลองดู [[WireProtocol]] สำหรับรายละเอียดเพิ่มเติม) หลังจาก Mercurial ดึงประวัติการแก้ไขจาก repository อื่นเข้ามาแล้ว การทำการรวมประวัติและเนื้อหาก็ทำได้ตามที่ได้อธิบายด้านบน === หมายเหตุ === * [[http://www.selenic.com/pipermail/mercurial/2008-April/018925.html|Merge with ancestor]] is not allowed, unless the merged descendant is a named branch. Does anyone know why? ---- CategoryCommand CategoryThai