Jujutsu: Giải pháp cho sự mệt mỏi khi duy trì lịch sử commit "sạch đẹp"

Phần mềm24 tháng 5, 2026·3 phút đọc

Bài viết này giới thiệu một quy trình làm việc sử dụng hệ thống kiểm soát phiên bản Jujutsu để giải quyết vấn đề "mệt mỏi vì sự nghiêm ngặt của Git". Thay vì cố gắng viết commit hoàn hảo trong suốt quá trình phát triển, phương pháp này cho phép lập trình viên làm việc tự do và dọn dẹp lịch sử một cách gọn gàng vào giai đoạn cuối cùng.

Khi phát triển một tính năng lớn, việc viết những commit "tốt" là một thử thách thực sự. Một lịch sử commit lý tưởng thường được chia nhỏ theo các bước logic như: định nghĩa kiểu dữ liệu, thêm hàm cơ sở dữ liệu, xây dựng API máy chủ và cuối cùng là giao diện người dùng. Điều này giúp người review code dễ dàng theo dõi thay đổi từng phần một.

Tuy nhiên, thực tế thường diễn ra theo hướng hoàn toàn khác. Chúng ta thường rơi vào vòng lặp sửa đổi: thêm code, thử nghiệm, sửa lỗi UI, tái cấu trúc (refactor) và sửa thêm các lỗi khác. Kết quả là các commit sau ghi đè hoặc làm rối loạn công việc của các commit trước, phá vỡ tính mạch lạc của câu chuyện phát triển tính năng.

Vấn đề của sự nghiêm ngặt trong Git

Duy trì kỷ luật nghiêm ngặt với Git trong suốt vòng đời phát triển tính năng là rất mệt mỏi. Mặc dù Jujutsu (một hệ thống kiểm soát phiên bản tương thích với Git) giúp việc di chuyển giữa các commit dễ dàng hơn, nhưng việc duy trì sự ngăn nắp vẫn đòi hỏi nhiều công sức.

Các công cụ như jj absorb hay jj squash -i có phần nào đó giúp ích, nhưng chúng vẫn có những điểm yếu. jj absorb có thể gán thay đổi sai commit dựa trên lịch sử sửa đổi tệp tin gần nhất, trong khi squash có thể khiến bạn bị mắc kẹt trong "địa ngục xung đột gộp" (merge conflict hell) nếu ranh giới thay đổi không đủ rõ ràng.

Quy trình "Giặt đồ" với Jujutsu

Để giải quyết vấn đề "mệt mỏi vì sự nghiêm ngặt của Git" (Git Rigour Fatigue), tác giả đã đề xuất một kỹ thuật thú vị có thể gọi là "Làm commit như một đống giặt đồ".

Ý tưởng cốt lõi là không cố gắng giữ lịch sử sạch sẽ trong lúc code. Hãy viết commit một cách tự phát, bao gồm cả các trạng thái debug tạm thời. Sau khi hoàn thành tính năng, chúng ta sẽ dọn dẹp toàn bộ một lúc.

Các bước thực hiện như sau:

  1. Tạo cấu trúc lý tưởng: Trước tiên, hãy tạo ra các commit trống đại diện cho cấu trúc lịch sử mong muốn. Ví dụ: jj new -B messy-first -m 'định nghĩa kiểu dữ liệu'.
  2. Gộp tất cả vào một: Gộp toàn bộ các commit chứa thay đổi thực tế vào một commit lớn duy nhất. Ví dụ: jj squash --from messy-first..messy-last --into messy-first.
  3. Phân loại lại: Sử dụng jj squash -i để di chuyển các phần code (hunks) từ commit lớn đó vào các commit trống đã tạo ở bước 1. Bạn chỉ cần chọn các thay đổi liên quan đến "định nghĩa kiểu dữ liệu" và đưa nó vào commit tương ứng, rồi làm tương tự với UI, API, v.v.

Cuối cùng, mọi thứ sẽ nằm đúng vị trí và commit "chứa tất cả" ban đầu sẽ trở nên trống rỗng và có thể xóa bỏ.

Tại sao phương pháp này hiệu quả?

Đối với các tính năng lớn, quy trình này dễ chịu hơn nhiều so với việc duy trì kỷ luật Git nghiêm ngặt liên tục. Nó cho phép bạn tạo các commit tạm thời, chứa code debug và dọn dẹp tất cả trong một lần duy nhất vào cuối quá trình.

Phương pháp này khác biệt và vượt trội hơn so với jj split. Với split, nếu bạn bỏ lỡ một đoạn code nào đó, bạn phải chia tách và gộp lại nhiều lần. Kỹ thuật mới cho phép sắp xếp các đoạn code dễ dàng nhất trước mà không lo ảnh hưởng đến trình tự commit.

Một nhược điểm cần lưu ý là không đảm bảo mọi commit trung gian đều có thể biên dịch (compile) được, điều này có thể là rào cản đối với một số đội ngũ phát triển. Tuy nhiên, nếu sự linh hoạt trong quá trình phát triển là ưu tiên, đây là một cách tiếp cận rất đáng thử.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗