Jujutsu Megamerges: Quy trình làm việc "đa luồng" hiệu quả cho lập trình viên

20 tháng 4, 2026·8 phút đọc

Bài viết này giới thiệu quy trình "megamerge" trong Jujutsu, một kỹ thuật cho phép lập trình viên làm việc trên nhiều nhánh cùng một lúc thông qua một commit hợp nhất tạm thời. Phương pháp này giúp giảm thiểu xung đột mã nguồn, dễ dàng chuyển đổi ngữ cảnh và duy trì sự đồng bộ giữa các tính năng đang phát triển.

Jujutsu Megamerges: Quy trình làm việc "đa luồng" hiệu quả cho lập trình viên

Jujutsu Megamerges: Quy trình làm việc "đa luồng" hiệu quả cho lập trình viên

Bài viết này dành cho những người dùng Jujutsu ở mức trung bình và cho những người dùng Git tò mò về Jujutsu. Là một người dùng thường xuyên của Jujutsu, tôi nhận thấy mình ngày càng phụ thuộc nhiều hơn vào những gì cộng đồng JJ gọi vui là quy trình làm việc "megamerge" (siêu hợp nhất) trong công việc hàng ngày. Chủ đề này ít được bàn luận bên ngoài một nhóm nhỏ người dùng chuyên sâu, vì vậy tôi muốn chia sẻ về cách thức hoạt động của nó và lý do tại sao nó lại hữu ích đến vậy, đặc biệt nếu bạn đang làm việc trong một môi trường phát triển phức tạp hoặc thường xuyên gửi nhiều Pull Request (PR) nhỏ.

Commit hợp nhất không giống như bạn nghĩ

Nếu bạn là người dùng Git trung bình (hoặc thậm chí là người dùng Jujutsu chưa tìm hiểu sâu về các quy trình nâng cao), bạn có thể ngạc nhiên khi biết rằng commit hợp nhất (merge commit) hoàn toàn không có gì đặc biệt. Nó không phải là một trường hợp đặc biệt có quy tắc riêng. Nó chỉ là một commit bình thường có nhiều cha (multiple parents). Nó thậm chí không nhất thiết phải rỗng!

Bạn có thể còn ngạc nhiên hơn khi biết rằng commit hợp nhất không bị giới hạn ở hai cha. Chúng ta gọi không chính thức các commit hợp nhất có ba cha trở lên là "octopus merges" (hợp nhất bạch tuộc). Trong khi bạn có thể tự hỏi "trong hoàn cảnh nào tôi lại muốn hợp nhất nhiều hơn hai nhánh?", thì đây thực sự là một ý tưởng rất mạnh mẽ. Octopus merges chính là động lực thúc đẩy toàn bộ quy trình megamerge!

Vậy Megamerge là cái quái gì?

Về cơ bản, trong quy trình megamerge, bạn hiếm khi làm việc trực tiếp trên đầu (tips) của các nhánh. Thay vào đó, bạn tạo một commit octopus merge (sau đây gọi là "megamerge") làm con của mọi nhánh làm việc mà bạn quan tâm. Điều này bao gồm các bản sửa lỗi (bugfixes), nhánh tính năng (feature branches), các nhánh đang chờ PR, nhánh của người khác mà mã của bạn cần tương thích, thậm chí cả các cài đặt môi trường cục bộ. Mọi thứ bạn quan tâm đều được đưa vào megamerge.

Điều quan trọng cần nhớ là bạn không đẩy (push) megamerge này lên remote, mà chỉ đẩy các nhánh cấu thành nên nó.

Tại sao lại làm phức tạp như vậy?

Ban đầu nghe có vẻ hơi rối, nhưng quy trình này mang lại một số lợi ích cực kỳ quý giá:

  • Bạn luôn làm việc trên tổng hợp của tất cả công việc: Điều này có nghĩa là nếu bản sao làm việc (working copy) của bạn biên dịch và chạy trơn tru, bạn biết rằng tất cả các công việc của mình sẽ tương tác với nhau mà không gặp vấn đề gì.
  • Hiếm khi phải lo lắng về xung đột hợp nhất: Vì bạn thực sự luôn hợp nhất các thay đổi của mình với nhau, bạn sẽ không bao giờ bị bất ngờ bởi các xung đột merge khi gửi lên forge (GitHub/GitLab...).
  • Ít ma sát hơn khi chuyển đổi giữa các nhiệm vụ: Vì bạn luôn làm việc trên nền tảng của megamerge, bạn không cần phải thao tác trên VCS để chuyển đổi nhiệm vụ. Chỉ cần sửa những gì bạn cần. Điều này cũng giúp việc tạo các PR nhỏ cho các bản sửa lỗi nhanh chóng trở nên dễ dàng hơn.
  • Dễ dàng giữ cho các nhánh được cập nhật: Với một chút thủ thuật, bạn có thể giữ cho toàn bộ megamerge của mình được cập nhật với nhánh chính (trunk) chỉ bằng một lệnh rebase duy nhất.

Cách tạo một Megamerge

Bắt đầu một megamerge cực kỳ đơn giản: chỉ cần tạo một commit mới với mỗi nhánh bạn muốn đưa vào megamerge làm cha. Tôi thích đặt tên cho commit đó và để nó rỗng, như sau:

jj new x y z
jj commit --message "megamerge"

Sau đó, bạn sẽ có một commit rỗng nằm trên cùng của tất cả những thứ này. Đây là nơi bạn thực hiện công việc của mình! Bất cứ thứ gì nằm trên commit megamerge đều được coi là WIP (Work In Progress - Công việc đang thực hiện). Bạn có thể tách chúng ra khi cần, tạo nhiều nhánh dựa trên commit megamerge đó, bất cứ điều gì bạn muốn. Mọi thứ bạn viết sẽ dựa trên tổng của mọi thứ trong megamerge.

Làm thế nào để gửi thay đổi?

Cách bạn đưa các thay đổi WIP vào megamerge phụ thuộc vào nơi chúng cần đến. Nếu bạn đang thực hiện các thay đổi thuộc về các thay đổi hiện có, bạn có thể sử dụng lệnh squash với cờ --to để đẩy chúng vào các commit hạ lưu đúng đắn. Nếu commit của bạn chứa nhiều thay đổi, bạn có thể chia nhỏ nó hoặc sử dụng squash --interactive để chọn ra các phần cụ thể cần di chuyển.

# Nén toàn bộ commit WIP (mặc định là `--from @`)
jj squash --to x --from y

# Nén tương tác một phần của commit WIP
jj squash --to x --from y --interactive

Tất nhiên, Jujutsu là một phần mềm tuyệt vời và có một số tính năng tự động hóa cho việc này! Lệnh absorb sẽ làm rất nhiều việc này cho bạn bằng cách xác định commit hạ lưu nào có thể thay đổi (mutable) mà mỗi dòng hoặc đoạn (hunk) của commit hiện tại thuộc về và tự động nén chúng xuống. Cảm giác này giống như phép thuật mỗi khi tôi sử dụng nó.

# Tự động nén thay đổi của bạn (mặc định là `--from @`)
jj absorb --from x

Cập nhật và quản lý nhánh

Nếu tôi bắt đầu làm việc trên một tính năng hoàn toàn mới hoặc tìm thấy một lỗi không liên quan để sửa, thì thậm chí còn đơn giản hơn! Sử dụng một vài bí danh (aliases), tôi có thể rất dễ dàng bao gồm các thay đổi mới trong megamerge của mình.

Đầu tiên, hãy định nghĩa một revset alias để tìm commit hợp nhất gần nhất:

[revset-aliases]
# Trả về commit hợp nhất gần nhất với `to`
"closest_merge(to)" = "heads(::to & merges())"

Sau đó, định nghĩa các alias lệnh:

[aliases]
# Chèn revset đã cho làm một nhánh mới dưới megamerge.
stack = ["rebase", "--after", "trunk()", "--before", "closest_merge(@)", "--revision"]

# `jj stage` để bao gồm toàn bộ stack sau megamerge
stage = ["stack", "closest_merge(@).. ~ empty()"]

# `jj restack` để rebase các thay đổi của bạn lên `trunk()`
restack = ["rebase", "--onto", "trunk()", "--source", "roots(trunk()..) & mutable()"]

Lệnh stack cho phép chúng tôi nhắm mục tiêu bất kỳ revset nào và chèn nó giữa trunk() (nhánh phát triển chính của bạn) và commit megamerge của chúng tôi. Lệnh stage thì thậm chí còn tiện hơn, nó không yêu cầu đầu vào nào cả! Chỉ cần chuẩn bị các commit của bạn và stage chúng:

jj stage

Giữ cho mọi thứ được cập nhật

Mảnh ghép cuối cùng của câu đố megamerge này là (thật không may) phải đối mặt với thực tế là những người khác: Làm cách nào để giữ tất cả những thứ này được cập nhật?

Jujutsu có một cách rất dễ dàng để rebase toàn bộ cây làm việc của bạn lên nhánh chính:

jj rebase --onto trunk()

Tuy nhiên, điều này chỉ hoạt động nếu toàn bộ cây làm việc là thay đổi của bạn. Khi bạn cố gắng tham chiếu các commit mà bạn không sở hữu (như các bookmark chưa được theo dõi hoặc nhánh của người khác), Jujutsu sẽ dừng sớm để bảo vệ chúng khỏi bị ghi đè.

Thay vào đó, hãy sử dụng alias restack đã định nghĩa ở trên. Nó chỉ nhắm mục tiêu đến các commit mà chúng ta thực sự được phép di chuyển. Điều này để lại các nhánh mà chúng ta không kiểm soát cũng như công việc được xếp chồng lên các nhánh của người khác. Nó chưa bao giờ làm tôi thất vọng, ngay cả với những megamerge khổng lồ hỗn hợp của nhiều người đóng góp!

Tóm lại

Jujutsu megamerges cực kỳ thú vị và cho phép bạn làm việc trên nhiều luồng công việc khác nhau cùng một lúc. Hãy thử sử dụng absorb và/hoặc squash --interactive để đưa các thay đổi mới vào các commit hiện có, commitrebase để tạo các commit mới dưới megamerge của bạn, và commit với stack hoặc stage để di chuyển toàn bộ nhánh vào megamerge.

Hãy nhớ rằng megamerges không thực sự được định nghĩa để đẩy lên remote; chúng chỉ là một cách tiện lợi để bạn nhìn thấy toàn bộ bức tranh. Bạn vẫn sẽ muốn xuất bản các nhánh riêng lẻ như bình thường.

Megamerges có thể không dành cho tất cả mọi người, nhưng một khi bạn thử chúng, bạn có thể sẽ thấy chúng cho phép bạn chuyển đổi giữa các nhiệm vụ với gần như không có nỗ lực nào. Hãy thử xem!

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗