Sổ tay kỹ thuật

Git worktree và stash – làm song song nhiều branch

how-to#git· cập nhật 2026-11-06

Dùng khi đang code dở mà phải sửa gấp branch khác, review PR hoặc chạy test dài trên branch khác mà không muốn mất trạng thái làm việc.

Sửa trang này
Mục lục

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