Git Worktree: Làm việc song song trên nhiều nhánh không cần stash hay clone thêm

Git tutorial - IT technology blog
Git tutorial - IT technology blog

Tình huống quen thuộc của mọi developer

Đang giữa chừng một feature phức tạp — code chưa xong, chưa commit được — thì Slack ping: “Anh ơi, production lỗi rồi, fix gấp đi.” Lúc đó chỉ có hai lựa chọn, đều tệ ngang nhau: git stash đống code đang dở rồi chuyển nhánh, hoặc mở terminal clone thêm repo về folder mới. Cả hai đều mất thời gian và dễ gây nhầm lẫn.

Mình gặp đúng cái này khi team bắt đầu chạy song song nhiều tính năng. Một người đang làm feature/payment, người kia cần review feature/auth, trong khi hotfix/critical-bug vừa tạo cần xem ngay. Repo lúc đó khoảng 800MB — mỗi lần clone lại tốn 2-3 phút, chưa kể phải mở thêm IDE một lần nữa.

Tại sao Git khó khi làm việc đa nhánh?

Về cơ bản, một working directory chỉ có thể phản ánh một nhánh tại một thời điểm. Khi bạn git checkout sang nhánh khác, Git thay thế toàn bộ nội dung thư mục làm việc — không thể có hai nhánh mở song song trong cùng một thư mục.

Không phải Git làm sai — đó là cách nó được thiết kế từ đầu. Vấn đề nảy sinh khi workflow đòi hỏi nhiều hơn: review code nhánh khác trong khi vẫn đang code, chạy test song song, hay xử lý hotfix giữa chừng feature đang làm dở.

Các cách thường dùng và tại sao chưa đủ

Git stash xử lý được tình huống đơn giản: lưu tạm code đang dở, chuyển nhánh, làm xong quay lại pop ra. Nhưng stash không phải không có giới hạn:

  • Stash là global per-repo, không gắn với nhánh cụ thể — dễ pop nhầm
  • Stash nhiều lần không đặt tên, danh sách git stash list thành mớ hỗn độn
  • Không chạy được test song song trên hai nhánh cùng lúc
  • Vẫn phải checkout sang nhánh khác — IDE load lại toàn bộ project

Clone thêm vào folder khác giải quyết được vấn đề song song, nhưng lại sinh ra vấn đề khác:

# Cách cũ: clone lại vào folder riêng
git clone /path/to/repo /path/to/repo-hotfix
cd /path/to/repo-hotfix
git checkout hotfix/critical-bug

Với repo nặng vài trăm MB đến vài GB, mỗi lần clone tốn thời gian đáng kể. Hai bản repo cũng hoạt động hoàn toàn độc lập — commit ở bản này không tự đồng bộ bản kia, và bạn có hai thư mục .git riêng biệt chiếm gấp đôi disk.

Git Worktree — một repo, nhiều thư mục làm việc

git worktree lấp đúng chỗ trống mà cả stash lẫn clone đều không làm được: nhiều thư mục làm việc từ cùng một repository, mỗi thư mục checkout một nhánh riêng. Vì tất cả dùng chung object database (.git/objects), tạo worktree gần như tức thì — không cần copy hàng trăm MB như clone — và mọi commit đều nhìn thấy nhau ngay.

Cú pháp cơ bản

# Tạo worktree mới cho nhánh đã có
git worktree add ../repo-hotfix hotfix/critical-bug

# Tạo worktree và tự tạo nhánh mới từ đó
git worktree add ../repo-feature -b feature/new-auth

# Xem danh sách worktree đang có
git worktree list

Output của git worktree list trông như này:

/home/dev/myproject          abc1234 [main]
/home/dev/repo-hotfix        def5678 [hotfix/critical-bug]
/home/dev/repo-feature       ghi9012 [feature/new-auth]

Làm việc trong worktree

Sau khi tạo, vào folder worktree và làm việc bình thường như một repo thông thường — commit, push, pull đều dùng được:

cd ../repo-hotfix

# Sửa bug, commit, push
git add src/payment.js
git commit -m "fix: resolve null pointer in payment flow"
git push origin hotfix/critical-bug

# Quay lại repo chính
cd ../myproject
# Code feature vẫn còn nguyên, không bị ảnh hưởng gì

Dọn dẹp worktree sau khi xong

# Xóa thư mục worktree
git worktree remove ../repo-hotfix

# Nếu còn thay đổi chưa commit, dùng --force
git worktree remove --force ../repo-hotfix

# Dọn metadata của worktree đã bị xóa tay
git worktree prune

Ứng dụng thực tế trong team

Team mình 8 người, mỗi người thường cần đứng ở ít nhất hai nhánh cùng lúc: nhánh đang code và nhánh cần review cho đồng nghiệp. Vấn đề: review bị trì hoãn liên tục vì không ai muốn stash đống đang làm rồi checkout sang nhánh khác — với VSCode và ~600 file TypeScript, IDE load lại cả project mất khoảng 20-30 giây mỗi lần.

Sau khi chuyển sang worktree, quy trình review gọn hơn hẳn:

# Tạo worktree riêng cho việc review
git worktree add ../review-auth origin/feature/teammate-auth
cd ../review-auth

# Chạy test, xem code thoải mái mà không ảnh hưởng nhánh đang làm
npm install
npm test

# Xem log, diff dễ dàng
git log --oneline -10
git diff main...

PR được review trong ngày thay vì chờ 2-3 ngày như trước. Và vì nhánh được merge sớm hơn, merge conflict cũng ít đi đáng kể — nhánh không còn sống lâu đến mức drift xa main.

Một số điểm cần chú ý

Không thể checkout cùng một nhánh ở hai worktree. Nếu main đang được checkout ở worktree gốc, bạn không thể tạo thêm worktree cũng checkout main. Git báo lỗi ngay:

git worktree add ../another-main main
# fatal: 'main' is already checked out at '/home/dev/myproject'

Nên đặt worktree ngoài thư mục repo gốc. Nếu để bên trong, git status ở repo gốc sẽ thấy folder worktree là untracked directory. Đặt song song nhau (cùng parent folder) là gọn nhất:

~/projects/
├── myproject/          ← repo gốc (main branch)
├── myproject-hotfix/   ← worktree (hotfix branch)
└── myproject-review/   ← worktree (review branch)

Hook và config dùng chung. Git hooks trong .git/hooks/ chạy cho tất cả worktree. Có hook kiểm tra lint hay chạy test trước commit? Nó cũng hoạt động ở worktree phụ — nhất quán, không cần setup lại.

So sánh nhanh ba cách

Git Stash Clone thêm Git Worktree
Tốc độ setup Rất nhanh Chậm Nhanh
Dùng chung history Có Không Có
Chạy song song Không Có Có
Dùng chung hooks Có Không Có
Tốn disk thêm Thấp Cao Thấp

Với workflow đơn giản — làm xong, chuyển nhánh, không cần chạy song song — stash vẫn đủ dùng. Nhưng khi cần thực sự làm việc trên hai nhánh cùng lúc — review, test song song, xử lý hotfix giữa chừng feature — git worktree thắng hoàn toàn so với clone thêm. Nhanh hơn, không tốn disk, và mọi thứ vẫn trong cùng một repo.

Share: