Bạn stash trước khi chuyển việc nhưng một file mới vẫn nằm ở thư mục cũ. Khi lấy thay đổi trở lại, phần đã stage cũng không còn giống lúc bắt đầu. Hai hiện tượng này liên quan đến phạm vi file và cách khôi phục index, không phải Git tự chọn ngẫu nhiên.
Bài hướng dẫn dùng repository thử độc lập để bạn quan sát từng trạng thái. Các lệnh chính đã được chạy với Git 2.54.0; tài liệu được đối chiếu ngày 24/10/2026. Không có thao tác stash trên repository dự án của người dùng trong lần kiểm chứng.
1. Chuẩn bị ba loại file
Theo tham chiếu git stash, tùy chọn -u đưa cả untracked vào stash, còn -a đưa thêm ignored. Đừng dùng -a theo thói quen nếu thư mục chứa file cấu hình riêng hoặc output lớn. Hãy thử bằng dữ liệu giả để hiểu phạm vi trước.
mkdir git-stash-demo
cd git-stash-demo
git init
git config user.name 'Stash Demo'
git config user.email '[email protected]'
printf '%s\n' 'local.log' > .gitignore
printf '%s\n' 'base' > tracked.txt
git add .gitignore tracked.txt
git commit -m 'Create stash fixture'
printf '%s\n' 'staged' > tracked.txt
git add tracked.txt
printf '%s\n' 'working' > tracked.txt
printf '%s\n' 'new note' > todo.txt
printf '%s\n' 'dummy ignored log' > local.log
git status --short --ignored
Chạy trong thư mục mới, không dán phần khởi tạo vào repository đang làm. Hai lệnh config ở đây chỉ đặt danh tính cho repository thử, không đổi cấu hình global.
Lúc này, tracked.txt có hai lớp thay đổi: index chứa staged, working tree chứa working. todo.txt chưa được theo dõi. local.log bị ignore bởi .gitignore. Đây là ba trường hợp giúp bạn nhìn rõ điều một lần stash sẽ mang theo.
2. Stash với untracked nhưng giữ ignored tại chỗ
git stash push -u -m 'demo-before-switch'
git status --short --ignored
git stash list
git stash show --include-untracked -p 'stash@{0}'
Sau push trong fixture, file tracked trở về nội dung base, todo.txt không còn trong working tree và local.log vẫn còn. show --include-untracked giúp bạn xem cả phần file mới trong stash thay vì chỉ nhìn diff tracked mặc định.
stash@{0} là stash mới nhất tại thời điểm chạy. Nếu tiếp tục tạo stash khác, số thứ tự thay đổi. Trong công việc thật, hãy xem danh sách và nội dung trước mỗi lần apply hoặc drop; đừng giữ nguyên một số thứ tự trong ghi chú rồi cho rằng nó luôn trỏ vào cùng công việc.
3. Khôi phục staged state có chủ đích
git stash apply --index 'stash@{0}'
git show :tracked.txt
cat tracked.txt
cat todo.txt
git diff --cached
git diff
git stash list
Trong fixture sạch sau push, apply thành công. git show :tracked.txt in staged; đọc file working tree được working; todo.txt được phục hồi. Stash vẫn còn trong danh sách vì bạn dùng apply.
--index yêu cầu thử khôi phục cả trạng thái index, không chỉ thay đổi working tree. Khi lịch sử hoặc file hiện tại đã khác, thao tác có thể conflict; kết quả của bài thử sạch không bảo đảm mọi lần áp dụng trên nhánh khác đều thành công.
Chỉ sau khi xem diff và xác nhận đầy đủ thay đổi, bạn mới bỏ entry thử:
git stash drop 'stash@{0}'
Lệnh trên dành cho fixture một stash đã kiểm tra. Không dùng git stash clear để dọn một entry vì nó có phạm vi toàn bộ danh sách. Với công việc chưa chắc đã phục hồi đủ, giữ stash thêm một thời gian thường dễ kiểm tra hơn việc xóa vội.
4. Chọn apply hay pop
Apply cho phép tách bước đưa thay đổi trở lại và bước bỏ bản cất. Pop kết hợp việc áp dụng với việc bỏ entry khi áp dụng thành công. Tài liệu Git nêu rằng khi pop gặp conflict, entry vẫn được giữ lại; bạn cần xử lý tình trạng hiện tại rồi quyết định bước tiếp theo.
Với một lần chuyển việc dễ gây nhầm lẫn, apply trước giúp bạn có khoảng dừng để kiểm tra index, working tree và file mới. Đây là lựa chọn quy trình để giảm thao tác vội, không phải cam kết apply không conflict hay không thay đổi dữ liệu.
Kiểm tra và lỗi thường gặp
Nếu file mới không được cất, kiểm tra bạn đã dùng -u chưa và file có thuộc nhóm ignored không. Nếu staged state khác kỳ vọng, xem có dùng --index không, thao tác có báo lỗi không, và index trước khi apply có đang chứa thay đổi khác không.
Nếu gặp conflict, đọc git status, xem từng file và hiểu phần nào đã được áp dụng trước khi chạy lại. Không lặp pop liên tục chỉ vì terminal chưa trở về trạng thái sạch. Sau khi giải quyết, xác nhận thay đổi bằng cả git diff và git diff --cached.
Stash là công cụ cất thay đổi local, không phải bản backup tự gửi lên remote. Đừng đưa secret vào stash rồi cho rằng ignore đã bảo vệ nó; dữ liệu được đưa vào Git object vẫn cần được quản lý. Với việc cần chia sẻ hoặc lưu lâu, cân nhắc commit trên nhánh riêng theo quy trình của nhóm.
Gợi ý tiếp theo
Làm lại fixture một lần không có -u, rồi một lần không có --index để tự quan sát sự khác biệt. Chỉ thực hành trong thư mục thử. Khi hiểu từng lớp dữ liệu, bạn sẽ chọn lệnh stash theo trạng thái cần giữ thay vì nhớ một chuỗi lệnh duy nhất.



