git worktree: làm việc với nhiều nhánh cùng lúc
git worktree gắn nhiều thư mục làm việc vào một kho Git, mỗi thư mục mở một nhánh riêng. Lệnh git worktree add ../hotfix main tạo thư mục với nhánh main cạnh dự án, lịch sử và đối tượng được dùng chung, và không cần clone lại.
Git worktree làm gì
git worktree gắn nhiều thư mục làm việc vào cùng một kho lưu trữ. Trong thư mục chính bạn mở nhánh tính năng, còn ở thư mục bên cạnh là main để sửa lỗi khẩn — cả hai tồn tại đồng thời. Đối tượng, commit và nhánh được dùng chung: commit tạo ở thư mục này xuất hiện ngay ở thư mục khác, không cần push hay fetch.
Khi không có worktree, việc chuyển ngữ cảnh diễn ra như sau: git stash, git switch main, sửa lỗi, git switch quay lại, git stash pop. Nếu dự án có bản build lâu hoặc node_modules nặng, mỗi lần đổi nhánh còn làm mất cache. Cách khác là clone lại kho, nhưng khi đó có hai lịch sử độc lập phải đồng bộ qua máy chủ.
Worktree cho bạn cả hai ưu điểm: thư mục riêng nhưng dùng chung một .git. Điều này khả thi vì nhánh trong Git chỉ là một con trỏ tới commit, chứ không phải bản sao tệp, và không có gì cản các thư mục làm việc khác nhau trỏ tới các con trỏ khác nhau.
Cách tạo thêm thư mục làm việc
Cú pháp cơ bản: git worktree add <đường-dẫn> [<nhánh>]. Dưới đây là các biến thể chính.
Mở một nhánh đã có
cd ~/projects/shop
git worktree add ../shop-main main
Preparing worktree (checking out 'main')
HEAD is now at 3f2c1ab Cập nhật README
Cạnh dự án sẽ xuất hiện thư mục shop-main với nhánh main. Chuyển vào đó bằng cd thông thường và làm việc như trong bất kỳ kho nào khác.
Tạo nhánh mới cùng với thư mục làm việc
git worktree add -b hotfix/payment-timeout ../shop-hotfix main
Cờ -b tạo nhánh hotfix/payment-timeout từ main và mở nó trong thư mục mới. Cờ -B làm tương tự nhưng nếu nhánh đã tồn tại thì đặt lại nó về commit chỉ định — hãy dùng cẩn thận.
Dạng viết ngắn
git worktree add ../experiment
Nếu không chỉ định nhánh, Git tạo nhánh mới có tên là thành phần cuối của đường dẫn (ở đây là experiment) từ HEAD hiện tại. Nếu nhánh cùng tên đã có, nó sẽ được mở.
Thư mục làm việc không gắn nhánh
git worktree add --detach ../shop-v1.4 v1.4.0
Chế độ detached HEAD tiện để build hoặc kiểm tra một bản phát hành cũ theo thẻ mà không tạo nhánh thừa.
Nhánh lấy từ máy chủ
git fetch origin
git worktree add ../review-auth feature/auth
Nếu chưa có nhánh cục bộ feature/auth nhưng có đúng một nhánh từ xa origin/feature/auth, Git sẽ tạo nhánh cục bộ có theo dõi — giống như khi chạy git switch feature/auth. Cách này tiện để review pull request của người khác mà không đụng tới công việc đang làm.
Xem và xóa thư mục làm việc
git worktree list
/home/anna/projects/shop a1b2c3d [feature/cart]
/home/anna/projects/shop-hotfix 7e8f9a0 [hotfix/payment-timeout]
/home/anna/projects/shop-v1.4 5d6e7f8 (detached HEAD)
Dòng đầu là thư mục làm việc chính, các dòng sau là thư mục liên kết (linked). Với script có đầu ra máy đọc được: git worktree list --porcelain.
Khi hotfix đã được gộp, xóa thư mục làm việc:
git worktree remove ../shop-hotfix
git branch -d hotfix/payment-timeout
git worktree remove xóa thư mục và các bản ghi phụ trợ. Nếu trong thư mục có thay đổi chưa commit hoặc tệp chưa theo dõi, lệnh sẽ từ chối; chỉ thêm --force khi chắc chắn chúng không cần. Lưu ý: bản thân nhánh không bị xóa, nó cần được xóa riêng.
Nếu xóa thư mục bằng tay
Xóa thư mục qua trình quản lý tệp hoặc rm -rf để lại một bản ghi «mồ côi» trong .git/worktrees, và nhánh tiếp tục bị coi là đang bận. Dọn các bản ghi như vậy:
git worktree prune --verbose
Git cũng tự làm việc này định kỳ khi dọn rác, nhưng không cần chờ.
Cấu trúc bên trong
Trong thư mục làm việc liên kết, thay vì thư mục .git có một tệp .git chỉ gồm một dòng:
gitdir: /home/anna/projects/shop/.git/worktrees/shop-hotfix
Trong thư mục phụ trợ đó lưu dữ liệu riêng của từng thư mục làm việc: HEAD riêng, index riêng (staging area), trạng thái merge và rebase riêng. Mọi thứ còn lại là dùng chung: đối tượng, nhánh, thẻ, remote, cấu hình và hook.
| Riêng cho từng thư mục làm việc | Dùng chung |
|---|---|
| HEAD (nhánh hoặc commit hiện tại) | Đối tượng và toàn bộ lịch sử |
| Index (git add) | Nhánh cục bộ và từ xa, thẻ |
| Merge, rebase, cherry-pick đang dở | Stash (refs/stash dùng chung) |
| Các tệp trong thư mục làm việc | .git/config và các hook |
Hệ quả không hiển nhiên: git stash list trong bất kỳ thư mục nào cũng cho cùng danh sách. Điều này thậm chí tiện — bạn có thể cất thay đổi ở một thư mục và lấy ra ở thư mục khác.
Giới hạn chính: một nhánh chỉ được mở ở một thư mục
Không thể mở cùng một nhánh ở hai thư mục làm việc. Nếu thử, Git sẽ báo lỗi như sau:
git worktree add ../shop-copy feature/cart
fatal: 'feature/cart' is already used by worktree at '/home/anna/projects/shop'
(ở các phiên bản Git cũ thông báo là «is already checked out at»). Giới hạn này ngăn commit ở một thư mục âm thầm thay đổi nhánh dưới chân thư mục khác. Cách giải quyết: tạo nhánh mới từ cùng commit (-b), mở bản sao ở chế độ --detach, hoặc khi thật sự cần thì dùng --force và chấp nhận hệ quả.
Vì lý do tương tự, trong thư mục chính không thể chạy git switch main khi main đang mở ở thư mục liên kết khác.
Các kịch bản thực tế
Hotfix khẩn giữa lúc đang làm tính năng
git worktree add -b hotfix/null-price ../shop-hotfix main
cd ../shop-hotfix
# sửa lỗi, kiểm thử
git commit -am "Sửa lỗi khi giá trống"
git push -u origin hotfix/null-price
cd ../shop
git worktree remove ../shop-hotfix
Tính năng dang dở vẫn nguyên vẹn, không phải cất vào stash, và IDE đang mở dự án thậm chí không nhận ra có sự chuyển đổi nào.
Review pull request có chạy code
Thư mục riêng để review cho phép build và chạy nhánh của người khác, chạy test, trong khi bạn vẫn tiếp tục công việc của mình ở cửa sổ editor khác.
So sánh hành vi của hai phiên bản
Hai thư mục ứng với hai thẻ có thể được chạy song song trên các cổng khác nhau để so sánh, ví dụ, thời gian phản hồi của API trước và sau khi tối ưu.
Test và build dài
Chạy bộ test đầy đủ ở một thư mục, còn viết code ở thư mục khác — việc build không bị hỏng vì bạn sửa tệp.
Nhiều agent AI làm việc song song
Khi nhiều agent hoặc tiến trình cùng làm các công việc, mỗi bên có thể được cấp một thư mục làm việc riêng trên nhánh của mình: chúng không cản trở nhau, còn kết quả vào thẳng kho chung.
Cách tổ chức thư mục khi dùng worktree thường xuyên
Nếu bạn cần các thư mục làm việc hằng ngày, hãy có một quy ước rõ ràng, nếu không các thư mục cạnh nhau nhanh chóng thành bãi rác. Một mô hình phổ biến là một thư mục dự án cha chứa kho bare và mỗi nhánh một thư mục:
git clone --bare git@example.com:team/shop.git ~/projects/shop/.bare
cd ~/projects/shop
echo "gitdir: ./.bare" > .git
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch origin
git worktree add main
git worktree add -b feature/cart feature-cart main
Dòng với remote.origin.fetch cần thiết vì bản clone bare mặc định không thiết lập theo dõi nhánh từ xa. Kết quả là trong ~/projects/shop có các thư mục main và feature-cart, mỗi thư mục gắn một nhánh riêng, và không thư mục nào «quan trọng» hơn thư mục nào.
Thói quen tốt thứ hai là đặt tên thư mục giống tên nhánh (thay dấu gạch chéo bằng gạch ngang). Khi đó từ kết quả git worktree list và đường dẫn trong terminal luôn rõ bạn đang ở đâu. Và cuối cùng, hãy xóa thư mục ngay sau khi nhánh được gộp: các thư mục cũ chiếm chỗ và giữ các nhánh ở trạng thái «bận».
Lỗi thường gặp và điều cần lưu ý
- Dependencies và build không dùng chung. Mỗi thư mục là một thư mục riêng, nên
node_modules, môi trường ảo Python,.envvà sản phẩm build phải tạo lại. Tệp chưa theo dõi không được chuyển sang thư mục mới. - Thư mục làm việc đặt bên trong thư mục chính. Lệnh
git worktree add ./hotfixsẽ tạo thư mục bên trong dự án, và thư mục chính sẽ coi nó là tệp chưa theo dõi. Hãy đặt các thư mục cạnh nhau (../) hoặc trong một thư mục riêng, hoặc thêm đường dẫn vào.gitignore. - Di chuyển thư mục bằng tay. Liên kết sẽ bị hỏng. Hãy di chuyển bằng
git worktree move ../cũ ../mới; nếu đã lỡ di chuyển, chạygit worktree repairtrong thư mục mới. - Thư mục trên ổ rời biến mất. Để prune không xóa bản ghi về thư mục trên ổ đã ngắt kết nối, hãy khóa nó:
git worktree lock --reason "ổ ngoài" ../shop-usb. - Submodule. Hỗ trợ submodule trong thư mục làm việc còn hạn chế; sau khi tạo thư mục hãy chạy
git submodule update --initvà kiểm tra kết quả.
Bảng tra cứu git worktree
| Việc cần làm | Lệnh |
|---|---|
| Mở nhánh đã có trong thư mục mới | git worktree add ../dir nhánh |
| Tạo nhánh và thư mục | git worktree add -b nhánh-mới ../dir main |
| Thư mục không gắn nhánh (thẻ, commit) | git worktree add --detach ../dir v1.0 |
| Danh sách thư mục | git worktree list |
| Xóa thư mục | git worktree remove ../dir |
| Dọn bản ghi thư mục đã mất | git worktree prune |
| Di chuyển thư mục | git worktree move ../dir ../dir-mới |
| Sửa liên kết sau khi chuyển | git worktree repair |
| Bảo vệ khỏi prune | git worktree lock ../dir |
git worktree, stash hay clone thứ hai
| Tiêu chí | stash | worktree | clone thứ hai |
|---|---|---|---|
| Tốc độ chuyển đổi | Nhanh, nhưng kèm đổi nhánh | Tức thì — chỉ là thư mục khác | Tức thì |
| Dung lượng đĩa | Tối thiểu | Chỉ các tệp làm việc | Toàn bộ lịch sử |
| Đồng bộ | Không cần | Không cần, lịch sử dùng chung | Qua push/fetch |
| Làm việc song song | Không | Có | Có |
Stash vẫn là lựa chọn tốt nhất cho việc gián đoạn ngắn chỉ vài phút. Với mọi việc kéo dài hơn, hoặc khi cần giữ hai phiên bản mở cùng lúc, worktree tiện hơn.
Tóm lại
git worktree là cách đơn giản để làm việc với nhiều nhánh cùng lúc: add tạo thư mục, list liệt kê, còn remove và prune dọn dẹp. Lịch sử được dùng chung, còn HEAD, index và tệp của mỗi thư mục là riêng; một nhánh không thể mở ở hai thư mục cùng lúc. Vì sao chuyển nhánh nhẹ đến vậy và các nhánh hoạt động ra sao được chúng tôi giải thích thực hành trong khóa học Git.
Câu hỏi thường gặp
git worktree có từ phiên bản Git nào?
Lệnh xuất hiện từ Git 2.5 và sau đó được bổ sung nhiều, ví dụ remove và move ra đời muộn hơn. Với mọi phiên bản Git hiện đại, tất cả các lệnh trên đều dùng được.
Commit ở một thư mục có nhìn thấy ở thư mục khác không?
Có, lịch sử dùng chung. Commit hiện ngay trong git log ở mọi thư mục, và có thể gộp bằng git merge mà không cần push hay fetch.
IDE có nhận ra nhiều thư mục làm việc không?
Với IDE, mỗi thư mục là một thư mục dự án thông thường, mở trong cửa sổ riêng. Nhiều editor cũng hiển thị danh sách thư mục làm việc trong giao diện Git tích hợp.
git worktree remove có xóa nhánh không?
Không, chỉ xóa thư mục và bản ghi phụ trợ. Nhánh cần xóa riêng bằng git branch -d.
git worktree có dùng được với kho bare không?
Có, một mô hình phổ biến là giữ bản clone bare và tạo thư mục làm việc cho từng nhánh từ đó; khi ấy không có thư mục chính chứa tệp nào cả.
Chủ đề này được giảng chi tiết kèm thực hành trong khóa học “Git с нуля до уверенного разработчика”.
Đến khóa học