Tổng quan và git commit --amend

Xem thử

Vấn đề cần giải quyết

Bạn vừa commit và ngay sau đó nhận ra mình quên một tệp, hoặc thông điệp có lỗi gõ. Để lại một commit "thêm tệp bị quên" thì lịch sử rối; sửa lại thì phải thay commit cũ. Git cho phép bạn viết lại lịch sử để nó gọn gàng trước khi chia sẻ. Nhưng viết lại lịch sử đã chia sẻ sẽ làm lệch bản sao của đồng đội, nên có một ranh giới phải nhớ.

Sau bài này, bạn có thể

  • Phát biểu quy tắc số một của việc viết lại lịch sử và áp dụng nó.
  • Dùng git commit --amend để sửa thông điệp hoặc thêm tệp bị quên vào commit cuối.
  • Gọi tên các công cụ viết lại lịch sử và biết khi nào mỗi công cụ phù hợp.

Tiên quyết: chương Hoàn tác thay đổi.

Quy tắc số một

Viết lại tự do các commit chưa push. Đừng viết lại các commit đã chia sẻ.

Mọi quyết định bắt đầu bằng một câu hỏi: commit này đã rời khỏi máy bạn chưa?

Đang tải sơ đồ…

Cách đọc hình. Câu hỏi duy nhất là commit đã được push và chia sẻ chưa. Nếu chưa, bạn viết lại thoải mái bằng amend, rebase hay reset. Nếu rồi, đừng viết lại: hãy thêm commit mới hoặc dùng git revert để đảo ngược.

git commit --amend

--amend sửa commit gần nhất: đổi thông điệp, hoặc thêm hay bớt tệp.

bash
git commit --amend -m "Thông điệp mới rõ ràng hơn"

git add file-quen.txt
git commit --amend --no-edit

Dòng đầu chỉ đổi thông điệp. Hai dòng sau thêm tệp bị quên vào commit cuối và giữ nguyên thông điệp nhờ --no-edit. Bản chất: amend thay thế commit cũ bằng một commit mới có hash khác.

Thử và quan sát

Hãy dự đoán: commit chưa push và bạn quên một tệp. Cách nào gọn nhất để thêm tệp mà không để lại commit "thêm tệp bị quên"? Chạy mô phỏng, rồi thử biến thể khi commit đã push.

Đang tải Animation…

Bảng bước (bản đọc tĩnh của mô phỏng)

BướcLệnhĐiều xảy ra
1git status -sCommit C2 chỉ có app.js. Tệp file-quen.txt vẫn chưa theo dõi.
2git add file-quen.txtĐưa tệp bị quên vào Staging Area như bình thường.
3git commit --amend --no-editAmend lấy nội dung Staging Area và tạo C2' thay C2, giữ nguyên thông điệp nhờ --no-edit. C2 cũ không còn trên main.

Biến thể: Commit đã push: tạo commit mới

BướcLệnhĐiều xảy ra
1git status -sbmain và origin/main cùng ở C2: commit này đã được chia sẻ nên không nên viết lại.
2git add file-quen.txt && git commit -m "Thêm tệp bị quên"Thay vì amend, thêm một commit mới. Lịch sử dài thêm nhưng không làm lệch ai.
3git pushPush thông thường thành công vì chỉ thêm commit.

Giải đáp. git add tệp bị quên rồi git commit --amend --no-edit: Git tạo C2' từ nội dung Staging Area, cha vẫn là C1, và main chuyển sang C2'. C2 cũ không còn trên nhánh nên lịch sử sạch. Nhưng C2' khác hash với C2, vì thế nếu C2 đã push thì amend sẽ làm lệch lịch sử; khi đó hãy tạo commit mới như ở biến thể.

Các công cụ viết lại lịch sử

  • git commit --amend: sửa commit cuối.
  • git rebase: di chuyển hoặc chỉnh sửa một chuỗi commit.
  • git rebase -i: rebase tương tác để gộp (squash), sửa, đổi thứ tự hoặc bỏ commit.
  • git reflog: lưới an toàn ghi lại mọi nơi HEAD từng đi qua.

Nắm nhóm lệnh này giúp bạn tạo lịch sử sạch, dễ review, miễn là bạn luôn nhớ ranh giới giữa cục bộ và công khai.

Hiểu lầm thường gặp

  • "Amend chỉnh sửa tại chỗ." Amend thay bằng commit mới có hash khác.
  • "Viết lại lịch sử luôn xấu." Với commit chưa chia sẻ, nó là thao tác bình thường để làm sạch lịch sử.
  • "Đã push nhưng chưa ai kéo thì amend cũng được." Về kỹ thuật được, nhưng bạn phải force push và rủi ro rất cao; tốt nhất tạo commit mới.

Tự kiểm tra

  1. Quy tắc số một của việc viết lại lịch sử là gì?
  2. git commit --amend --no-edit làm gì khác với --amend -m "..."?
  3. Bạn đã push commit và phát hiện thiếu một tệp. Nên làm gì?

Đáp án gợi ý. (1) Chỉ viết lại commit chưa chia sẻ. (2) --no-edit giữ thông điệp cũ, còn -m thay thông điệp mới. (3) Tạo commit mới chứa tệp bị quên, không amend.

Điều cần nhớ

  • Viết lại tự do commit chưa push; đừng viết lại commit đã chia sẻ.
  • Amend là thay thế, hash đổi.
  • Công cụ: amend, rebase, rebase -i, reflog.
  • Bài sau: git rebase.

Nguồn tham khảo

Pro Git, chương 7.6 "Rewriting History" (git-scm.com/book).