Bài stash giải bài toán "đổi việc gấp" bằng cách cất tạm. Nhưng có tình huống cần mạnh hơn: bạn muốn làm hai nhánh cùng lúc thật sự — đang code tính năng ở nhánh A, đồng thời cần build và chạy nhánh B để so, hay review một PR trong khi vẫn giữ nguyên công việc dở của mình. Stash thì phải chuyển qua chuyển lại (mất ngữ cảnh); clone lại kho thì tốn dung lượng và tách rời khỏi remote/stash gốc. git worktree giải đúng chỗ này: một kho .git dùng chung, nhiều thư mục làm việc, mỗi thư mục ở một nhánh khác nhau. Đo thật bằng git 2.39.

Một .git, nhiều working tree

Bình thường một kho Git có một thư mục .git và một working tree. git worktree add tạo thêm working tree — một thư mục riêng, ở một nhánh riêng — nhưng dùng chung cùng .git (object, ref, config, remote, stash đều chung).

git worktree add ../wt-B tinh-nang   # tạo cây mới ở nhánh tinh-nang
git worktree list                     # liệt kê các cây + nhánh
git worktree remove ../wt-B           # gỡ cây khi xong
git worktree prune                    # dọn cây đã xóa tay

Ảnh chụp đoạn mã nền tối giải thích git worktree một kho .git nhiều thư mục làm việc, vấn đề cần làm hai nhánh cùng lúc đang code nhánh A cần build test xem nhánh B song song cách cũ stash rồi đổi nhánh mất ngữ cảnh hoặc clone lại tốn dung lượng tách rời khỏi kho gốc git worktree một .git dùng chung nhiều thư mục làm việc mỗi thư mục ở một nhánh khác nhau, các lệnh worktree git worktree add wt-B tinh-nang tạo cây mới ở nhánh tinh-nang git worktree list liệt kê các cây và nhánh git worktree remove gỡ cây khi xong git worktree prune dọn cây đã xóa tay, lợi thế và một quy tắc chung .git commit ở cây này cây kia thấy ngay không cần push pull nhẹ hơn clone không nhân đôi lịch sử giữ nguyên remote stash quy tắc không checkout cùng một nhánh ở hai cây cùng lúc tránh hai nơi ghi đè con trỏ nhánh Git chặn

Hình 1: git worktree cho một .git dùng chung nhưng nhiều thư mục làm việc, mỗi cái ở một nhánh. Nhẹ hơn clone (không nhân đôi lịch sử), giữ chung remote/stash. Quy tắc: không checkout cùng một nhánh ở hai cây.

Đo thật: hai cây, hai nhánh, làm việc song song

Ảnh chụp bảng kết quả đo thật nền tối chạy git 2.39, phần một worktree add cộng list git worktree add wt-tinhnang tinh-nang git worktree list main-repo 0b6829c master wt-tinhnang 0b6829c tinh-nang 2 cây 2 nhánh, phần hai làm việc song song độc lập main-repo nhánh master sửa app.txt wt-tinhnang nhánh tinh-nang thêm feature.txt cộng commit không cần stash clone lại hai cây không đụng nhau, phần ba chung một .git commit thấy được từ cả hai từ main-repo git log tinh-nang 145c503 feat commit vừa tạo ở cây kia thấy ngay 0b6829c base, phần bốn không checkout cùng nhánh ở hai cây git worktree add wt-master master fatal master is already checked out at main-repo

Hình 2: worktree list cho thấy hai cây main-repo [master] và wt-tinhnang [tinh-nang]. Mỗi cây làm việc độc lập; commit 145c503 feat tạo ở cây tinh-nang được thấy ngay từ main-repo (git log tinh-nang). Thử checkout master ở cây thứ hai → fatal: 'master' is already checked out.

Kết quả làm rõ mọi thứ:

  • Nhiều cây một lệnh: git worktree add ../wt-tinhnang tinh-nang tạo thư mục wt-tinhnang đã checkout sẵn nhánh tinh-nang. git worktree list liệt kê cả hai cây kèm nhánh của mỗi cây.
  • Làm việc song song thật: sửa app.txt ở main-repo (master) và commit feature.txt ở wt-tinhnang (tinh-nang) — hai cây độc lập, không đụng nhau, không cần stash hay đổi nhánh qua lại. Bạn có thể mở hai cửa sổ terminal / hai cửa sổ IDE trên hai thư mục.
  • Chung một .git: commit 145c503 feat vừa tạo ở cây tinh-nang được thấy ngay từ main-repo (git log tinh-nang) — vì object và ref dùng chung, không cần push/pull giữa hai cây. Đây là khác biệt cốt lõi với việc clone hai bản (clone thì phải push/pull để đồng bộ).
  • Quy tắc một nhánh một cây: thử git worktree add ../wt-master master → fatal: 'master' is already checked out at 'main-repo'. Git cấm checkout cùng một nhánh ở hai cây cùng lúc, vì hai working tree cùng ghi đè con trỏ nhánh sẽ hỏng. Mỗi nhánh chỉ được một cây "giữ".

Đánh đổi và lưu ý

Worktree lý tưởng cho: build/test song song, review PR, hotfix. Ví dụ: git worktree add ../hotfix main để sửa bug production ở một thư mục riêng, build và deploy, trong khi thư mục chính vẫn giữ nguyên công việc dở — không stash, không mất trạng thái IDE. Hay CI/build một nhánh trong khi bạn code nhánh khác.

Nhớ dọn bằng git worktree remove, đừng xóa thư mục tay. Nếu xóa thư mục worktree bằng rm -rf mà không git worktree remove, Git vẫn giữ metadata "ma" trong .git/worktrees — dọn bằng git worktree prune. Và một worktree có thay đổi chưa commit thì remove bị chặn (dùng --force nếu chắc chắn bỏ).

File không theo dõi và build artifact không chia sẻ. Mỗi cây có working tree riêng, nên node_modules/, file build, cấu hình cục bộ không dùng chung — mỗi cây phải cài/build riêng. Đây vừa là điểm mạnh (cô lập) vừa là chi phí (tốn chỗ cho mỗi cây). Với dự án có bước cài đặt nặng, cân nhắc.

Ba ý mang về

  1. git worktree cho một .git dùng chung, nhiều thư mục làm việc ở các nhánh khác nhau — đo thật, main-repo [master] và wt-tinhnang [tinh-nang] làm việc song song độc lập, không cần stash/clone lại.
  2. Chung object/ref nên đồng bộ tức thì: commit ở cây này (145c503 feat) thấy ngay từ cây kia mà không cần push/pull — nhẹ hơn clone (không nhân đôi lịch sử), giữ chung remote/stash.
  3. Một nhánh chỉ một cây: Git chặn checkout cùng nhánh ở hai cây (fatal: already checked out); nhớ git worktree remove/prune để dọn, và file untracked/build không chia sẻ giữa các cây.

Nguồn

Phần sau ta xử lý một kiểu "repo trong repo" khác — git submodule: nhúng một kho Git vào kho khác, con trỏ commit cố định, và vì sao submodule hay gây rối nếu không hiểu cơ chế.