Vấn đề là...
Trong quá trình code, chúng ta thường tạo ra các commit không cần thiết để tránh mất code hoặc bị trùng tên. Bạn đã từng nghĩ đến việc gộp (squash) các commit này thành một commit có ý nghĩa hơn chưa?
Squash commit là một việc cần làm, nhưng không phải ai cũng nghĩ đến. Thậm chí nếu nghĩ đến cũng có thể không muốn làm vì lo sợ mất code. Tuy nhiên, hãy nhớ rằng, một khi đã commit code thì nó không thể mất đi. Hãy thoải mái thực hiện squash commit.
Để squash commit, chúng ta sử dụng câu lệnh git rebase -i hoặc git rebase -interactive. Trong bài viết này, tôi sẽ không giải thích về rebase. Bạn có thể tham khảo các bài viết sau để hiểu rõ hơn:
- https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase
- https://www.atlassian.com/git/tutorials/merging-vs-rebasing
Bài viết này thuộc series về Git Workflow. Bạn có thể tham khảo bài viết giới thiệu tại đây.
Trước khi squash
Trước khi thực hiện squash, bạn nên kiểm tra lại lịch sử commit của mình để xác nhận lần cuối commit mà bạn muốn squash. Hãy sao chép hash id của commit trước những commit cần squash.
Ví dụ trong ảnh trên, chúng ta có 4 commit giống nhau, tất cả đều là "update readme.md". Những commit này có cùng một nhiệm vụ là cập nhật readme, vì vậy chúng ta có thể gộp chúng thành một commit duy nhất để tránh tạo rác trong lịch sử git. Để squash, bạn cần có hash id của commit trước tất cả các commit cần squash, ví dụ trong ảnh là dbd01be2.
Bắt đầu squash commit
Tổng hợp các commit
- Mở terminal ở thư mục gốc của project và gõ lệnh
$ git rebase -i dbd01be2
. - Màn hình VIM editor sẽ hiện lên, đôi khi có thể là một editor khác nếu bạn đã thiết lập hoặc sử dụng mặc định khác. Đừng lo lắng, chỉ cần chỉnh sửa nội dung trong editor và đó chỉ là text thông thường.
Trong màn hình này, bạn sẽ thấy 4 commit mà bạn đã chọn để squash ở đầu danh sách. Mỗi commit nằm trên một dòng với nội dung gồm 3 phần: "pick 7424f7c update readme.md".
- "pick" là lệnh mặc định để giữ lại commit đó sau khi rebase và không làm thay đổi gì.
- "7424f7c" là hash id của commit.
- "update readme.md" là commit message.
Bạn cũng có thể thấy hướng dẫn rebase ở phía dưới (nằm trong vùng comment) để biết thêm về các lệnh có thể sử dụng. Tuy nhiên, ở đây chúng ta chỉ quan tâm đến lệnh squash. Nếu bạn làm rebase lần đầu, hãy đọc kỹ để hiểu rõ hơn về rebase.
Đổi action của các commit cần squash
Tiếp tục squash:
- Nhấn phím "i" để có thể chỉnh sửa nội dung.
- Đổi command của 3 commit sau từ "pick" thành "squash".
Chú ý: Bạn cần cẩn thận khi chỉnh sửa thông tin trong màn hình này. Squash luôn gộp với commit trước đó, vì vậy commit đầu tiên không thể là squash. Ví dụ, trong màn hình trên, 3 commit sau sẽ được gộp vào commit đầu tiên và tạo ra một commit mới. Đừng xóa bất kỳ dòng nào không phải commit #. Nếu bạn xóa một dòng, commit tại dòng đó sẽ bị mất.
- Nhấn phím "Esc" để thoát khỏi chế độ chèn (INSERT mode).
- Gõ lệnh ":wq" để lưu nội dung và thoát khỏi VIM editor.
Cập nhật commit message của commit mới (commit sau khi gộp)
Bạn sẽ được chuyển đến một màn hình VIM editor mới. Nhiệm vụ này là để cập nhật commit message cho commit mới - kết quả gộp của 4 commit trước đó. Git sẽ tổng hợp lại thông tin của 4 commit để bạn có thể chọn hoặc sửa đổi để thay thế.
- Xóa bớt những phần không cần thiết và chỉ giữ lại những gì bạn cần.
- Bỏ qua các comment vì chúng sẽ không được đưa vào commit message thực tế.
- Gõ lệnh ":wq" để lưu và thoát.
Kết quả trên command line sẽ là:
Sau khi squash commit
Lịch sử git sẽ thay đổi như sau:
Kết quả thật sự là một commit mới do đã có hash id khác. Trong trường hợp bạn muốn hoàn tác quá trình squash, bạn chỉ cần kiểm tra với git reflog:
Ở phần bên trái, bạn sẽ thấy các hash id của commit cũ. Để hoàn tác, chỉ cần sao chép hash id của commit cuối cùng (trong 4 commit đã gộp là 71e40e0) và nhập lệnh sau vào terminal: $ git reset -hard 71e40e0
. Kiểm tra lịch sử sẽ thấy mọi thứ trở lại như chưa từng xảy ra. Tuyệt vời, phải không?
Bonus
Sau khi reset, bạn có muốn thử kiểm tra git reflog xem điều gì đã xảy ra không? Thần kì... :))