Hiểu về lỗi Git Checkout bị ghi đè
Bạn đang tập trung làm việc với một tính năng, thì đột nhiên có báo cáo lỗi khẩn cấp. Đã đến lúc chuyển nhánh để sửa rồi, đúng không? Bạn gõ git checkout another-branch, và rồi BÌNH! Màn hình hiện ra thông báo này:
error: Your local changes to the following files would be overwritten by checkout:
file.txt
Please commit your changes or stash them before you switch branches.
Aborting
Thông báo lỗi này có nghĩa là Git đang làm đúng nhiệm vụ của nó: bảo vệ công việc của bạn. Bạn có những thay đổi chưa được commit trên nhánh hiện tại — có thể là các chỉnh sửa với file.txt, như trong ví dụ. Nếu Git cứ chuyển sang another-branch, những thay đổi đó có thể bị mất, bị ghi đè bởi các file từ nhánh đích, hoặc tạo ra tình trạng lộn xộn. Git ngăn chặn việc mất dữ liệu này bằng cách hủy thao tác và chỉ cho bạn biết chính xác phải làm gì: commit hoặc stash các thay đổi của bạn.
Cách sửa từng bước: Giải quyết các thay đổi chưa commit trước khi checkout
Khi lỗi này xuất hiện, bước đầu tiên bạn cần làm là đánh giá trạng thái hiện tại của thư mục làm việc. Hãy luôn bắt đầu với git status để có cái nhìn rõ ràng về những gì Git đang cảnh báo.
git status
Lệnh này cho thấy những file nào đang được chỉnh sửa, đã staged, hoặc chưa được theo dõi. Tùy thuộc vào việc bạn muốn giữ, lưu tạm thời, hay loại bỏ những thay đổi này, bạn có ba lựa chọn chính.
Lựa chọn 1: Commit các thay đổi (nếu đã sẵn sàng)
Nếu những thay đổi hiện tại của bạn đã hoàn chỉnh, ổn định và sẵn sàng trở thành một phần lịch sử của nhánh, thì commit chúng là giải pháp trực tiếp nhất. Cách này phù hợp khi bạn đã hoàn thành một tác vụ nhỏ độc lập hoặc một phần logic của tính năng lớn hơn.
-
Stage các thay đổi của bạn:
git add .
Lệnh này stage tất cả các file đã chỉnh sửa và file mới. Nếu bạn chỉ muốn stage một số file cụ thể, hãy liệt kê chúng rõ ràng (ví dụ: `git add file.txt another_file.js`).
-
**Commit các thay đổi của bạn:**
```
git commit -m "feat: Complete initial implementation of new login form"
Luôn sử dụng thông điệp commit rõ ràng và mô tả đầy đủ. Nếu đây chỉ là những thay đổi tạm thời mà bạn định amend hoặc squash sau này, hãy cân nhắc dùng thông điệp "WIP" (Work In Progress), ví dụ như "WIP: temporary changes before switching branch".
-
Bây giờ, chuyển nhánh:
git checkout another-branch
Hoặc, nếu đang dùng phiên bản Git mới hơn:
```bash
git switch another-branch
Các thay đổi của bạn đã được ghi lại an toàn vào lịch sử nhánh hiện tại, và bạn có thể chuyển nhánh mà không gặp vấn đề gì.
Lựa chọn 2: Stash các thay đổi (nếu chưa sẵn sàng để commit)
Thường thì các thay đổi của bạn chưa đủ để commit đầy đủ, nhưng bạn chắc chắn không muốn mất chúng. Đó chính xác là lý do tại sao git stash lại hữu ích đến vậy. Lệnh này lấy các file được theo dõi đã chỉnh sửa và các thay đổi đã staged của bạn, lưu chúng vào một 'stack' đặc biệt chứa công việc chưa hoàn thành. Sau đó, nó đưa thư mục làm việc của bạn về trạng thái sạch sẽ. Hãy nghĩ về nó như việc gọn gàng gác lại dự án hiện tại của bạn một cách tạm thời.
-
Stash các thay đổi của bạn:
git stash save "WIP: Login form redesign before bug fix"
Việc thêm thông điệp mô tả (như `"WIP: Login form redesign before bug fix"`) được khuyến nghị mạnh mẽ, đặc biệt nếu bạn dự kiến có nhiều stash. Nếu không có thông điệp, Git sẽ mặc định dùng tên nhánh hiện tại và thông điệp commit.
Để stash nhanh cả file được theo dõi và chưa được theo dõi (nhưng không bao gồm file bị ignored), bạn có thể dùng:
```bash
git stash -u
Hoặc để stash tất cả file, kể cả file bị ignored (dùng cẩn thận):
```bash
git stash -a
-
**Xác nhận thư mục làm việc đã sạch:**
```bash
git status
Bạn sẽ thấy thông báo "nothing to commit, working tree clean."
-
Chuyển nhánh:
git checkout another-branch
Hoặc:
```bash
git switch another-branch
-
(Sau này) Áp dụng lại các thay đổi đã stash:
Khi bạn đã quay lại nhánh ban đầu (hoặc nhánh khác mà bạn muốn áp dụng), bạn có thể lấy lại các thay đổi của mình.
Để xem danh sách stash:
git stash list
Để áp dụng lại stash gần nhất và xóa nó khỏi danh sách stash:
```bash
git stash pop
Để áp dụng lại một stash cụ thể (ví dụ: stash@{1}) và xóa nó:
```bash
git stash pop stash@{1}
Để áp dụng lại stash nhưng vẫn giữ nó trong danh sách stash (hữu ích khi bạn muốn áp dụng cho nhiều nhánh hoặc chỉ kiểm tra):
```bash
git stash apply
Lựa chọn 3: Hủy bỏ các thay đổi (nếu không cần nữa)
Đôi khi, các thay đổi của bạn chỉ mang tính thử nghiệm, vô tình tạo ra, hoặc đơn giản là không còn cần thiết nữa. Nếu bạn hoàn toàn chắc chắn muốn loại bỏ chúng và đưa thư mục làm việc về trạng thái đã commit lần cuối, đây là lựa chọn dành cho bạn.
CẢNH BÁO: Hành động này không thể hoàn tác. Hãy đảm bảo bạn thực sự muốn mất những thay đổi này trước khi tiến hành.
-
Hủy thay đổi của các file được theo dõi:
git restore .
Lệnh này (có từ Git 2.23+) sẽ đưa tất cả các file được theo dõi đã chỉnh sửa về trạng thái tại lần commit cuối. Nếu bạn đang dùng phiên bản Git cũ hơn, hãy dùng:
```bash
git checkout -- .
Hoặc cho một file cụ thể:
```bash
git restore file.txt
-
**Hủy bỏ các file và thư mục chưa được theo dõi:**
Nếu bạn có các file mới chưa được thêm vào Git (file chưa được theo dõi), `git restore` hoặc `git checkout -- .` sẽ không xử lý chúng. Bạn cần dùng `git clean`.
Đầu tiên, chạy thử để xem những gì sẽ bị xóa:
```bash
git clean -n
Để xóa các file chưa được theo dõi:
```bash
git clean -f
Để xóa cả file và thư mục chưa được theo dõi:
```bash
git clean -df
Một lần nữa, hãy hết sức cẩn thận với git clean vì nó xóa file vĩnh viễn.
-
Xác nhận thư mục làm việc đã sạch:
git status
Bạn sẽ thấy thông báo "nothing to commit, working tree clean."
-
**Bây giờ, chuyển nhánh:**
```bash
git checkout another-branch
Hoặc:
```bash
git switch another-branch
## Các bước kiểm tra
Sau khi áp dụng một trong các giải pháp, điều quan trọng là phải xác nhận bạn đã chuyển nhánh thành công và thư mục làm việc đang ở trạng thái như mong đợi.
-
**Xác nhận nhánh hiện tại:**
```bash
git branch
Kết quả hiển thị sẽ có dấu hoa thị (*) bên cạnh another-branch (hoặc nhánh bạn định chuyển đến).
-
Kiểm tra trạng thái thư mục làm việc:
git status
Kết quả sẽ hiển thị "On branch another-branch" và "nothing to commit, working tree clean."
-
**Nếu bạn dùng `git stash`, kiểm tra danh sách stash (tùy chọn):**
```bash
git stash list
Nếu bạn dùng git stash pop, mục stash sẽ không còn trong danh sách nữa. Nếu bạn dùng git stash apply, nó vẫn còn trong danh sách.
Mẹo để có quy trình Git mượt mà hơn
-
Commit thường xuyên: Hãy tạo các commit nhỏ, thường xuyên và có ý nghĩa. Thói quen này giảm đáng kể khả năng có nhiều thay đổi chưa commit làm tắc nghẽn quy trình làm việc. Nó cũng giúp việc hoàn tác hoặc quản lý công việc của bạn đơn giản hơn nhiều.
-
Hiểu về
git stash: Đây là cứu cánh khi cần chuyển ngữ cảnh. Hãy làm quen vớistash,stash list,stash applyvàstash pop. -
Dùng
git worktreecho các tình huống nâng cao: Nếu bạn thường xuyên cần chuyển đổi nhanh giữa các nhánh và làm việc với chúng đồng thời, hãy cân nhắc dùnggit worktree. Nó cho phép bạn checkout nhiều nhánh vào các thư mục riêng biệt, tạo ra nhiều working tree từ cùng một repository.
git worktree add ../hotfix-branch hotfix/urgent-bug
Lệnh này tạo một thư mục mới `../hotfix-branch` với nhánh `hotfix/urgent-bug` được checkout, trong khi repository gốc của bạn vẫn ở nhánh hiện tại.
-
**Chú ý đến các file chưa được theo dõi:** Các file chưa được theo dõi thường là các artifact build hoặc file tạm thời. Hãy cấu hình file `.gitignore` để ngăn chúng xuất hiện trong `git status` và làm lộn xộn workspace, giảm nhu cầu dùng `git clean`.

