Bạn đã sửa một file, chạy git add, rồi tiếp tục sửa thêm. Bây giờ bạn muốn bỏ file khỏi lần commit sắp tới nhưng vẫn giữ nội dung trên máy. Một lệnh restore không rõ phạm vi có thể làm khác điều bạn muốn vì Git đang giữ nhiều phiên bản của cùng file.
Bài này dùng một repository tạm để tách ba vùng dữ liệu. Các thao tác được đối chiếu tài liệu Git và kiểm tra bằng Git 2.54.0 ngày 23/10/2026. Không thực hành lệnh bỏ thay đổi trên repository đang có công việc chưa được lưu của bạn.
Ba vùng cần nhìn thấy cùng lúc
HEAD chỉ tới commit hiện tại. Index, thường được gọi là staged, chứa nội dung dự kiến cho lần commit tiếp theo. Working tree là các file bạn đang chỉnh trong thư mục làm việc. Sau khi git add rồi sửa tiếp, index và working tree có thể giữ hai nội dung khác nhau.
git diff cho thấy chênh lệch giữa working tree và index. git diff --staged cho thấy chênh lệch giữa index và HEAD. Cần đọc cả hai nếu muốn biết một lệnh restore sẽ thay đổi phần nào.
Tạo tình huống trong thư mục riêng
Chạy các lệnh sau trong terminal thử. mktemp tạo thư mục mới; cấu hình danh tính chỉ áp dụng trong repository demo. Ví dụ không thêm remote và không gửi dữ liệu ra ngoài.
demo_repo=$(mktemp -d)
cd "$demo_repo"
git init -q
git config user.name 'AeDev Demo'
git config user.email '[email protected]'
printf 'base\n' > note.txt
git add note.txt
git commit -qm 'Create demo note'
printf 'staged\n' > note.txt
git add note.txt
printf 'working\n' > note.txt
git status --short
git diff -- note.txt
git diff --staged -- note.txt
Lúc này commit giữ base, index giữ staged và file trên máy giữ working. Trạng thái ngắn có thể hiện hai vị trí sửa đổi vì cả index lẫn working tree đều khác vùng so sánh tương ứng. Cách hiển thị màu và thông báo có thể khác theo cấu hình Git.
Unstage và giữ nguyên file trên máy
git restore --staged -- note.txt
git diff --staged -- note.txt
cat note.txt
Mặc định khi dùng --staged, nguồn là HEAD và đích là index. Vì thế diff staged của file trở thành rỗng, còn nội dung working tree vẫn là working. Đây là thao tác phù hợp khi bạn chỉ muốn thay đổi danh sách nội dung sắp commit.
Dấu -- ngăn Git hiểu tên file phía sau như một option. Chỉ định đúng file giúp phạm vi thao tác dễ kiểm tra hơn dùng một pathspec bao trùm toàn bộ repository. Với tên có khoảng trắng, đặt path trong dấu nháy.
Restore working tree lấy từ index theo mặc định
Tiếp tục trong repository demo, đưa nội dung working vào index rồi sửa file một lần nữa:
git add note.txt
printf 'extra\n' > note.txt
git restore -- note.txt
cat note.txt
git diff --staged -- note.txt
File trở về working, vì lần restore này không có --staged và lấy nguồn mặc định từ index. Nó không tự đưa file về nội dung base trong commit. Phần extra chưa được lưu vào index hoặc commit đã bị thay thế; hãy xác nhận bạn muốn bỏ phần đó trước khi dùng lệnh tương tự ngoài demo.
Điều này giải thích nhiều trường hợp “đã restore mà Git vẫn báo thay đổi”: staged vẫn khác HEAD, còn lệnh vừa chạy chỉ điều chỉnh working tree. Kiểm tra trạng thái từng vùng sẽ rõ hơn việc chạy thêm nhiều lệnh hoàn tác theo cảm tính.
Chọn nguồn commit nhưng giữ index
git restore --source=HEAD --worktree -- note.txt
cat note.txt
git diff --staged -- note.txt
Lần này nguồn được chỉ rõ là HEAD, đích chỉ là working tree. File trên máy thành base nhưng index vẫn giữ working. Nếu commit ngay, Git vẫn dùng nội dung trong index. Đây là lý do phải đọc lại diff staged trước mỗi lần commit, dù nội dung đang mở trong editor có vẻ đã đúng.
Muốn khôi phục cả hai vùng về một commit cần chọn cả --staged lẫn --worktree; thao tác đó có thể thay thế cả phần đang sửa và phần đã stage. Chỉ thực hiện sau khi đã lưu những nội dung cần giữ và xác nhận đúng nguồn, đúng file.
Những trường hợp không giải quyết bằng restore thông thường
File untracked chưa nằm trong Git không được quản lý giống file đã commit. Đừng suy ra cần chạy thêm lệnh dọn toàn bộ file chỉ vì restore không tác động đến nó. Khi đang merge hoặc rebase có conflict, index còn các stage đặc biệt; nên đọc hướng dẫn của chính trạng thái đó thay vì áp dụng máy móc ví dụ một file ở trên.
Nếu muốn giữ một phần thay đổi, xem chế độ git restore --patch và đọc từng hunk trước khi chọn. Nếu muốn giữ toàn bộ công việc để thử một hướng khác, có thể lưu thành commit trên nhánh riêng hoặc dùng workflow phù hợp của team.
Kết luận
Trước mỗi lần restore, hãy nói rõ nguồn dữ liệu, vùng sẽ bị thay đổi và file nằm trong phạm vi. Sau đó đọc lại cả diff thường lẫn diff staged. Ba bước đó giúp việc hoàn tác có thể dự đoán được thay vì phụ thuộc tên gọi chung “bỏ thay đổi”.





