Tóm tắt: Việc ngắn (vài phút) thì git stash push -m → chuyển branch → quay lại git stash pop. Việc dài hoặc cần chạy song song (hotfix, review, build) thì git worktree add ../repo-hotfix hotfix/1.2 để có thư mục làm việc thứ hai dùng chung .git, xong thì git worktree remove. Lệnh dưới đã chạy thử với Git 2.34; tuỳ chọn cần bản mới hơn có ghi chú.
Luồng hoạt động
flowchart TD A[Đang code dở trên feature] --> B{Việc chen ngang} B -->|"ngắn, cùng thư mục"| C["git stash push -m"] C --> D["git switch hotfix, sửa, commit"] D --> E["git switch -, git stash pop"] B -->|"dài hoặc chạy song song"| F["git worktree add ../repo-hotfix"] F --> G["cd ../repo-hotfix, sửa, commit, push"] G --> H["git worktree remove ../repo-hotfix"]
Lệnh
Worktree
Mỗi worktree là một thư mục checkout riêng, dùng chung object, branch và remote với repo chính. Một branch chỉ được checkout ở một worktree tại một thời điểm.
| Mục đích | Lệnh |
|---|---|
| Checkout branch có sẵn ra thư mục mới | git worktree add ../repo-hotfix hotfix/1.2 |
Tạo branch mới từ main trong worktree mới |
git worktree add -b feat/x ../repo-feat main |
| Worktree detached để review/build một commit | git worktree add --detach ../repo-review origin/main |
| Review PR GitHub (fetch ref PR trước) | git fetch origin pull/42/head:pr-42 && git worktree add ../pr-42 pr-42 |
| Liệt kê worktree | git worktree list (script: --porcelain) |
| Xoá worktree (thư mục sạch) | git worktree remove ../repo-hotfix |
| Xoá kể cả khi còn file sửa/untracked | git worktree remove --force ../repo-hotfix |
Dọn metadata của worktree đã bị rm -rf |
git worktree prune -v (xem trước: -n) |
| Đổi chỗ thư mục worktree | git worktree move ../repo-hotfix ../hf |
Khoá worktree trên ổ rời, chống prune |
git worktree lock --reason "usb" ../repo-feat / unlock |
# Hotfix gấp khi đang code dở feature
git fetch origin
git worktree add -b hotfix/1.2.1 ../netinv-hotfix origin/release/1.2
cd ../netinv-hotfix
# ... sửa, test ...
git commit -am "fix: timeout SSH khi backup"
git push -u origin HEAD
cd - && git worktree remove ../netinv-hotfixĐặt worktree ngoài thư mục repo chính (../tên) để tool như ruff, pytest, IDE không quét lồng. Mỗi worktree cần venv riêng (uv sync trong thư mục đó), xem uv cheatsheet.
Stash
Lệnh stash cơ bản (push -u -m, list, pop, apply, branch) đã có trong Git cheatsheet. Phần dưới là các dạng hay quên.
| Mục đích | Lệnh |
|---|---|
| Chỉ stash một số file | git stash push -m "wip f" -- path/a.py path/b.py |
| Chọn từng hunk để stash | git stash push -p -m "một phần" |
Stash nhưng giữ nguyên phần đã add |
git stash push --keep-index -m "test phần đã stage" |
| Chỉ stash phần đã stage (Git ≥ 2.35) | git stash push --staged -m "staged" |
| Xem diff một stash, kể cả file untracked (Git ≥ 2.32) | git stash show -p -u stash@{1} |
| Pop một stash cụ thể | git stash pop stash@{1} |
| Khôi phục cả trạng thái stage như lúc stash | git stash pop --index |
| Xoá một / tất cả stash | git stash drop stash@{1} / git stash clear |
| Lấy một file từ stash, không pop | git restore --source=stash@{0} -- path/a.py |
git stash clear và drop không hỏi lại. Stash đã xoá chỉ còn tìm lại được qua git fsck --unreachable (dòng unreachable commit) cho tới khi bị gc, đừng trông vào đó.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
fatal: 'hotfix/1.2' is already checked out at '...' (bản mới: is already used by worktree) |
Branch đang được checkout ở worktree khác | git worktree list để tìm, làm việc ở đó hoặc tạo branch mới bằng -b |
fatal: '../x' contains modified or untracked files, use --force |
Worktree còn thay đổi chưa commit | Commit/stash trong worktree đó, hoặc remove --force nếu chắc chắn bỏ |
cannot remove a locked working tree |
Worktree đã bị lock |
git worktree unlock <path> rồi remove |
git worktree list còn đường dẫn không tồn tại |
Thư mục bị xoá bằng rm -rf |
git worktree prune -v |
stash pop báo CONFLICT, stash vẫn còn trong list |
Code hiện tại sửa cùng dòng | Giải conflict, git add, rồi git stash drop thủ công |
Pop sau --keep-index bị conflict trên chính file đó |
Phần đã stage vẫn ở working tree và cũng nằm trong stash | Trước khi pop: git restore --staged --worktree <file> (hoặc git reset --hard nếu không còn gì khác) |
| Stash xong file mới vẫn còn | push mặc định bỏ qua untracked |
Thêm -u (hoặc -a gồm cả file ignored) |
error: unknown option 'staged' |
Git < 2.35 | Nâng Git; bản cũ dùng git stash push -p chọn đúng hunk cần cất |
Tham khảo
- git-worktree
- git-stash
- Git troubleshooting khi lỡ mất commit hoặc stash.