cat blog/.md
Git Worktree: Làm việc nhiều branch cùng lúc mà không cần stash
Bạn đang code ngon lành trên branch feature/payment — đang sửa đến giữa file, IDE mở 10 tab, debugger bật sẵn. Rồi đột nhiên: “Ê ông ơi, review giúp cái PR gấp” hoặc “Production có bug, fix hotfix ngay nhé”.
Lúc này bạn phải git stash, switch branch, xong quay lại thì stash conflict, IDE mất hết context, debugger reset. Quen chưa?
Mình từng chịu cảnh này suốt cho đến khi phát hiện ra git worktree — một tính năng có sẵn trong Git mà ít người biết đến. Nó cho phép bạn checkout nhiều branch cùng lúc trên các thư mục khác nhau, không cần stash, không cần clone thêm repo.
Vấn đề: Context switching với git stash là ác mộng
Workflow truyền thống khi cần chuyển branch:
# Đang làm dở feature/payment...
git stash push -m "payment wip"
git checkout hotfix/login-bug
# ... fix bug, commit, push ...
git checkout feature/payment
git stash pop
# Hy vọng không conflict 🙏
Nghe thì đơn giản, nhưng thực tế:
- Stash hay bị quên —
git stash listdài dằng dặc, không nhớ cái nào là cái nào - Stash conflict — pop ra mà file đã thay đổi ở branch khác là đau đầu
- Mất context — IDE phải reload, dev server restart, dependencies có thể khác nhau giữa các branch
- Không thể chạy song song — muốn so sánh output giữa 2 branch? Phải switch qua switch lại
Nếu bạn đang dùng cách clone repo ra nhiều folder thì cũng giải quyết được, nhưng tốn disk (mỗi clone là một bản copy đầy đủ .git), và không share history.
Git Worktree là gì?
Git worktree cho phép bạn tạo nhiều working directory từ cùng một repository. Mỗi worktree là một thư mục riêng, checkout một branch riêng, nhưng share chung .git data — nghĩa là share commit history, remote, config.
Hình dung thế này:
~/projects/
├── my-app/ # Main worktree (branch: feature/payment)
│ ├── .git/
│ ├── src/
│ └── ...
├── my-app-hotfix/ # Linked worktree (branch: hotfix/login-bug)
│ ├── .git (file, trỏ về main)
│ ├── src/
│ └── ...
└── my-app-review/ # Linked worktree (branch: pr/new-dashboard)
├── .git (file, trỏ về main)
├── src/
└── ...
Ba thư mục, ba branch khác nhau, mở song song trên ba cửa sổ IDE. Không stash, không conflict, không mất context.
Các lệnh cơ bản
Tạo worktree mới
# Tạo worktree từ branch đã có
git worktree add ../my-app-hotfix hotfix/login-bug
# Tạo worktree + tạo branch mới luôn
git worktree add -b hotfix/urgent-fix ../my-app-hotfix main
Lệnh đầu tiên sẽ tạo thư mục ../my-app-hotfix và checkout branch hotfix/login-bug vào đó. Branch hiện tại trên main worktree không hề bị ảnh hưởng.
Xem danh sách worktree
git worktree list
Output:
/Users/hoa/projects/my-app cb565aa [feature/payment]
/Users/hoa/projects/my-app-hotfix a1b2c3d [hotfix/login-bug]
/Users/hoa/projects/my-app-review d4e5f6g [pr/new-dashboard]
Xóa worktree khi xong việc
# Xóa worktree (xóa thư mục + unlink)
git worktree remove ../my-app-hotfix
# Hoặc xóa thư mục thủ công rồi dọn dẹp
rm -rf ../my-app-hotfix
git worktree prune
Use cases thực tế
1. Review PR mà không mất context
Đây là use case mình dùng nhiều nhất. Đang code dở, cần review PR của đồng nghiệp:
# Tạo worktree cho PR cần review
git fetch origin pull/42/head:pr-42
git worktree add ../my-app-review pr-42
# Mở IDE mới ở thư mục worktree
code ../my-app-review
Review xong, comment trên GitHub, rồi dọn dẹp:
git worktree remove ../my-app-review
git branch -D pr-42
Main worktree vẫn nguyên xi, dev server vẫn chạy, IDE vẫn mở đúng chỗ.
2. Hotfix production không gián đoạn feature
# Đang làm feature/payment, production cần fix gấp
git worktree add -b hotfix/critical-bug ../my-app-hotfix main
cd ../my-app-hotfix
# Fix bug, test, commit
git push origin hotfix/critical-bug
# Quay lại feature, xóa worktree
cd ../my-app
git worktree remove ../my-app-hotfix
Không stash, không cần nhớ đang làm đến đâu. Feature branch sạch sẽ y nguyên.
3. So sánh output giữa hai branch
Muốn xem behavior khác nhau giữa branch hiện tại và main? Chạy cả hai cùng lúc:
# Tạo worktree cho main
git worktree add ../my-app-main main
# Terminal 1: chạy app ở feature branch (port 3000)
cd ~/projects/my-app && npm run dev -- --port 3000
# Terminal 2: chạy app ở main (port 3001)
cd ~/projects/my-app-main && npm run dev -- --port 3001
# Mở 2 tab browser, so sánh trực tiếp
Cực kỳ hữu ích khi debug regression hoặc demo “before vs after” cho team.
4. Chạy test trên branch khác mà không block
# Tạo worktree để chạy full test suite
git worktree add ../my-app-test feature/payment
cd ../my-app-test
npm test # Chạy test ở đây
# Trong khi đó, ở main worktree vẫn tiếp tục code bình thường
Lưu ý quan trọng
Không thể checkout cùng một branch ở hai worktree
Git không cho phép hai worktree cùng checkout một branch — vì sẽ gây xung đột khi commit:
# ❌ Sẽ báo lỗi nếu branch đã được checkout ở worktree khác
git worktree add ../another-dir feature/payment
# fatal: 'feature/payment' is already checked out at '/Users/hoa/projects/my-app'
Đây là thiết kế có chủ đích, không phải bug.
Dependencies cần install riêng
Mỗi worktree có node_modules, vendor, hay virtual env riêng. Sau khi tạo worktree, nhớ:
cd ../my-app-hotfix
npm install # Node.js
# hoặc
composer install # PHP/Laravel
# hoặc
pip install -r requirements.txt # Python
Nếu dùng monorepo lớn, đây có thể tốn thời gian. Tip: dùng npm ci thay vì npm install cho nhanh hơn.
Dọn dẹp worktree thường xuyên
Worktree tạo xong quên xóa sẽ chiếm disk và làm rối git worktree list. Tạo thói quen:
# Kiểm tra worktree nào đã bị xóa thư mục nhưng chưa unlink
git worktree prune
# Xem danh sách và dọn các worktree không cần nữa
git worktree list
So sánh: Worktree vs Stash vs Clone
| git stash | git clone | git worktree | |
|---|---|---|---|
| Giữ context hiện tại | Không | Có | Có |
| Tốn thêm disk | Không | Nhiều (full clone) | Ít (share .git) |
| Share history/remote | N/A | Không (riêng biệt) | Có |
| Chạy song song | Không | Có | Có |
| Setup nhanh | Nhanh | Chậm (clone + install) | Nhanh |
Worktree gần như “best of both worlds” — giữ context như clone nhưng nhẹ và nhanh hơn nhiều.
Tips
- Đặt tên thư mục có quy ước — VD:
{repo}-{mục đích}nhưmy-app-review,my-app-hotfixđể dễ nhận biết - Tạo alias cho các lệnh hay dùng:
# Thêm vào ~/.zshrc hoặc ~/.bashrc
alias gwta='git worktree add'
alias gwtl='git worktree list'
alias gwtr='git worktree remove'
- Kết hợp với tmux/terminal tabs — mỗi worktree một tab, switch cực nhanh
- Dùng
--detachnếu chỉ cần xem code mà không cần branch cụ thể:
git worktree add --detach ../my-app-browse HEAD~10
Kết
git worktree là một trong những tính năng “ẩn” của Git mà khi biết rồi thì không thể quay lại. Nó giải quyết triệt để vấn đề context switching — thứ mà mọi developer đều gặp hàng ngày nhưng ít ai nghĩ đến cách giải quyết tốt hơn git stash.
Lần tới khi cần review PR hoặc fix hotfix gấp, thay vì stash rồi cầu nguyện, hãy thử:
git worktree add ../quick-fix hotfix/bug
Mình đảm bảo bạn sẽ thấy workflow của mình smooth hơn hẳn.
Bạn đã từng dùng git worktree chưa? Hay có trick nào khác để xử lý context switching? Chia sẻ với mình qua email nhé!