Tình huống ai cũng gặp: bạn đang sửa dở một tính năng, code chưa chạy, chưa muốn commit "nửa vời" — thì có việc gấp phải nhảy sang nhánh khác (sửa bug production). Commit dở thì bẩn lịch sử, mà đổi nhánh với thay đổi chưa lưu thì Git chặn hoặc kéo theo lung tung. git stash sinh ra cho đúng lúc này: cất thay đổi vào một ngăn tạm, trả working tree về sạch, để bạn làm việc khác rồi quay lại lấy ra tiếp. Đơn giản nhưng có vài bẫy đáng biết. Đo thật bằng git 2.39.
Cất và lấy lại
git stash gom các thay đổi đã theo dõi (tracked) vào ngăn tạm và khôi phục working tree về trạng thái của commit gần nhất:
git stash # cất thay đổi đã theo dõi
git stash list # xem: stash@{0}, stash@{1}...
git stash pop # lấy stash mới nhất ra VÀ xóa khỏi list
git stash apply # lấy ra nhưng GIỮ lại trong list
git stash -u # cất CẢ file chưa theo dõi (untracked)
git stash drop # xóa một stash; git stash -p cất từng phần

Hình 1: git stash cất thay đổi vào ngăn tạm để working tree sạch lại. Các lệnh stash/list/pop/apply/-u/drop. Bản chất mỗi stash là commit ẩn gắn vào refs/stash, không nằm trên nhánh nào.
Đo thật: bẫy untracked, và pop vs apply

Hình 2: git stash cất a.txt (tracked) nhưng c.txt (untracked) vẫn còn — phải git stash -u mới cất cả untracked. git stash apply lấy lại thay đổi nhưng stash vẫn trong list (stash@{0}, stash@{1}), khác pop (xóa luôn). git stash drop xóa một stash.
Kết quả làm rõ ba điểm:
- Cất và lấy:
git stashđưaM a.txtvào ngăn tạm, working tree sạch;git stash poplấy lại đúng thay đổi đó. - Bẫy untracked:
git stashmặc định bỏ qua file chưa theo dõi — sau khi stash,c.txt(untracked) vẫn còn trong working tree. Nếu bạn tưởng stash đã cất mọi thứ rồi checkout nhánh khác,c.txtsẽ đi theo và gây bối rối. Muốn cất cả untracked, dùnggit stash -u(sau đó working tree sạch hoàn toàn). Thêm-a(--all) nếu muốn cất cả file bị.gitignore. popvsapply: cả hai lấy thay đổi ra, nhưngpopxóa stash khỏi list sau khi lấy, cònapplygiữ lại (đo thật, sauapplyvẫn thấystash@{0},stash@{1}). Dùngapplykhi muốn áp cùng stash lên nhiều nhánh; dùngpopcho luồng thông thường. Dọn bằnggit stash drop.
Đánh đổi và lưu ý
Stash là commit ẩn — mất được nhưng cứu được như reflog. Mỗi stash thực chất là một (hoặc vài) commit gắn vào ref refs/stash, không nằm trên nhánh nào. Nếu lỡ drop nhầm, nó thành commit mồ côi — vẫn cứu được qua git fsck --no-reflog | grep commit rồi git stash apply <sha>, cho tới khi gc dọn. Nhưng đừng dựa vào đó.
Đừng dùng stash làm nơi lưu trữ lâu dài. Stash là ngăn tạm cục bộ: không đồng bộ khi push, không mã hóa, dễ quên. Một stash "để mai làm tiếp" nằm hàng tuần rồi xung đột lung tung khi pop là chuyện thường. Nếu công việc đáng giữ lâu, tạo nhánh (git switch -c wip/tinh-nang) và commit — rõ ràng và an toàn hơn nhiều.
git stash -p để cất chọn lọc. Nếu chỉ muốn cất một phần thay đổi (giữ lại phần khác để tiếp tục), git stash -p (patch) cho chọn từng đoạn (hunk) — giống git add -p. Hữu ích khi bạn muốn tách một thử nghiệm ra khỏi công việc chính.
Ba ý mang về
git stashcất thay đổi vào ngăn tạm để đổi nhánh/làm việc gấp mà không commit dở, rồi lấy lại — đo thật, stasha.txtxong working tree sạch,poplấy lại nguyên vẹn.git stashbỏ qua file untracked (đo thậtc.txtvẫn còn) — phảigit stash -uđể cất cả untracked;applygiữ stash trong list cònpopxóa (dùngapplykhi áp lên nhiều nhánh).- Stash là commit ẩn, ngăn tạm cục bộ: lỡ drop vẫn cứu được như reflog (tới khi gc), nhưng đừng dùng làm lưu trữ lâu dài — việc đáng giữ thì tạo nhánh + commit;
stash -pđể cất chọn lọc.
Nguồn
- Pro Git — Git Tools: Stashing and Cleaning: https://git-scm.com/book/en/v2/Git-Tools-Stashing-and-Cleaning
- Git Documentation — git-stash: https://git-scm.com/docs/git-stash
Phần sau ta xử lý cùng bài toán "làm nhiều việc song song" theo cách mạnh hơn stash: git worktree — một kho .git nhưng nhiều thư mục làm việc, mỗi cái ở một nhánh khác nhau.