Jujutsu - Hệ thống quản lý phiên bản phân tán tương thích Git, đơn giản nhưng mạnh mẽ
(github.com/martinvonz)- Jujutsu là một hệ thống quản lý phiên bản dùng để sao chép mã, theo dõi thay đổi và công bố thay đổi trong các dự án phần mềm, được thiết kế để dễ sử dụng cho cả người mới lẫn người có kinh nghiệm, cũng như cho cả dự án cá nhân mới và đội nhóm lớn với lịch sử phát triển đồ sộ
- Hệ thống này tách biệt nội bộ giữa giao diện người dùng và thuật toán quản lý phiên bản với hệ thống lưu trữ cung cấp nội dung; hiện tại sử dụng kho Git làm tầng lưu trữ nên tương thích với các công cụ dựa trên Git
- Trong Git chỉ lưu commit và file; bookmark (branch) và các siêu dữ liệu cấp cao khác được lưu trong một kho tùy biến nằm ngoài Git
- Backend Git mặc định sử dụng thư viện Rust gitoxide; có thể lấy branch từ kho Git từ xa, push lên remote và tạo các commit trông như commit Git thông thường
- Sử dụng mô hình working-copy-as-a-commit để biểu diễn bản sao làm việc dưới dạng commit thực; thay đổi file được tự động ghi lại thành commit thường và sau đó được amend mỗi khi có thay đổi mới
- Lệnh không bị thất bại vì working copy đang dirty
- Không cần
git stash - Có thể đặt commit message cho commit của working copy ngay cả trước khi công việc hoàn tất
- Mọi thao tác trong kho đều được ghi lại kèm snapshot trạng thái kho sau thao tác đó, cho phép khôi phục trạng thái kho trước đó, undo theo từng thao tác và revert một thao tác cụ thể không nhất thiết phải là thao tác mới nhất
- Xung đột được ghi lại như một đối tượng hạng nhất tương tự commit, nên thao tác phát sinh xung đột vẫn thành công và có thể được xử lý sau đó bằng một quy trình giải quyết xung đột thống nhất
- Khi sửa một commit, toàn bộ descendant của commit đó sẽ tự động được rebase lên trên commit mới; kết quả giải quyết xung đột cũng được lan truyền tới các descendant, đồng thời bookmark và working copy trỏ tới các commit đã rebase cũng được cập nhật
- Không có index hay staging area tường minh; việc chọn commit dùng ngôn ngữ revset, còn định dạng đầu ra được xử lý bằng ngôn ngữ template do người dùng cấu hình
- Cung cấp các tính năng viết lại lịch sử như
jj describeđể sửa message của commit bất kỳ,jj diffeditđể chỉnh sửa thay đổi của commit mà không cần checkout,jj splitđể tách commit, vàjj squash -i --from X --into Yđể chuyển một phần thay đổi sang commit khác - Tính năng sao chép đồng thời an toàn hiện đang ở mức thử nghiệm; được thiết kế để tránh làm kho rơi vào trạng thái hỏng khi dùng hệ thống file phân tán hoặc công cụ sao lưu như Dropbox hay
rsync, và trong tình huống xấu nhất hướng tới việc chỉ bộc lộ xung đột giữa trạng thái cục bộ và từ xa jjlà một hệ thống quản lý phiên bản thử nghiệm; khả năng tương thích với Git đã ổn định, nhưng vẫn có thể còn các tính năng đang phát triển, UX chưa tối ưu và khoảng trống trong workflow ở một số cách sử dụng nhất định- Tính năng nhìn chung đã khá hoàn thiện, nhưng hỗ trợ Git submodule vẫn chưa xong, còn nhiều lỗi hiệu năng và chưa có hỗ trợ native cho workflow dựa trên email
- Trước phiên bản 1.0.0 sẽ còn có thay đổi workflow và các thay đổi không tương thích ngược đối với định dạng lưu trên đĩa; với các thay đổi định dạng, dự án sẽ cố gắng cung cấp nâng cấp minh bạch hoặc lệnh/script nâng cấp khi được yêu cầu
- Đây là phần mềm mã nguồn mở theo giấy phép Apache 2.0, không phải sản phẩm được Google hỗ trợ và việc hỗ trợ được cung cấp bởi cộng đồng
2 bình luận
Jujutsu - hệ thống DVCS tương thích Git đơn giản và mạnh mẽ
Tôi đã đăng bài này từ một năm rưỡi trước, giờ lại thấy nó trở thành chủ đề nổi bật trên HN.
Ý kiến trên Hacker News
Rất vui khi thấy nó được đăng ở đây. Tôi đã chuyển sang jj khoảng 2–3 tuần trước và không có ý định quay lại. Phải thay đổi khá nhiều cách làm việc trong đầu, nhưng tôi khá thích luồng mà
jjcung cấpKhông còn phải dành thời gian nghĩ riêng xem sẽ commit gì; mọi thay đổi trong file đều tự động được phản ánh vào commit bản sao làm việc. Tất nhiên cũng có lúc không muốn như vậy, nên có các chức năng để tách commit thành hai hoặc di chuyển thay đổi, và tôi thích điểm mọi thao tác đều hoạt động trên commit
jj logrất tuyệt để xem toàn bộ bản đồ của nhiều branch; có thể chỉ giải quyết một phần conflict rồi chuyển sang branch khác; và ID changeset rút gọn cũng tiện. Ví dụ, trongjj logcó thể xem changeset cần rebase rồi chạy kiểujj rebase -s qr -d master, nhanh hơn việc gõ đầy đủ tên branchTài liệu nói có thể dùng với backend như Dropbox, nhưng tôi mong sẽ có một hệ thống dễ dùng với IPFS. Với dữ liệu lớn, không thể lưu 1TB trên GitHub, còn LFS thì tính phí nên tôi loại ra
Những người muốn dùng dataset dù sao cũng sẽ có nó ở local, nên IPFS, nơi nguồn tải xuống không phải là một mà là hàng nghìn, là lời giải tự nhiên. Nếu dùng IPFS cho kho dữ liệu thì tôi sẽ chuyển ngay, còn nếu không thì tôi nghĩ không đáng để xem xét nhiều
Jujutsu bắt đầu là dự án cá nhân của tác giả, và hiện đã trở thành dự án toàn thời gian của tác giả tại Google. Nó từng được trình bày tại Git Merge 2022
Jujutsu: A Git-Compatible VCS - Git Merge 2022:
Video:
https://youtu.be/bx_LGilOuE4
Slides:
https://docs.google.com/presentation/d/1F8j9_UOOSGUN9MvHxPZX...
Tôi đã dùng jj hằng ngày trong gần 1 năm và thấy chắc chắn tốt hơn nhiều so với trải nghiệm người dùng của Git. Tôi khá nhạy cảm với việc chia thay đổi thành các commit nguyên tử, nên rebase tự động là tính năng cốt lõi
Vì có thể ghi conflict vào commit, nên không cần dừng giữa chừng khi rebase để sửa conflict như Git hay Mercurial. Dù sửa hoặc xóa commit, jj sẽ tự động rebase tất cả commit hậu duệ, và khác với Git rebase, nó cũng xử lý nhiều commit con giống Mercurial evolve
Các lệnh cơ bản để thao tác với lịch sử commit cũng tốt. Dùng
jj move|restoređể chuyển hoặc sao chép thay đổi của một commit sang commit khác,jj splitđể tách commit, vàjj rebaseđể di chuyển commit. Vì mọi thứ đều nằm trong lịch sử commit, không có working tree hay index, nên có thể xử lý bằng cùng các lệnh và flagNhật ký thao tác cũng rất tuyệt, nên có thể hoàn tác hầu hết công việc mà không gặp vấn đề. Điều này trái ngược với Git, nơi để sửa một rebase tệ hoặc
commit --amend, bạn phải lục tìm đúng commit trong reflog rồi sửa ref thủ côngĐiểm bất tiện nhất là commit bản sao làm việc tự động đôi khi cố commit cả những file không mong muốn, và vì không có phát hiện đổi tên, nên xử lý merge không thanh nhã bằng Git. Dù vậy, commit bị hỏng có thể sửa tương đối dễ bằng
jj split|restore, và các nhà phát triển jj cũng đang suy nghĩ về vấn đề đổi tênTôi thích việc ngay cả khi kết quả thao tác sinh ra conflict, nó vẫn ghi thông tin đó vào commit và coi thao tác là thành công, rồi có thể giải quyết conflict sau. Khoảng 10 năm qua tôi đã làm việc với các thuật toán chỉnh sửa cộng tác, và lý tưởng thì các công cụ như Git cuối cùng nên được thay thế bằng cách tiếp cận dựa trên CRDT
Dùng CRDT thì có thể pair programming bằng cùng một công cụ, và cũng xử lý tốt hơn các kiểu merge phức tạp như self-conflict có thể xảy ra trong Git. Nó cũng là một mô hình mạnh hơn
Tuy nhiên, CRDT văn bản hiện đại tự động giải quyết chỉnh sửa đồng thời mà không có conflict, trong khi khi cộng tác viết code offline, ta thường muốn conflict lộ ra để con người tự giải quyết. CRDT có nhiều thông tin lịch sử chỉnh sửa hơn Git nên về lý thuyết là có thể, nhưng để làm đúng có lẽ phải đưa chính conflict vào mô hình dữ liệu của file văn bản, và tôi không rõ nó sẽ ăn khớp với các editor hiện đại như thế nào
Nghe có vẻ jj đã tìm ra một mẹo tương tự, nên tôi mong xem thực tế nó hoạt động tốt đến đâu. Cảm giác như tiến thêm một bước tới giấc mơ về kho mã nguồn dựa trên CRDT
git bisecthay saoNếu có một bug tái hiện được và nguyên nhân phức tạp, tôi nghĩ việc tìm commit nào đã đưa bug vào rồi xem thay đổi nào là nguyên nhân là hữu ích. Ít nhất nó giúp có cảm nhận ban đầu về thứ cần sửa
Hiện tại
git bisecthoạt động tốt nhất khi mọi commit đều có thể build và chạy. Nếu có commit chứa dấu conflict khiến không build hoặc chạy được, sẽ cần can thiệp thủ công nhiều hơn rất nhiềuTôi tò mò không biết có thể điều chỉnh chức năng tương đương
git bisecttrong kịch bản này như thế nào. Chỉ quét chuỗi đánh dấu conflict có thể không phù hợp, vì tài liệu có thể đang mô tả dấu conflict, hoặc trong một số ngôn ngữ markup,=======có thể được dùng hợp lệ làm gạch chânNó có vẻ mâu thuẫn với ý tưởng rằng lịch sử quản lý mã nguồn là một sản phẩm đầu ra có ý nghĩa, và các bó patch cần được sắp xếp thành một chuỗi thay đổi tăng dần, nguyên tử trước khi rời máy phát triển
Tuy nhiên, hầu hết lập trình viên quanh tôi vốn đã xem lịch sử Git như lịch sử undo vô hạn của editor, nên cách tiếp cận này có lẽ chỉ củng cố thực tế đó
Tôi tò mò mọi người hình dung lịch sử dài hạn sẽ hoạt động thế nào, và liệu nó sẽ hữu ích hơn hay kém hữu ích hơn hiện tại
Việc bản sao làm việc được tự động commit thoạt đầu nghe có vẻ hay, nhưng có nhiều tình huống không tốt
Nếu một tệp đầu ra mới được tạo ra mà bạn chưa kịp đưa vào
.gitignorethì nó sẽ bị tự động commit; sau khi thêm tệp bị bỏ qua ở một nhánh rồi chuyển sang nhánh khác, tệp vẫn còn trong bản sao làm việc nhưng không có trong.gitignore, nên có thể bị tự động commitNgoài ra, staging chỉ một số tệp rồi commit dễ hơn nhiều so với việc tách commit về sau
Bản thân tôi cũng đã ăn sâu suy nghĩ đó trong đầu, nhưng không biết nó có thật sự đúng không. Thực tế là việc sửa index rồi amend commit sau đó diễn ra khá thường xuyên, và cũng có thể làm trước
Nếu dù sao cũng không thể tránh hoàn toàn việc chỉnh sửa sau, có lẽ một quy trình làm việc duy nhất cho các chỉnh sửa như vậy sẽ tốt hơn. Tôi chưa dùng thử, nhưng đây có vẻ là một cách tiếp cận khá thuyết phục khi đặt câu hỏi rằng những tập quán ta xem là hiển nhiên có thể thực ra không giúp ích gì
Tôi không có use case nào mà mọi tệp được tạo/sửa đổi luôn luôn đi vào commit
Việc khi chuyển sang nhánh khác, tệp vẫn còn trong bản sao làm việc nhưng lại không có trong
.gitignorelà thất bại của Git theo tôi. Nên có thứ gì đó như.local.gitignoređược bổ sung thêm vào.gitignore. Các tệp cần ignore chỉ riêng tôi dùng là chuyện rất phổ biến và không phải loại nên đưa vào.gitignorecủa dự án. Có cách làm, nhưng tất cả đều gượng gạo, nên cần được cung cấp đơn giản theo mặc địnhDù vậy vẫn thú vị. Tôi chưa từng thích staging của Git, nhưng cũng chưa gặp trường hợp được nói ở đây, nên giờ mới hiểu rằng cần có một bước trung gian giữa hệ thống tệp và commit
.gitignore, chúng sẽ lại bị loại khỏi commit bản sao làm việc ẩn danh ở lần auto-commit tiếp theoLuồng “được đưa vào commit bản sao làm việc ẩn danh rồi bị loại ra” thay vì ngay từ đầu không được thêm vào không trực quan lắm, nhưng nếu commit ẩn danh đó hầu như không hiện ra với người dùng thì có lẽ cũng không khác biệt
Tài liệu có đề cập rõ ràng đến nhiều trường hợp đáng lo ngại:
https://github.com/martinvonz/jj/blob/main/docs/git-comparis...
Ngoại trừ vài trường hợp đặc biệt, nhiều năm nay tôi hầu như không dùng Git trên dòng lệnh. Hằng ngày tôi dựa vào tích hợp sẵn trong IDE như IntelliJ, và khó hiểu vì sao phải tự chịu cảnh làm thủ công
Ngay trong editor có thể chọn theo từng dòng để commit một phần, xem tất cả nhánh, merge và cherry-pick, commit hoặc amend, pull cập nhật, chỉnh sửa tag, tất cả chỉ bằng một phím tắt
Tuy nhiên ở đây có vẻ tôi thuộc thiểu số. Nhất là khi tính đến bầu không khí kiểu Git là kỹ năng bắt buộc nên lập trình viên thật sự phải nhắm mắt cũng gõ được lệnh, tôi càng tò mò vì sao lại như vậy
Kỹ năng này không phụ thuộc môi trường: kết nối vào máy từ xa để xem repository cũng giống như local, không cần học lại cách tích hợp VCS của từng editor, và có thể dùng nguyên các công cụ quen thuộc
Những tác vụ được nêu làm ví dụ cũng có thể làm dễ dàng y như vậy trên dòng lệnh, nên tôi không thấy tích hợp editor có gì đặc biệt. Nếu cần các thao tác lạ và nâng cao kiểu đụng đến reflog, cuối cùng khả năng cao vẫn phải mở dòng lệnh
Tất nhiên tôi không có phàn nàn gì với người dùng GUI. Nếu họ năng suất với công cụ đó thì không có gì để phán xét; chỉ là bạn hỏi vì sao nên tôi trả lời, chứ không khẳng định cách của tôi tốt hơn
Đây là bối cảnh phổ biến nhất khi người ta nói “phải học Git CLI”
Vài ngày trước cũng có ví dụ dùng GitHub Desktop để khỏi phải học lệnh Git: https://www.reddit.com/r/learnprogramming/comments/15b7pra/s...
Nhờ cách tiếp cận đặt khả năng tương thích với Git lên trước, Jujutsu trông có vẻ là ứng viên thay thế Git mạnh hơn trong số những gì tôi đã thấy đến nay
Khi đọc phần giải thích về khả năng tương thích với Git, điều tôi thắc mắc là có vẻ nó chủ yếu tập trung vào trường hợp người dùng Jujutsu truy cập các kho Git được host trên GitHub, v.v. bằng jj. Ngược lại, tôi cũng tò mò liệu có hỗ trợ cách truy cập kho Jujutsu native bằng Git hay không
Vì hầu hết lập trình viên đã quen với Git CLI, trong vận hành thực tế có lẽ sẽ có các lập trình viên dùng cả jj lẫn Git trên cùng một codebase. Hoặc tôi tự hỏi liệu kịch bản vận hành thực tế có phải là luôn dùng Git làm kho lưu trữ backend thay vì cơ sở dữ liệu Jujutsu native, để cả hai CLI đều truy cập được hay không
Backend này chủ yếu tồn tại để bảo đảm rằng sau này có thể thêm các tính năng vốn không dễ thêm vào backend Git
Nếu làm việc và đóng góp cho một dự án đã dùng Jujutsu, thì việc tôi thích nghi với dự án sẽ hợp lý hơn là dự án phải thích nghi với workflow của tôi
Nhờ cách tiếp cận ưu tiên tương thích với Git, Jujutsu trông mạnh hơn trong số các ứng viên thay thế Git mà tôi đã thấy đến nay
Tôi tò mò về quản lý xung đột. Tôi biết pmeunier đã bỏ nhiều công sức để hình thức hóa lý thuyết patch cho Pijul, và các khái niệm patch/xung đột không lành mạnh hoặc có vấn đề có thể dẫn đến rắc rối lớn. Hình như vấn đề hiệu năng của Darcs cũng phát sinh như vậy
Sẽ tốt hơn nếu trang so sánh trong wiki của kho giải thích cách xử lý xung đột của Pijul chi tiết hơn một chút, thay vì chỉ nói là “tương tự”
Việc lưu trữ xung đột một cách ký hiệu như thế này cho phép tái hiện xung đột về sau và thậm chí có thể tự động giải quyết một số xung đột nhất định, nhưng không xử lý đến vấn đề giải quyết chính nội dung xung đột thực tế
Nếu có ai triển khai, có lẽ cũng có thể dùng Pijul làm backend cho jj để có được ưu điểm của cả hai bên
Sao chép an toàn qua rsync, Dropbox, hệ thống tệp phân tán nghe hay đấy. Dạo này tôi ngày càng nghiêng về các hệ thống thân thiện với đồng bộ hóa đơn giản
Vì chỉ cần ném nó vào đâu đó bằng bất kỳ công cụ nào là nó cứ hoạt động. Một công cụ mới đi theo hướng này luôn là điều đáng hoan nghênh
Tôi từng nghe nói có vấn đề như vậy nhưng chưa trực tiếp gặp phải. Tôi tò mò giữa Git và các công cụ như rsync/Dropbox sẽ phát sinh điều kiện tranh chấp nào gây ra vấn đề
Bản sao làm việc được commit tự động thì thật tốt. Đây là tính năng đã cần từ lâu
Xin vỗ tay cho Martin vì đã bỏ công sức tạo ra một công cụ thanh lịch