- Manyana คือ ต้นแบบการจัดการเวอร์ชันบนพื้นฐาน CRDT ที่พัฒนาโดย Bram Cohen โดยนำเสนอแนวทางใหม่ที่ตัดปัญหา merge conflict และเก็บรักษาประวัติอย่างมีโครงสร้าง
- ใช้ CRDT (Conflict-Free Replicated Data Type) ทำให้การ merge สำเร็จได้เสมอ และจัดการ conflict เป็นเพียง การแสดงข้อมูลประกอบ เพื่อให้ผู้ใช้มองเห็นการเปลี่ยนแปลงได้อย่างชัดเจน
- แกนสำคัญคือ ความคงอยู่ของลำดับบรรทัด, การ merge ที่ไม่บล็อก, และ การฝังประวัติไว้ในโครงสร้างข้อมูล โดยแม้ผ่านกระบวนการ rebase ก็ไม่ทำลายบันทึกเดิม
- เป็น implementation ระดับเดโมที่เขียนด้วย Python ราว 470 บรรทัด และเปิดโค้ดทั้งหมดพร้อมเอกสารการออกแบบบน GitHub ในรูปแบบ public domain
- เป็นตัวอย่างเชิงทดลองที่เสนอ โมเดลการจัดการเวอร์ชันยุคถัดไปที่ไม่มีการ merge ล้มเหลว ก้าวข้ามข้อจำกัดของ Git
Manyana: วิสัยทัศน์ที่สอดคล้องสำหรับอนาคตของการจัดการเวอร์ชัน
- Manyana คือ ต้นแบบระบบจัดการเวอร์ชันบนพื้นฐาน CRDT ที่ Bram Cohen เผยแพร่ เพื่อแก้ปัญหา merge conflict ของระบบแบบเดิม
- CRDT รับประกันได้ว่าการ merge จะสำเร็จเสมอ และ จัดการ conflict เป็นเพียงเครื่องหมายเชิงข้อมูล เพื่อให้ผู้ใช้ตรวจสอบการเปลี่ยนแปลงจริงได้อย่างชัดเจน
- แนวทางนี้มีคุณสมบัติหลัก 3 ประการ ได้แก่ ความคงอยู่ของลำดับบรรทัด, การจัดการ conflict แบบไม่บล็อก, และ การฝังประวัติไว้ในโครงสร้าง
- แม้ในกระบวนการ rebase ก็ยังคงรักษาประวัติเดิมไว้ และสามารถจัดการโครงสร้างการ merge ที่ซับซ้อนซึ่งไม่มี common ancestor เดียวได้อย่างเสถียร
- Manyana เป็น implementation ระดับเดโม ที่เขียนด้วย Python ราว 470 บรรทัด โดยเอกสารการออกแบบและโค้ดถูกเผยแพร่บน GitHub ในรูปแบบ public domain
แกนสำคัญของแนวทางบนพื้นฐาน CRDT
- CRDT ทำให้ การ merge สำเร็จเสมอ และมอบ eventual consistency ที่รับประกันผลลัพธ์เดียวกันไม่ว่าการ merge จะเกิดในลำดับใด
- แม้หลายผู้ใช้จะทำงานบน branch แยกกันอย่างอิสระ แล้วนำมา merge ในลำดับใดก็ตาม ผลลัพธ์ก็ยังคงเหมือนเดิม
- ด้วย ความคงอยู่ของลำดับบรรทัด เมื่อตัดสินลำดับของโค้ดที่ถูกแทรกในตำแหน่งเดียวกันแล้ว ลำดับนั้นจะถูกรักษาไว้ต่อไป
- ช่วยป้องกันปัญหาที่แต่ละ branch แก้ส่วน conflict เดียวกันออกมาต่างกัน
- conflict ถูกจัดการเป็นเพียงเครื่องหมายให้ข้อมูล และไม่ขัดขวางการ merge
- ระบบจะสร้างผลลัพธ์จากการ merge ได้เสมอ และ conflict จะถูกแสดงเป็น “ส่วนที่ถูกแก้พร้อมกันในตำแหน่งใกล้เคียงกัน”
- มีการติดตามทั้งผู้กระทำและการกระทำของแต่ละการเปลี่ยนแปลง เพื่อให้ การแสดง conflict ที่มีประโยชน์
- ประวัติถูกฝังอยู่ในโครงสร้างข้อมูล
- สถานะถูกแทนด้วยโครงสร้าง
weave ที่รวมทุกบรรทัดของไฟล์ พร้อมเมทาดาทาที่ระบุเวลาของการเพิ่มและการลบในแต่ละบรรทัด
- เวลาทำ merge เพียงป้อนสถานะสองชุดเข้าไปก็จะได้ผลลัพธ์ที่ถูกต้องเสมอ โดยไม่ต้องหา common ancestor หรือไล่สำรวจ DAG
การแสดง conflict ที่ดีขึ้น
- ระบบจัดการเวอร์ชันแบบเดิม เมื่อเกิด conflict มักเพียงแสดงโค้ดสองบล็อกวางคู่กัน ทำให้ผู้ใช้ต้องตีความความต่างเอง
- Manyana จะแสดงแต่ละช่วง conflict อย่างชัดเจนว่า “ถูกลบ”, “ถูกเพิ่ม” เป็นต้น พร้อมระบุว่า ใครเป็นผู้ทำการเปลี่ยนแปลงอะไร
- ตัวอย่างเช่น หากผู้ใช้คนหนึ่งลบฟังก์ชัน และอีกคนเพิ่มหนึ่งบรรทัดเข้าไปในฟังก์ชันนั้น Manyana จะจำแนกโครงสร้างของแต่ละการเปลี่ยนแปลงให้เห็นอย่างชัดเจน
- ทำให้ผู้ใช้ไม่ต้องเทียบบล็อกโค้ดสองก้อนเอง แต่สามารถ เข้าใจความหมายและบริบทของการเปลี่ยนแปลงได้ทันที
การนิยาม rebase ใหม่
- ในระบบบนพื้นฐาน CRDT นั้น rebase ไม่ทำลายประวัติ
- rebase แบบเดิมจะนำ commit ไปวางซ้อนใหม่บน base ใหม่ จนเกิดประวัติที่แต่งขึ้นภายหลัง
- แต่ใน Manyana สามารถให้ผลแบบเดียวกันได้ โดยยัง เก็บรักษาประวัติดั้งเดิมทั้งหมด
- เพื่อทำสิ่งนี้ เพียงเพิ่มหมายเหตุ “primary ancestor” ลงใน DAG ก็เพียงพอ
- วิธีนี้ทำงานได้อย่างเสถียรแม้กับ โครงสร้างการ merge ที่ไม่มี common ancestor และช่วยหลีกเลี่ยงความล้มเหลวของการ merge แบบ 3-way ดั้งเดิม
สถานะปัจจุบันของโครงการ
- Manyana ยังเป็น implementation ระดับเดโม ไม่ใช่ระบบจัดการเวอร์ชันที่สมบูรณ์ และทำงานในระดับไฟล์เดี่ยว
- ประกอบด้วย โค้ด Python ราว 470 บรรทัด
- ฟีเจอร์ Cherry-pick และ local undo ยังไม่ได้ถูกพัฒนา แต่มีการอธิบายทิศทางในอนาคตไว้ใน README แล้ว
- โครงการนี้ พิสูจน์ว่าการจัดการเวอร์ชันบนพื้นฐาน CRDT สามารถแก้ปัญหา UX ได้ และให้ผลลัพธ์ที่ดีกว่าเครื่องมือเดิม
- โค้ดทั้งหมดเผยแพร่แบบ public domain และ เอกสารการออกแบบทั้งหมดรวมอยู่ใน GitHub README
สรุปปฏิกิริยาจากชุมชน
- ผู้ใช้รายหนึ่งมองว่าแม้ Git จะถูกใช้งานมานานกว่าสิบปี แต่ก็ยัง ต้องการกระบวนทัศน์ใหม่ของการจัดการเวอร์ชัน และกล่าวถึงความพยายามของ Manyana ในทางบวก
- เขาชี้ว่าแนวคิดที่ว่าการ merge สำเร็จเสมอนั้นยังไม่ใช่เรื่องเข้าใจได้โดยสัญชาตญาณ และขอ ตัวอย่างและคำอธิบายเพิ่มเติม
- เขาสนใจแนวคิดการปรับปรุง rebase และระบุว่าในโปรเจกต์ส่วนตัว เขาใช้ วิธีจัดการ merge ผ่าน branch กลาง
- เขายังชี้ข้อจำกัดของ Git เช่น การจัดการไฟล์ไบนารี, ความสับสนเรื่อง branch ซ้าย/ขวา, และ การขาดการสรุปเมื่อโค้ดเปลี่ยนจำนวนมาก
- เขาเสนอว่าในอนาคต ระบบจัดการเวอร์ชันควรรองรับความสามารถแบบ token-aware หรือ ปลั๊กอินตามภาษาและชนิดไฟล์
- ผู้ใช้อีกรายถามว่า Manyana มีพื้นฐานคล้ายกับ Pijul หรือ Darcs หรือไม่ และอยากเห็นการเปรียบเทียบปัญหาด้านประสิทธิภาพของ Darcs กับสถานะปัจจุบันของ Pijul
บทสรุป
- Manyana คือ เดโมที่จับต้องได้ของการนำ CRDT มาใช้กับการจัดการเวอร์ชัน โดยออกแบบปัญหา conflict และ rebase ใหม่ตั้งแต่รากฐาน
- โครงสร้างที่ไม่มีการ merge ล้มเหลว การทำให้ conflict กลายเป็นข้อมูล และการฝังประวัติไว้เชิงโครงสร้าง ล้วนเป็น แนวทางออกแบบที่ก้าวข้ามข้อจำกัดของโมเดล Git แบบเดิม
- แม้ยังไม่ใช่ระบบที่สมบูรณ์ แต่ก็เป็น จุดเริ่มต้นที่มีความหมายในฐานะแบบพิมพ์เขียวของระบบจัดการเวอร์ชันยุคถัดไป
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
คิดว่าวิธีแสดงผล merge เป็นคนละประเด็นกับการแสดงประวัติ
ผมเองก็ไม่ชอบ UI merge เริ่มต้นของ Git เลยใช้ p4merge แทน มันเป็นเครื่องมือที่แสดง 4 พาเนล (ซ้าย, ขวา, common base, ผลลัพธ์) ทำให้เห็นสาเหตุของ conflict และวิธีแก้ได้ในภาพเดียว
เลยไม่คิดว่าจำเป็นต้องเปลี่ยนตัว VCS เอง
merge.conflictStyleของ Git เป็น"diff3"หรือ"zdiff3"ก็จะแสดงเวอร์ชัน base ด้วยแบบนี้ดูแค่ conflict marker ก็พอจะอนุมานได้ว่าฝั่งไหนเป็นคนเพิ่ม โค้ดใหม่
เคยฟังพอดแคสต์หนึ่งที่มีแขกรับเชิญซึ่งสร้าง VCS ตัวใหม่ แต่กลับเข้าใจ วิธีเก็บ diff ของ Git ผิด ฟังแล้วตกใจมาก ทำโปรเจ็กต์มาหลายปีแต่ยังไม่เคยค้นแนวคิดพื้นฐานเลย ทำให้รู้สึกว่าแนวคิดแบบ NIH(ประดิษฐ์ใหม่เอง) ยังมีชีวิตชีวาอยู่
แต่ถ้าจัดการในระดับ SCM จะมีข้อดีตรงที่สามารถ จดจำ ประวัติการ merge ของผู้ใช้ได้ ซึ่ง Git ยังมี edge case ในเรื่องนี้
ไม่แน่ใจว่าการที่ merge ไม่ล้มเหลวเลยจะเป็นเรื่องดีหรือเปล่า
การ merge ล้มเหลวมักไม่ใช่แค่ตำแหน่งชนกัน แต่เป็นสัญญาณของ semantic conflict ด้วย กรณีแบบนี้ต้องจัดการด้วยมือ
คิดว่า CRDT ไม่เหมาะกับการจัดการเวอร์ชัน
conflict คือแก่นแท้ของ version control อยู่แล้ว ถ้านักพัฒนาสองคนเปลี่ยนโค้ดไปคนละทิศทาง สุดท้ายก็ต้องมี การเลือกเชิงความหมาย อยู่ดี CRDT มีโอกาสสูงที่จะสร้าง โค้ดประหลาด ในสถานการณ์แบบนั้น
ตอนนี้ก็มีเครื่องมือบน Git มากมายที่ให้ UX การ merge ที่ดีกว่าอยู่แล้ว และการที่ cherry-pick หรือ revert ทำได้ง่ายก็เป็นข้อดีของ Git
เช่น branch หนึ่งลบค่าคงที่ออกไป แต่อีก branch ยังใช้ค่าคงที่นั้นอยู่ สุดท้ายโค้ดก็พัง
conflict ของ Git ส่วนมากเป็นปัญหาเชิงไวยากรณ์ ดังนั้นแนวทาง semantic merge ที่ฉลาดขึ้นหรือแนวทางแบบ CRDT อาจช่วยได้
ตัวอย่างเช่น เวลาติดตามชื่อไฟล์, คุณสมบัติ, แฮช ฯลฯ อาจใช้ OR-set(https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) ได้
แต่การแก้ conflict ก็ยังต้องจัดการผ่านอินเทอร์เฟซภายนอกอยู่ดี
ไม่ค่อยเข้าใจว่าทำไมถึงโฟกัสกับ CRDT มากนัก
ปัญหาเชิงความหมายของ conflict ก็ยังมีอยู่เหมือนเดิม แถมการเปลี่ยนแปลงอาจดู สอดแทรกปะปนกัน(interleave) จนยิ่งสับสน
ผมเป็นพวก rebase เป็นหลัก ควรหลีกเลี่ยง merge commit และทุก commit ควรเป็นหน่วยที่เป็นอิสระต่อกัน ผมมองว่า Gitflow เป็น anti-pattern
Jujutsu กับ Gerrit แก้ปัญหาจริงของ Git เรื่อง “การจัดการสายโซ่ของ commit ตาม feedback จากการรีวิว” ได้ดี
Git ใช้วิธีนำ snapshot กลับมาใช้ใหม่ เลยเท่ากับว่างานเดียวกันมีอยู่สองครั้ง ขณะที่ Pijul ทำงานเป็น หน่วยของ patch ทำให้ได้ผลลัพธ์เดียวกันไม่ว่าลำดับจะเป็นอย่างไร ผมคิดว่านี่แหละคือหน่วยงานที่เป็นอิสระจริง ๆ
แม้อยู่ในสถานะที่มี conflict ก็ยัง ย้อนกลับ(undo) เฉพาะบาง commit ได้ จึงอาจมีโครงสร้างที่ยืดหยุ่นกว่า Git
ในโลกจริงหลายครั้งสิ่งสำคัญมีแค่ผลลัพธ์สุดท้าย การผสม squash merge อย่างเหมาะสมจึงเป็นทางออกที่ใช้งานได้จริง
แต่บางปัญหาต้องมี conflict โดยธรรมชาติ เช่น อาการที่ตัวอักษรถูกสลับปนกันในตัวแก้ไขแบบแก้พร้อมกัน ซึ่งอาจให้ผลลัพธ์ที่แย่กว่าเดิม
โปรเจ็กต์นี้ดูเหมือนเป็นการขยายแนวคิดจาก Codeville ที่ Bram เคยทำไว้ก่อนหน้านี้
Codeville โผล่มาในช่วงกระแส DVCS บูมต้นยุค 2000 และใช้ การเก็บและ merge แบบ weave
มันเป็นแนวคิดที่มาก่อน CRDT ราว 10 ปี แต่ก็ต่อยอดกันมาอย่างเป็นธรรมชาติ
ดีใจที่ Bram ยังจับปัญหานี้อยู่และพยายามลองสิ่งใหม่ ๆ
arxiv:2002.09511
ไม่เห็นด้วยกับคำพูดที่ว่า “ยังไม่มี VCS ที่ใช้ CRDT”
มี Pijul อยู่แล้ว และเป็นโปรเจ็กต์ที่ผู้เชี่ยวชาญทุ่มเวลาไปหลายพันชั่วโมง
มันยังอยู่ในสถานะทดลองมา 6 ปีแล้ว และผมก็เคยเปิด อีชู เองเมื่อ 4 ปีก่อน แต่ก็ยังไม่ถูกนำไปแก้
Pijul เป็น VCS ที่พัฒนาด้วยตัวมันเอง เลยไม่ได้ใช้ GitHub
pijul pull -aก็เกิด conflict เลยลงท้ายด้วยการ clone ใหม่เฉย ๆ สงสัยว่ามี pull แบบติดตามอัปเดตโดยเฉพาะไหมmanana.py เป็นโค้ด Python แบบ ไม่มี dependency ยาว 473 บรรทัด
ตัว implementation จริงมีแค่ประมาณ 240 บรรทัด ที่เหลือเป็นโค้ดทดสอบ เรียบง่ายแต่ชวนประทับใจ
พอคิดถึงเหตุการณ์ left-pad ใน ecosystem ของ JS ก็ยิ่งรู้สึกว่า Python เองก็ควรมี แพ็กเกจเล็ก ๆ ที่รับผิดชอบชัดเจน แบบนี้ให้มากขึ้น
ระบบแบบนี้ควรถูกออกแบบโดยวิเคราะห์ ลักษณะของ merge conflict ตามขนาดทีม
ทีม 1 คน, 10 คน, 100 คน, 1000 คน เจอปัญหาอะไรต่างกันอย่างไร และ การพัฒนาแบบใช้เอเจนต์ จะเปลี่ยนเรื่องนี้อย่างไรก็ควรนำมาคิดด้วย
จากประสบการณ์ของผม ในทีมขนาด 1~100 คน ถ้าแบ่ง subtree ของโค้ดตามทีมก็แทบไม่มี conflict เลย
ถ้าเอเจนต์มีมากขึ้น 100 คนก็อาจกลายเป็นเหมือน 1000 คนได้ แต่ตอนนี้ยังรู้สึกว่า มีโซลูชันก่อนที่จะมีปัญหาจริง
เดี๋ยวนี้แค่ ให้ Codex จัดการ merge conflict ก็จบ เลยยิ่งมีเหตุผลน้อยลงที่จะใช้ VCS ใหม่
Git ถูกออกแบบมาสำหรับทีมขนาดใหญ่ และในยุคของเอเจนต์ก็รับมือได้ด้วย การทำกระบวนการให้เป็นอัตโนมัติ
ปัญหากลับมักเกิดจาก คอขวดของ shared library หรือข้อจำกัดด้านสิทธิ์เข้าถึงมากกว่า
ปัญหาที่ใหญ่กว่า conflict คือ scalability ของ Git
ขนาดของที่เก็บและความเร็วในการเปลี่ยนแปลงกำลังเข้าใกล้ขีดจำกัดแล้ว ต้องมีการออกแบบใหม่ทั้งฝั่งเซิร์ฟเวอร์ ไคลเอนต์ และโปรโตคอล
ส่วนตัวผมยังไม่ค่อยเห็นว่าระบบนี้แก้ปัญหาอะไร
ในเชิงนามธรรมมันน่าสนใจ แต่ในทางปฏิบัติ jj ใช้งานได้จริงกว่า Git มาก
ผมคิดว่าก้าวต่อไปควรเป็นระบบที่จัดการเวอร์ชันในระดับ AST ไม่ใช่ระดับไฟล์
เคยมีความพยายามอย่าง LightTable หรือ Dark มาก่อน ถ้าได้ทดลอง VCS แบบอิงต้นไม้(tree-based) แนวนี้ก็น่าสนใจ