Jujutsu สำหรับนักพัฒนาที่งานยุ่ง
(maddie.wtf)- Jujutsu (jj) เป็นระบบควบคุมเวอร์ชัน ที่มีแนวคิดและคำสั่ง เรียบง่ายกว่า Git แต่ยังคงมีความสามารถทรงพลัง
- เนื่องจากใช้ Git เป็นแบ็กเอนด์ จึงมีข้อดีคือ ใช้งานควบคู่กันได้หรือกลับไปใช้ Git ได้ง่าย
- มีความสามารถอย่าง stacked diff, rebase ที่ทำได้ง่าย, และ revision ชั่วคราว ให้ใช้งานได้อย่างเป็นธรรมชาติ
- ใช้แนวคิด Bookmarks แทน Branch ซึ่งเข้าใจได้ตรงกับเวิร์กโฟลว์การทำงานจริงมากกว่า
- วิธีจัดการ conflict มีความยืดหยุ่น และช่วยให้งานจัดการเวอร์ชันในชีวิตประจำวันง่ายขึ้นมาก
Elevator Pitch
Jujutsu (jj) เป็นระบบควบคุมเวอร์ชันที่ให้ mental model และ command-line interface ที่เรียบง่ายกว่า Git มาก
โดยไม่ต้องแลกกับความสามารถที่ลดลง และในความเป็นจริงอาจมองได้ว่าทรงพลังกว่าด้วยซ้ำ
ความสามารถอย่าง stacked diff, rebase ที่ทำได้ง่าย, และ revision ชั่วคราว ทำงานได้อย่างเป็นธรรมชาติ
เพราะใช้ Git เป็นแบ็กเอนด์ จึงสามารถเริ่มใช้งานควบคู่กับ Git repository ได้ด้วยคำสั่งเพียงบรรทัดเดียว และกลับไปใช้ Git เมื่อไรก็ได้
ทั้งยังไม่ส่งผลกระทบต่อวิธีที่ผู้ใช้อื่นจัดการกับ repository นั้น
Getting Started
- หลังติดตั้งเครื่องมือบรรทัดคำสั่ง
jjแล้ว แนะนำให้ตั้งค่าข้อมูลผู้ใช้และ shell auto-completion - หากจะใช้กับ repository เดิม การ clone ใหม่หรือเริ่มใช้งานในสถานะที่ไม่มีการเปลี่ยนแปลงจะเหมาะกว่า
- ใน repository เดิม สามารถใช้คำสั่ง
jj git init --colocate .เพื่อสร้าง Git และ Jujutsu repository แบบใช้งานคู่กันได้ - ข้อมูลของ
jjrepository จะถูกเก็บไว้ในโฟลเดอร์.jj/แยกจาก.gitของ Git - โดยทั่วไปการซิงก์ข้อมูลระหว่าง Git และ Jujutsu ทำงานได้โดยไม่มีปัญหา
- แต่ต้องระวังว่า คำสั่ง
git clean -fdxจะลบโฟลเดอร์.jj/ออกไป - การตั้งค่า remote branch tracking ก็สามารถทำได้พร้อมกันด้วยคำสั่งดังกล่าว
How To Use It
command-line interface ของ Jujutsu แคบกว่าและกระชับกว่า Git
แม้แนวคิดพื้นฐานจะเรียบง่าย แต่เวิร์กโฟลว์ก็ยังต้องใช้เวลาปรับตัวเล็กน้อย
ส่วนนี้จะอธิบายวิธีใช้งานหลักด้วยขั้นตอนสั้น ๆ และตัวอย่าง
Starting A New Revision
- งานใหม่ใน Git มักเริ่มจากการสร้าง branch แต่ Jujutsu ใช้วิธีสร้าง revision ใหม่
- อัปเดตสถานะล่าสุดจาก remote repository:
jj git fetch - ตรวจสอบ history ของ repository:
jj log - revision ใน history จะถูกแยกด้วย revision ID เฉพาะของ Jujutsu และ Git commit hash
- เริ่มงานใหม่ด้วย
jj new mainเพื่อสร้าง revision ใหม่บน main ปัจจุบัน - revision ที่กำลังแก้ไขอยู่จะระบุด้วยสัญลักษณ์
@ - หาก prefix เดียวกันหมดไป prefix แบบสั้นของ revision ID ก็จะเปลี่ยนตามไปด้วย
Making Changes
- เมื่อแก้ไขไฟล์ การเปลี่ยนแปลงจะ ถูกรวมเข้า revision นั้นทันที (ไม่มี staging area แยกต่างหาก)
- เมื่อแก้ไขเสร็จแล้ว ให้เพิ่มข้อความให้ revision ด้วย
jj describe -m "ข้อความ" - เมื่อต้องการสร้าง revision ใหม่ ใช้
jj new(หรือระบุ revision ก่อนหน้า) jj commitเป็นการทำงานแบบผสมระหว่างjj describe+jj new
Navigating
- revision ว่างที่สร้างด้วย
jj newจะถูกทิ้งอัตโนมัติเมื่อย้ายออกจากมัน - ลบ revision แบบระบุชัดเจน:
jj abandon <rev ID> - ย้อนการลบ:
jj op undo - กลับไปยัง revision เดิม ใช้
jj edit <rev ID> - ขณะอ้างอิง revision ยังสามารถใช้ revset expressions ได้ด้วย:
@: revision ปัจจุบันx-: parent revisiony+: child revisionz::: ลูกหลานทั้งหมดของ z
Branches (Bookmarks)
- Jujutsu ไม่มีสถานะแบบ “อยู่บน branch” เหมือน Git
- แต่ Bookmarks เป็นเพียง pointer ที่ชี้ไปยัง revision ใด revision หนึ่ง
- สร้าง bookmark ใหม่:
jj bookmark create <ชื่อ> -r <revision> - แม้จะ commit แล้ว bookmark จะไม่เลื่อนตามอัตโนมัติ ดังนั้นหากต้องการต้องย้ายเองด้วย
jj bookmark move <ชื่อ> --to <revision> - ตอน push หากต้องการยอมรับการสร้าง remote branch ใหม่ ให้ใช้แฟลก
--allow-new - หาก bookmark ต่างจากฝั่ง remote จะมีเครื่องหมาย
*แสดงไว้ และสามารถซิงก์ด้วยjj git push
Conflicts
- วิธีจัดการ conflict ของ Jujutsu ยืดหยุ่นกว่า Git
- เมื่อเกิด conflict จะมีเครื่องหมาย ‘conflicted’ แสดงบน revision นั้นและ revision ลูกหลาน
- ไฟล์ที่ conflict จะมี conflict marker ถูกแทรกไว้ และสามารถแก้ไขได้ด้วยการลบ marker เหล่านั้นออก
- จะเลือกแก้ไขโดยตรง หรือแก้ใน revision ใหม่แล้วค่อยรวมด้วย
jj squashก็ได้
บทสรุป
เท่านี้ก็เป็นแนวทางในการจัดการงาน 80% ที่พบบ่อยที่สุดใน Git ให้เรียบง่ายขึ้นด้วย Jujutsu
ต่อไปจะมีการจัดทำคู่มืออ้างอิงแบบ Quick Reference สำหรับการใช้งานทั่วไปและขั้นสูง
รองรับคำสั่ง jj status เช่นเดียวกับ Git
หากมีคำถามหรือข้อเสนอแนะสามารถติดต่อได้ทางอีเมลที่ระบุในบทความ
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
มีจุดหนึ่งที่อยากเน้นสำหรับคนที่กำลังชั่งใจว่า jj คุ้มค่ากับการเรียนรู้ไหม
พอพูดถึง jj บน Hacker News คนจะถูกแบ่งเป็นสองกลุ่ม: คนที่ยังไม่เคยลอง กับคนที่เชียร์แบบสุดตัว
แทบไม่เคยเห็นใครที่ลองใช้ jj อยู่หนึ่งสัปดาห์แล้วกลับไปใช้ git อีก
คนที่ได้ลองใช้อย่างจริงจังเกือบทั้งหมดก็ตั้งหลักอยู่กับ jj กันไปเลย
หวังว่าวันนี้จะเป็นจุดเริ่มต้นให้คุณได้ลองใช้ jj
การย้ายไปใช้มันง่ายกว่าที่คิดมาก และผมก็ยังรักษาประสิทธิภาพการทำงานได้ตั้งแต่วันแรก โดยภายในหนึ่งสัปดาห์ไม่ต้องกลับไปใช้คำสั่ง git เลย
ผมทำงานได้มีประสิทธิภาพขึ้นในเวลาไม่นาน และยังอดแปลกใจไม่ได้ว่าเมื่อก่อนใช้ git กันมาได้อย่างไร
สำหรับผม git ไม่ได้สร้างความลำบากด้านประสิทธิภาพการทำงานเลย
ผมไม่ได้ใช้คำสั่ง git หนัก ๆ ทุกวัน และโดยมากมันก็ไม่ได้เป็นอุปสรรคต่อการทำงาน
ถ้าคุณต้องจัดการ repo ด้วย git เยอะมาก jj อาจดีกว่า แต่กรณีของผมไม่ใช่แบบนั้น
มันคล้ายกับการชวนให้ลองใช้ bim ที่เกือบเหมือน vim มากแต่มีฟีเจอร์เพิ่มเข้ามา
แต่ผมไม่ได้สนใจว่าจะต้องกด "i" เพิ่มอีกไม่กี่ครั้ง และก็ไม่ต้องการระบบเติมโค้ดอัตโนมัติของ julia
ถ้าใครคิดว่า jj ดีกว่าก็ขอให้ใช้อย่างมีความสุข
jj ถือว่าเป็นพัฒนาการของ UI สำหรับ VCS อย่างชัดเจน แต่ถ้าเป็นผู้ใช้ git ระดับสูงก็ยังมีข้อจำกัดบางอย่าง
การไม่รองรับ gitattributes ทำให้ใช้งานลำบากหากต้องพึ่งฟิลเตอร์อย่าง git-crypt หรือ git-lfs
ความเข้ากันได้บน Windows เช่นเรื่องการจัดการตัวจบบรรทัดก็อาจด้อยลง
อีกทั้งเครื่องมือภายนอกอย่าง git-annex หรือ git-bug ก็ไม่ผสานกับ oplog และอาจทำให้ history ยุ่งเหยิงได้
ผมเองเคยลองใช้จริงเกินหนึ่งสัปดาห์แล้วก็กลับไปใช้ git
โดยส่วนตัวผมชอบ workflow ของ staging area มากกว่า แม้ว่าคนส่วนใหญ่จะไม่ชอบ git staging แต่สำหรับผมข้อดีนั้นไม่ได้มากพอให้ทิ้งมันไปอยู่กับ jj
ผมอาจเปลี่ยนนิสัยได้ แต่ตอนนี้ยังไม่จำเป็นต้องผูกตัวเองกับ jj
แต่ก็ยังเปิดใจว่าจะกลับไปลองใหม่สักวัน
ผมใช้ jj อยู่หลายเดือนก่อนจะกลับไปหา git เพราะปัญหาเรื่องประสิทธิภาพ
การทำงานต่าง ๆ ใน jj ใช้เวลาหลายวินาที ขณะที่ git ตอบสนองทันทีไม่ว่าโปรเจกต์จะใหญ่แค่ไหน
อีกอย่างคือพอใช้ jj แล้วรู้สึกว่ามันเพิ่มภาระทางความคิดขึ้นนิดหน่อย พอกลับมาใช้ git ก็รู้สึกโล่งขึ้นมาก
เรื่องนี้อาจเป็นเพราะประสบการณ์การใช้ git ระยะยาวของผมเองก็ได้
การพูดว่า “ยังไงก็มีแค่สองกลุ่ม” ฟังดูเป็นประโยคแบบที่พวกนักเผยแพร่ jj ชอบพูดกันมาก
สิ่งที่ผมไม่ชอบใน jj คือการที่การเปลี่ยนแปลงทุกอย่างถูก staging อัตโนมัติเสมอ
ระบบแบบ SVN ก็เคยเป็นอย่างนั้น และผมรู้สึกว่า git ปรับปรุงเรื่องนี้ได้มากเพราะต้อง staging แบบชัดเจน
ใน repo มักจะมีการเปลี่ยนแปลงมากกว่าสิ่งที่อยากใส่ใน commit ถัดไปอยู่เสมอ และใน git การเลือกเฉพาะสิ่งที่จะใส่จึงเป็นเรื่องปกติ
แต่ใน jj (รวมถึง SVN) กลับต้องใช้วิธีจัดการด้วยมือที่ยุ่งยาก เช่น ย้ายการเปลี่ยนแปลงออกไปชั่วคราวก่อน commit
ประเด็นนี้สำหรับผมก็เป็น dilemma เหมือนกัน
staging น่ารำคาญเสมอจนแม้แต่ตอนใช้ Mercurial ก็ยังลำบาก
ถ้าเคสกว่า 90% ต้อง auto add มันกลับสะดวกกว่า แต่ปัญหาคือไฟล์ที่ใส่ใน
.gitignoreไม่ได้จะปิด auto add ก็ลำบาก จะเปิดไว้ก็ก้ำกึ่ง
ไม่มีทางไหนที่สะอาดหมดจดจริง ๆ
workflow ของ JJ ต่างออกไปนิดหน่อย เช่น คุณอาจสร้าง base commit ก่อน แล้วซ้อน anonymous commit ไว้ด้านบนเพื่อทำงาน
พอพร้อมแล้วค่อยจัดระเบียบด้วย
jj squashหรือjj splitผมใช้
jj commit -i, ตัวเลือก-iของหลายคำสั่ง และตั้งค่าsnapshot.auto-track="none()"ใน configตอนใช้ Mercurial ผมก็ทำคล้ายกัน
จริง ๆ แล้วถ้าใช้ฟีเจอร์ absorb บ่อย ๆ ไฟล์หรือ chunk ที่ไม่จำเป็นก็มักจะถูกมองข้ามให้อัตโนมัติ
คำสั่ง “jj new” ไม่น่าจะเหมาะกับ workflow ที่คุณต้องการหรือ?
jj ติดตาม branch ที่ไม่ใช่ head บน tree ได้อย่างถูกต้องด้วย จึงทำให้ rebase และ merge ทำงานได้ลื่นโดยไม่ต้อง stash
มันปรับตัวยากกับการที่มีการเพิ่มการเปลี่ยนแปลงอัตโนมัติ
บางครั้งในเครื่อง local ผมแก้ไฟล์บางไฟล์ชั่วคราวระหว่างพัฒนา โดยไม่ได้ตั้งใจจะ commit มัน
ใน git ถ้าไม่ staging มันก็ไม่มีทางถูก commit หรือ push จึงอุ่นใจได้
แต่ใน jj มันให้ความรู้สึกว่าต้อง unstage อะไรบางอย่างหรือระวังเป็นพิเศษ
อาจเป็นแค่เรื่องความเคยชิน แต่สำหรับผมการระบุให้ชัดว่าจะ commit อะไรบ้างสบายใจกว่า
เลยสงสัยว่าผมเข้าใจ jj ผิดไปหรือเปล่า
ใน jj คุณสามารถใช้
jj splitเพื่อแยกการเปลี่ยนแปลงได้สิ่งที่เลือกจะไปอยู่ใน revision แรก ส่วนที่เหลือจะไปอยู่ใน revision ที่สอง
ถ้าคุณทำหลายอย่างพร้อมกันแล้วค่อยแบ่งเป็น revision คำเล็ก ๆ ภายหลัง มันง่ายกว่า git มาก
คุณสามารถสร้าง revision ใหม่ (
jj new) แบบเดียวกับ git แล้วค่อยแก้ จากนั้นใช้jj squash -iเพื่อย้ายเฉพาะส่วนที่ต้องการได้พอดีในเชิงแนวคิด “@” คือ revision ปัจจุบัน และ “@-” คือหนึ่งขั้นก่อนหน้า จึงคิดได้คล้าย working copy/stage ของ git
auto staging ของ jj ไม่ได้ดีเสมอไป
อยากให้เอกสารทางการของ jj และคนที่สอนมือใหม่บอกให้ชัดกว่านี้ว่าค่าเริ่มต้นสามารถปิดได้ง่าย
ใน
~/.jjconfigให้เขียนว่า[snapshot]
auto-track = "none()"
เท่านี้ก็พอ
ปกติผมจะใช้
jj splitหลังทำงานเสร็จเพื่อ review และจัดระเบียบว่าจะ commit อะไรบ้างworkflow นี้เคลื่อนไหวคล้าย
add -pของ gitcommit บนสุดมักใช้เสมือนเป็น working copy ที่ไม่ push
และสลับ branch ได้โดยไม่ต้อง stash โดยเนื้อหาที่ทำค้างไว้ยังถูกเก็บไว้อย่างดี
ใช่เลย นิสัยแบบนั้นของผมก็เปลี่ยนยากเหมือนกัน
เหตุผลที่พอฟังขึ้นสำหรับการเปลี่ยนมันคือ เราไม่ควรรันโค้ดในสถานะ untracked
การเก็บเฉพาะการเปลี่ยนแปลงที่มีความหมายไว้ใน commit และไม่บันทึกที่เหลือจะปลอดภัยกว่า
ปัญหาคือเวลาการตั้งค่าระดับทั้ง repo กับการตั้งค่าเฉพาะเครื่องแยกจากกันไม่ได้ ซึ่ง VSCode เป็นตัวอย่างชัดเจน
ในกรณีแบบนี้จึงจำเป็นต้องมีการเปลี่ยนแปลงที่ไม่ควรถูก commit ตามสภาพแวดล้อม ทำให้ยิ่งซับซ้อนขึ้น
ถ้าคุณอยากได้ workflow แบบนี้ ให้คิด “@” ของ jj เป็นเหมือน git index แล้วตอน commit ค่อย squash ไปที่ “@-” ก็จะได้ผลใกล้เคียงกับ
git add --patchผมพยายามเปลี่ยนทีมให้ใช้ jj แต่ยังไม่สำเร็จ
คงจะดีถ้ามีหน้าที่แสดงให้เห็นแบบเร็ว ๆ ว่างานซับซ้อนใน git ทำใน jj ได้ง่ายแค่ไหน
เหมือน elevator pitch แบบสั้น ๆ
ผมเองก็คิดว่าคงต้องเดโมให้ดูด้วยตัวเอง
สำหรับงาน git ที่คนส่วนใหญ่ใช้กันบ่อย ๆ หลายอย่าง ดูเหมือนว่าจะไม่ได้ง่ายกว่าใน jujutsu
แต่ jujutsu มี workflow ใหม่ ๆ ที่ใน git ทำไม่ได้หรือทำได้ยาก
ซึ่งสิ่งนี้อาจไม่โดนใจนักพัฒนาที่คุ้นกับ git แบบเดิมอยู่แล้ว
ผมเองก็ไม่ได้ชอบ git เป็นพิเศษ
เมื่อก่อนใช้แต่ mercurial แต่ตอนนี้ git ฝังอยู่ในหัวไปแล้ว
ต่อให้ Jujutsu มีข้อดีชัดเจนบางอย่าง ผมก็ยังไม่รู้สึกว่ามันดึงดูดพอจะไปใส่ใจกับการตั้งค่าเริ่มต้นทั้งหมด เช่น ตั้งค่าสีที่ซับซ้อนหรือสคริปต์ที่คุ้นมือ
สำหรับผม การได้เห็นการเปรียบเทียบงานหนึ่งอย่างระหว่าง jj กับ git ช่วยให้เข้าใจมากขึ้นมาก
https://lottia.net/notes/0013-git-jujutsu-miniature.html
ขอแนะนำลิงก์ที่มีประโยชน์อีกหลายอัน
https://v5.chriskrycho.com/essays/jj-init/
https://v5.chriskrycho.com/journal/jujutsu-megamerges-and-jj-absorb/
https://ofcr.se/jujutsu-merge-workflow
เนื้อหาถัดไปที่ผมกำลังจะเพิ่มในโพสต์นี้น่าจะเป็นสิ่งที่คุณชอบ
อีกไม่นานจะลงไว้ทั้งท้ายหน้าและแยกเป็นอีกโพสต์หนึ่งต่างหาก
ผมใช้ jj มาหลายสัปดาห์แล้ว ถึงขั้นทำสคริปต์ข้อความ commit อัตโนมัติขึ้นมา
วันนี้ผมพยายามพอร์ตสคริปต์เดียวกันไปใช้กับ git repo เก่าตัวหนึ่ง แล้วก็เพิ่งตระหนักว่าใน git ต้องมีโค้ดไว้ตรวจจับอัตโนมัติว่านี่คือจังหวะ commit หรือ amend
แต่ใน jj สคริปต์เรียบง่ายมากเพราะโครงสร้าง commit แบบ immutable
สุดท้ายก็ clone repo ใหม่ด้วย jj ไปเลย
หลุดพ้นจากความสับสนระหว่าง commit กับ amend ได้แทบจะทันที
https://codeberg.org/jcdickinson/nix/src/branch/main/home/common/scripts/jj-auto.fish
git ทำงานได้ดีเพียงพออยู่แล้ว
มันมี learning curve อยู่บ้าง แต่พอเข้าใจแล้วทุกอย่างก็สมเหตุสมผล
พูดตามตรง ใน 95% ของสถานการณ์ แค่รู้
pull,add,reset,branch,commitก็เพียงพอแล้วใน workflow ของผม stacked diff เป็นของจำเป็น
มันช่วยให้ผมไม่ติดคอขวดระหว่างรอ review และยังซ้อนงานในอนาคตไว้ก่อนได้
การตั้งค่าใน git ไม่ได้ยาก แต่ถ้าต้องเพิ่มการเปลี่ยนแปลงลงไปที่ชั้นล่างของสแตกแล้ว restack ทั้งหมด นั่นคือฝันร้ายจริง ๆ
ถ้าทำงานร่วมกับคนอื่น การเข้าใจ rebase/squash เป็นสิ่งจำเป็น
ต่อให้ไม่อยากใช้ก็เลี่ยงไม่ได้จนกว่าจะโน้มน้าวให้ทั้งทีมเลิกใช้มัน
โดยเฉพาะเวลาเร่งพัฒนากันหลายคนบน branch เดียว นิสัยแบบ git จะเริ่มกลายเป็นความอึดอัด
โดยพื้นฐานมันใช้งานสะดวก แต่พอเจอสถานการณ์ซับซ้อนก็มีปัญหาเยอะ
แค่ได้เจอสถานการณ์แปลก ๆ ไม่กี่ครั้งก็จะเห็นจุดอ่อนของ git แล้ว
ผมใช้ jj มาได้ประมาณ 2 สัปดาห์ และเป็นครั้งแรกที่รู้สึกสบายใจกับการจัดการเวอร์ชันผ่าน command line ล้วน ๆ
ตอนใช้ git ผมต้องพึ่ง GUI (Git Graph ใน VSCode) แล้วคลิกขวาเป็นหลักตลอด
แต่กับ jj แค่อ่าน tutorial อย่างเดียวก็เข้าสู่ command line ที่มีความสอดคล้องได้ทันที
อย่างไรก็ตาม ถ้าอยากเลิกคอย copy-paste id ใน log ของ jj คงต้องเรียนรู้ภาษา revset
ผมก็คล้ายกัน
ใช้ git มานาน แต่เรื่องซับซ้อนมักจัดการผ่าน UI ตลอด
เกือบหนึ่งเดือนมานี้ผมใช้แค่ jj CLI และค่อนข้างพอใจมาก
แต่อย่างหนึ่งคือเอกสารทางการของ jj เขียนโดยสมมติว่าผู้อ่านมีพื้นฐานอยู่แล้ว ทำให้มือใหม่สับสนได้ง่าย
หวังว่าจะมีบล็อกและ tutorial เพิ่มขึ้น
ผมเองก็อยากเรียนรู้ภาษา revset กับ rebase ให้มากขึ้น
ชอบทั้ง cli ที่กระชับ การแก้ conflict และ oplog
ผมก็เคยรำคาญเรื่องการคัดลอกวาง id เหมือนกัน แต่พอใช้ jjui(https://github.com/idursun/jjui) แล้วลื่นขึ้นมาก
มันทำให้ทำงานได้เร็วเหมือนกำลังกวาดตาดู log อยู่
ผมคิดว่าฟีเจอร์ที่ดีที่สุดของ jj คือ undo
ใน git การ undo ทำได้ยากเพราะขึ้นกับว่าคุณพลาดแบบไหนและต้องใช้คำสั่งต่างกัน
แต่ jj แค่
jj undoครั้งเดียวก็จบและมันไม่ได้ผูกกับระบบ backend ใด ๆ จนทำให้ถึงคุณจะใช้ jj คนเดียวในเครื่อง local ก็ไม่กระทบเพื่อนร่วมทีม
ผมยังสับสนว่า jj คืออะไรกันแน่
มันเป็น frontend สำหรับคนที่สับสนกับ git หรือเปล่า
แม้จะบอกว่า abstract backend ได้ แต่ก็ได้รับอิทธิพลจาก git มากเกินไป จนผมนึกภาพไม่ออกว่ามันจะเข้ากับระบบที่บังคับให้ commit มีเลขลำดับต่อเนื่องอย่าง Perforce หรือ Piper ได้อย่างไร
แนวคิด working copy = commit ดูเหมือนทำ quality control ไม่ได้
ความหมายดั้งเดิมของ commit คือการใส่เฉพาะสิ่งที่ตั้งใจจริง ๆ แต่โครงสร้างแบบนี้กลับทำให้แยก “ขยะ commit” ได้ยากขึ้น
ทั้ง git และ jj ดูจะอ่อนแอกับโปรเจกต์ขนาดใหญ่ และยังแก้ปัญหา commit กระจัดกระจายไม่ได้
ผมเลยสงสัยว่า jj แก้ปัญหาอะไรอยู่กันแน่ หรือมันเป็นแค่ frontend ตามรสนิยมของผู้เขียน
backend ของ Piper กลับทำงานได้เป็นธรรมชาติกว่า backend ของ Git เสียอีก
commit ของ jj ไม่ได้ตรงกับ commit ของ git แบบหนึ่งต่อหนึ่งสมบูรณ์ ดังนั้นไม่ต้องเข้าใจผิด
จริง ๆ แล้วเวลาเรียก “commit” มันใกล้กับแนวคิด “diff ที่มีชื่อ” มากกว่า และก่อน push ก็สามารถรื้อและจัดระเบียบการเปลี่ยนแปลงใหม่ได้ง่ายเสมอ
มันสะดวกกว่า rebase หรือการแก้ history ใน git มาก
ผมมักสร้างหลาย commit ระหว่างทำงาน เช่น สำหรับการทดลองหรือเอกสารต่าง ๆ ซึ่งถ้าเป็น git ก็คงต้องยัดลง stash หรือ branch ชั่วคราวแบบฝืน ๆ
jj เป็นมากกว่า frontend ของ git
มันคือระบบ version control และเป็น backend-agnostic
backend หลักที่เด่นที่สุดคือ git จึงทำให้สลับไปใช้กับ repo เดิมได้ทันที
ผมเป็นผู้ใช้ git มาตั้งแต่ก่อน GitHub จะออกด้วยซ้ำ แต่พอใช้ jj แล้วก็กลับไปหา git ไม่ได้อีก
jj ทั้งเรียบง่ายกว่าและทรงพลังกว่า
แนวคิด working copy = commit จริง ๆ ควรเข้าใจประมาณว่า “index ก็เป็น commit แบบหนึ่ง”
เช่น เวลาจะเริ่มทำ feature x ก็ใช้
jj new -m "working on feature x" trunkเพื่อสร้าง commit ใหม่ แล้ววาง commit เปล่าอีกอันไว้ด้านบนงานที่กำลังทำจะอยู่ใน working copy (
@) แล้วค่อย “ย้าย” (squash) ไปยัง commit ก่อนหน้า (@-) แทนที่จะใช้ตัวเลือกซับซ้อนของ git อย่าง add-p หรือ reset โดยให้ทุกอย่างถูกจัดการผ่าน diff ระหว่าง commitโครงสร้างนี้ทำให้การแยกและจัดระเบียบ commit ยืดหยุ่นและทรงพลังกว่า git index
ส่วนปัญหา commit กระจัดกระจายนั้นใกล้เคียงกับวัฒนธรรม pull request มากกว่า ซึ่ง jj ก็ช่วยได้เพียงบางส่วนเท่านั้น
working copy ไม่ได้ถูก push ขึ้น GitHub แบบส่งเดช และสามารถค่อย ๆ review/จัดระเบียบตอนใส่คำอธิบาย commit ได้
ผมลองใช้ jj อยู่ไม่กี่วัน แต่ยังพอใจกับ lazygit เดิม รวมถึง workflow และชุดสคริปต์ที่ตั้งไว้แล้ว
jj มีอะไรใหม่ ๆ ที่น่าสนใจและก็ใช้ได้ดี แต่ถ้าไม่ได้เพิ่งเริ่มต้นกับ version control ก็คงยังไม่มีแรงจูงใจมากพอให้เปลี่ยน
ผมยังใช้ diff ของ Lazygit อยู่เหมือนเดิม แต่ถึงจะอยู่ในสถานะ detached HEAD ก็ไม่เป็นปัญหาเลย
JJ เข้ากับ git ได้ดีมาก และช่วยให้จัดการทุกอย่างได้ง่ายกว่ามากโดยไม่ต้องท่องจำคำสั่งซับซ้อน
การที่ไฟล์ที่ยังไม่ commit เคลื่อนตามไปด้วยอัตโนมัติเวลาสลับ branch คือฟีเจอร์ที่ดีที่สุด
มันทำให้สลับไปมาระหว่างการพัฒนา แก้บั๊ก แก้ข้อความ ได้สะดวกมาก
ถ้า AI agent เป็นคนแก้ไฟล์ ก็แค่แยก worktree ออกไปใช้
และการที่ใส่คำอธิบายการเปลี่ยนแปลง (=commit message) ไว้ล่วงหน้าก่อนงานเสร็จแล้วเห็นได้เลยบน tree ก็ยอดเยี่ยมมาก
โดยรวมแล้ว JJ ยอดเยี่ยมมากจริง ๆ