Jujutsu (jj) คือ version control ตัวใหม่ที่รันบน git repo เดิม ตัด staging area ทิ้ง และ undo ได้ทุกคำสั่ง
Jujutsu (jj) คือ version control ตัวใหม่ที่รันอยู่บน git repo เดิมได้เลย ไม่ใช่เครื่องมือที่บังคับให้เลิกใช้ git จุดที่เห็นชัดคือไม่มี staging area, undo ได้ทุกคำสั่ง และ commit ทั้งที่ยังมี conflict ได้โดยคำสั่งไม่พัง

Jujutsu (jj) คือเครื่องมือจัดการเวอร์ชันของโค้ด หรือ version control ตัวใหม่ ที่ทำงานต่อยอดอยู่บน git ของเดิมได้เลย พูดให้เห็นภาพคือ git เป็นเครื่องมือที่นักพัฒนาใช้เก็บประวัติการแก้โค้ดทุกครั้ง เพื่อให้ย้อนกลับไปเวอร์ชันก่อนหน้าได้เวลาทำพลาด ส่วน jj ไม่ได้มาแทนที่ git แต่เป็นวิธีใช้งานแบบใหม่ที่ครอบอยู่บน git อีกชั้นหนึ่ง โค้ดที่อยู่ข้างใต้ยังเป็น git repo ปกติที่ push ขึ้น GitHub แพลตฟอร์มออนไลน์ที่นักพัฒนาใช้เก็บและแชร์โค้ด ได้เหมือนเคย
ใครที่เปิดเทอร์มินัลใช้ git ทุกวันน่าจะนึกภาพออกทันที เพราะปัญหาที่ jj ตั้งใจแก้คือสิ่งที่คนใช้ git เจอซ้ำๆ ไม่ว่าจะเป็น rebase ที่พลาดทีหนึ่งแล้วกู้คืนยาก, conflict ที่ทำให้คำสั่งค้างกลางทางไปต่อไม่ได้ หรือช่วงที่เผลอพิมพ์ git reset ผิดจนงานหลุดมือหายไปเฉยๆ jj มองปัญหาพวกนี้แล้วออกแบบขั้นตอนการทำงานใหม่ตั้งแต่ต้น โดยยังรักษาความเข้ากันได้กับ git ไว้
ข้อแตกต่างสำคัญสามอย่างระหว่าง jj กับ git คือ jj ตัด staging area ทิ้งไปทั้งก้อน บันทึกทุกคำสั่งไว้ให้ย้อนกลับได้ และยอมให้ commit ทั้งที่ยังมี conflict ค้างอยู่ได้ ทั้งสามอย่างนี้รวมกันทำให้การทำงานปลอดภัยและสะดวกขึ้น ไม่ใช่เพราะ jj เร็วกว่า แต่เพราะเวลาทำพลาดจะถอยกลับได้ง่ายกว่า
รันบน repo เดิม ไม่ได้ให้ทิ้ง git

หัวใจที่ทำให้ jj ไม่ใช่เรื่องไกลตัวคือ มันใช้ git repository เป็นที่เก็บข้อมูลจริงอยู่เบื้องหลัง commit ที่สร้างจาก jj จึงมีหน้าตาเหมือน git commit ทุกประการ จะ push หรือ pull กับ git remote อย่าง GitHub ก็ทำได้ตามปกติ ตอนนี้ Git backend ยังเป็นที่เก็บข้อมูลแบบเดียวที่พร้อมใช้งานจริงของ jj ด้วย
ที่สะดวกกว่านั้นคือ jj รองรับโหมด colocated ซึ่งหมายความว่าในโฟลเดอร์เดียวกันจะใช้คำสั่ง jj หรือคำสั่ง git สลับกันก็ได้ ไม่ต้องเลือกข้างเด็ดขาด ใครที่ยังไม่มั่นใจจึงค่อยๆ ลองได้ โดยไม่ต้องย้ายทั้งทีมหรือทิ้งเครื่องมือเดิมที่ใช้อยู่
ตัว jj เองเขียนด้วยภาษา Rust และใช้ไลบรารี gitoxide เป็นตัวจัดการฝั่ง git ส่วนชื่อ "Jujutsu" เลือกมาเพราะย่อแล้วได้ jj ที่พิมพ์สั้น นี่คือเหตุผลที่หลายคนเรียกมันสั้นๆ ว่า jj จนติดปาก
ไม่มี staging area ให้ต้องคอยจำ

ความต่างที่รู้สึกได้เร็วที่สุดคือ jj ไม่มี staging area หรือ index แบบ git พูดง่ายๆ คือไม่มีขั้นตอน git add ให้ต้องทำก่อน commit อีกแล้ว เพราะ jj จะ snapshot ไฟล์ที่กำลังแก้อยู่ในเครื่อง แล้วเก็บเป็น commit ให้อัตโนมัติทุกครั้งที่ใช้คำสั่ง
ผลพลอยได้ที่คนใช้ git น่าจะรู้สึกโล่งอกคือ งานที่กำลังแก้ด้วย jj นับเป็น commit อยู่แล้ว จึงไม่มี error คอยเตือนว่างานที่ยังไม่ commit อาจโดนเขียนทับ ให้มาขวางตอนจะรันคำสั่ง และไม่ต้องพึ่ง git stash เพื่อเก็บงานค้างไว้ชั่วคราว แถมยังตั้งข้อความ commit ล่วงหน้าได้ตั้งแต่ยังทำงานไม่เสร็จ
เมื่อไม่มี staging area แล้ว งานที่เคยต้องใช้โหมด interactive บน git อย่าง git add -p ก็เปลี่ยนไปอยู่ในคำสั่งของ jj แทน เช่น jj split ที่แยก commit หนึ่งออกเป็นสองก้อน หรือ jj squash -i ที่เลือกหยิบเฉพาะการแก้บางส่วนไปรวมกับ commit ก่อนหน้า ตรรกะเดิมยังอยู่ครบ เพียงแต่ย้ายมาทำบน commit ที่มีอยู่จริงแทนที่จะทำบนพื้นที่พักกลางทาง
ย้อนได้ทุกคำสั่ง ไม่ใช่แค่ commit ล่าสุด
จุดที่หลายคนน่าจะติดใจที่สุดคือ operation log ของ jj มันบันทึกทุกคำสั่งที่เกิดขึ้นเอาไว้ ไม่ว่าจะเป็น commit, pull, push หรือ rebase พร้อมกับเก็บภาพสถานะของ repo หลังจบแต่ละคำสั่ง นั่นแปลว่า jj จำได้เสมอว่าเมื่อกี้ repo หน้าตาเป็นยังไง
พอมีบันทึกครบขนาดนี้ คำสั่ง jj undo จึงทำงานได้กว้างกว่าที่คิด เพราะมันย้อนคำสั่งไหนก็ได้ ไม่จำเป็นต้องเป็นอันล่าสุดเสมอไป เทียบกับ git ที่ต้องไปงมใน reflog เองแล้วเดาว่า commit ไหนคืออันที่ต้องการ ส่วน operation log ทำหน้าที่คล้ายกันแต่ครอบคลุมกว่า เพราะมันจดการเปลี่ยนแปลงของตำแหน่ง branch ทุกอันใน repo พร้อมกันเป็นก้อนเดียว
อีกเรื่องที่ช่วยให้ทำงานสบายใจขึ้นคือ change ID ของ jj จะไม่เปลี่ยนแม้จะแก้ commit ไปแล้ว ต่างจาก commit hash ของ git ที่เปลี่ยนค่าใหม่ทุกครั้งที่แก้ commit เดิม การที่ ID ไม่เปลี่ยนหมายความว่าจะอ้างถึง commit เดิมได้ตลอด แม้จะแก้ข้อความหรือ rebase ไปแล้วก็ตาม
conflict ไม่ทำให้คำสั่งพัง
ความต่างข้อที่สามคือ jj มอง conflict เป็นข้อมูลปกติที่เก็บไว้ใน commit ได้ ไม่ใช่สถานะ error ที่ต้องรีบเคลียร์ให้จบก่อนถึงจะไปต่อได้ เวลาเกิด conflict ขึ้น คำสั่งของ jj จะไม่ fail แต่จะบันทึก conflict นั้นไว้ใน commit แล้วปล่อยให้กลับมาแก้ทีหลังได้
ข้อนี้สำคัญตอน rebase เพราะใน git พอเจอ conflict กลางทาง งานทั้งกระบวนการมักค้างรอให้แก้ก่อน ส่วนใน jj rebase รันจนจบได้เลย แล้วค่อยตามมาดูว่ามี conflict ตรงไหนบ้าง เมื่อแก้ conflict ใน commit หนึ่งเสร็จ jj จะส่งการแก้นั้นต่อไปยัง commit ลูกหลานที่ต่อจากมันโดยอัตโนมัติ คล้ายกับ git rerere แต่เป็นพฤติกรรมที่ออกแบบมาในตัวตั้งแต่แรก
เบื้องหลังที่ทำให้สิ่งเหล่านี้ลื่นไหลคือ jj จะ rebase commit ลูกหลานให้อัตโนมัติทุกครั้งที่แก้ commit ต้นทาง ไม่ต้องไล่ rebase ทีละชั้นเอง ส่วนเรื่อง branch jj ใช้คำว่า bookmark แทน และไม่มีแนวคิด "current branch" ที่ active ค้างอยู่ จึงไม่ต้องตั้งชื่อ branch ให้ทุกการแก้เล็กๆ เหมือนที่ git บังคับกลายๆ
อยากเห็นภาพ ก็มี jj_tui
ปกติ jj ใช้ผ่านคำสั่งในเทอร์มินัลเป็นหลัก แต่สำหรับคนที่อยากเห็นภาพ commit และ branch ชัดๆ ตอนนี้มี jj_tui ของ faldor20 เป็นหน้าจอแบบ TUI คือหน้าจอที่วาดด้วยตัวอักษรในเทอร์มินัล ให้ควบคุม jj ผ่านหน้าจอแทนการพิมพ์คำสั่งทีละบรรทัด ตัวนี้เพิ่งไปปรากฏบน Lobsters เว็บชุมชนที่นักพัฒนาใช้แชร์ของใหม่ และเป็นเหตุผลหนึ่งที่ทำให้คนพูดถึง jj กันมากขึ้น
jj_tui เป็นโปรเจกต์แยกต่างหาก ไม่ได้เป็นส่วนหนึ่งของ jj ตัวหลัก มันเขียนด้วยภาษา OCaml และเขียนระบบแสดงผลขึ้นมาใหม่ทั้งหมดเพื่อให้เห็นภาพตัวอย่างแบบทันทีขณะ rebase ฟีเจอร์ที่มีอยู่ครอบคลุมงานประจำวันอย่าง commit, rebase, push/pull, จัดการ bookmark, squash และ split ส่วนการนำทางใช้ปุ่มลูกศรหรือ hjkl ก็ได้ กด space เพื่อเลือกหลายรายการ และกด ? เพื่อดู help
ก่อนจะลอง jj_tui ต้องมี jj ติดตั้งไว้ก่อน โดยต้องเป็นเวอร์ชัน 0.30.0 ขึ้นไป ฝั่ง Linux มีไฟล์โปรแกรมที่พร้อมรันได้เลย ส่วน Mac ก็มีไฟล์สำเร็จรูปให้ แต่ Windows ยังไม่รองรับโดยตรง ต้องรันผ่าน WSL ซึ่งเป็นระบบที่ให้รัน Linux อยู่บน Windows อีกที ผู้สร้างระบุเองว่ายังไม่ได้ทดสอบบน Mac เต็มที่เพราะไม่มีเครื่อง Mac ไว้ลอง ใครใช้ Mac จึงควรเผื่อใจไว้ว่าอาจเจอจุดที่ยังไม่เนียน
ของใหม่ที่ยังต้องเผื่อใจ
ก่อนจะตัดสินใจย้ายงานจริงมา jj มีข้อจำกัดที่ควรรู้ไว้ก่อน ข้อแรกคือ jj ยังอยู่ในช่วงก่อนเวอร์ชัน 1.0 ซึ่งแปลว่ารูปแบบไฟล์ที่ใช้เก็บข้อมูลอาจเปลี่ยนในแบบที่เข้ากับเวอร์ชันเก่าไม่ได้ก่อนจะถึง 1.0.0 และข้อสำคัญที่ต้องย้ำคือ อย่าคาดหวังว่ามันจะเร็วกว่า git เพราะถึงทีมจะใส่ใจเรื่องความเร็ว แต่เอกสารก็ยอมรับเองว่ายังมีจุดที่ทำงานช้าผิดปกติอยู่หลายจุด จุดขายจริงของ jj คือขั้นตอนการทำงานที่ปลอดภัยและง่ายกว่า ไม่ใช่ความเร็ว
ด้านความครบของฟีเจอร์ก็ยังมีช่องว่าง เพราะ jj ยังไม่รองรับ git submodules และยังไม่รองรับการส่งแพตช์ทางอีเมล ใครที่ต้องพึ่งฟีเจอร์สองอย่างนี้อาจยังต้องใช้ git ไปก่อน
แม้จะยังใหม่ แต่จุดที่น่าสนใจคือ Martin ใช้ jj พัฒนาตัว jj เองมาตั้งแต่ต้นปี 2021 โดยไม่เคย re-clone repo ใหม่เลย นั่นพอจะบอกได้ว่าในงานจริงระดับหนึ่ง มันใช้ทำงานต่อเนื่องได้แล้ว ตัวโปรเจกต์เปิดเป็นโอเพนซอร์สภายใต้สัญญาอนุญาต Apache 2.0
เริ่มลองวันนี้บน repo เดิม
ข้อดีของการที่ jj รันบน git repo เดิมคือ จะลองโดยไม่ต้องเสี่ยงกับงานหลักก็ได้ เริ่มจากติดตั้ง jj ตามขั้นตอนใน Jujutsu install & setup ก่อน จากนั้นค่อยทำตามลำดับสั้นๆ นี้บน repo ที่คุณคุ้นเคยอยู่แล้ว
- เข้าไปในโฟลเดอร์ git repo เดิม แล้วสั่ง
jj git initเพื่อให้ jj เริ่มทำงานบน repo นั้นในโหมด colocated ซึ่งทำให้ยังสั่งgitในโฟลเดอร์เดียวกันได้ - แก้โค้ดได้เลยโดยไม่ต้อง
git addเพราะ jj เก็บงานที่แก้เป็น commit ให้อัตโนมัติ อยากตั้งข้อความก็สั่งjj describe -m "ข้อความของคุณ" - ถ้ารู้สึกว่าทำพลาด ให้สั่ง
jj undoเพื่อย้อนคำสั่งล่าสุดกลับ แล้วลองใหม่ได้สบายใจ
แค่สามขั้นนี้ก็พอจะสัมผัสได้แล้วว่า การทำงานโดยไม่มี staging area และมีคำสั่งย้อนกลับรออยู่ตลอด ให้ความรู้สึกต่างจาก git ยังไง โดยที่ commit ทุกอันยังเป็น git commit ที่ push กลับขึ้น remote เดิมได้เหมือนเคย
เครื่องมือ version control มีไว้เพื่อให้ย้อนกลับได้ตั้งแต่แรกอยู่แล้ว สิ่งที่ jj ทำคือเปลี่ยนการย้อนกลับให้เป็นเรื่องปกติที่ทำได้ทุกขั้น ไม่ใช่ทางออกฉุกเฉินที่ต้องลุ้นทุกครั้งว่าจะกู้คืนได้หรือเปล่า
ที่มา:
- Jujutsu (jj) บน GitHub
- Git comparison จาก Jujutsu docs
- jj_tui จาก faldor20



