Jesteś w trakcie zmian w trzech plikach na feature branchu, nic jeszcze nie zacommitowane, gdy kolega pisze o null-pointerze, który wywala produkcję. Standardowy ruch to git stash, checkout na main, poprawka, push, a potem git stash pop w nadziei, że nic w twojej niedokończonej funkcjonalności nie zależało od plików, od których właśnie odszedłeś. git worktree pomija całą tę żonglerkę. Robi checkout brancha z hotfixem do drugiego folderu, obok twojego feature brancha, a oba korzystają z tego samego repozytorium.

Co właściwie robi git worktree

Zwykły checkout daje ci pliki jednego brancha naraz. Przełączenie brancha nadpisuje te pliki w miejscu. git worktree daje ci kilka checkoutów tego samego repozytorium, każdy w swoim katalogu i na swoim branchu, które możesz edytować niezależnie od siebie.

To nie są osobne klony. Istnieje dokładnie jeden katalog .git, który przechowuje bazę obiektów, referencje i konfigurację, a każdy worktree czyta z niego i do niego zapisuje. W drugim worktree .git nie jest nawet katalogiem — to jednolinijkowy plik wskazujący z powrotem na wspólny katalog. Dlatego stworzenie worktree jest prawie natychmiastowe i nie dodaje żadnej historii na dysku.

Jedno ograniczenie ma znaczenie. Dwa worktree nie mogą mieć tego samego brancha zacheckoutowanego naraz, bo branch wskazuje na jeden aktualny commit, a dwa checkouty commitujące do niego rywalizowałyby o ten wskaźnik. Wszystko inne jest przypisane do konkretnego worktree: pliki nieśledzone, indeks i to, na jakim commicie stoi HEAD.

Jak stworzyć worktree na hotfix

Masz już checkout myapp, siedzisz na branchu feature/checkout-flow, z niezacommitowanymi zmianami:

1
git worktree add ../myapp-hotfix -b hotfix/null-pointer main

To tworzy ../myapp-hotfix obok twojego bieżącego katalogu, z nowym branchem hotfix/null-pointer, utworzonym z main i zacheckoutowanym w tym nowym worktree. Twój oryginalny katalog zostaje na feature/checkout-flow, niezapisany i nietknięty.

1
2
3
4
cd ../myapp-hotfix
# poprawka, commit, push
git push -u origin hotfix/null-pointer
cd ../myapp

Z powrotem w oryginalnym katalogu twoja praca nad funkcjonalnością jest dokładnie taka, jaką ją zostawiłeś. Nic do pop, żadnego stasha, o którym można zapomnieć.

Bez -b, git worktree add <path> nazywa branch po ostatnim elemencie ścieżki. Jeśli branch o tej nazwie nie istnieje, Git tworzy go z HEAD; jeśli istnieje i nie jest zacheckoutowany w innym worktree, Git po prostu go checkoutuje. Użyj -d (--detach), gdy chcesz pogrzebać w konkretnym commicie bez żadnego brancha.

Jak wylistować, usunąć i wyczyścić worktree

1
git worktree list
1
2
/home/user/myapp          3a1f9c2 [feature/checkout-flow]
/home/user/myapp-hotfix   7e04d81 [hotfix/null-pointer]

Gdy hotfix zostanie zmergowany, usuń worktree przez Gita, a nie przez usunięcie folderu:

1
git worktree remove ../myapp-hotfix

remove odmawia, jeśli worktree ma zmodyfikowane pliki śledzone albo nieśledzone. Dodaj -f, żeby to wymusić. Jeśli katalog zniknie w inny sposób (przypadkowy rm -rf, padnięty job CI), Git zachowuje swój wpis administracyjny i git worktree list wciąż go pokazuje. Usuń nieaktualny wpis:

1
git worktree prune

Najpierw uruchom to z -n, żeby zobaczyć, co by usunęło.

Niektóre worktree powinny zostać na tygodnie: długo żyjący branch z release’em albo checkout na dysku sieciowym, który nie jest zawsze zamontowany. Zablokuj je, żeby prune nie dotykał ich wpisu, a move i remove odmawiały na nich działania:

1
2
git worktree lock --reason "release branch, do not prune" ../myapp-release
git worktree unlock ../myapp-release

Odblokuj najpierw, jeśli chcesz przenieść worktree za pomocą git worktree move <path> <new-path>. Przeniesienie albo usunięcie zablokowanego worktree bez odblokowania wymaga --force podanego dwa razy — to ma być świadome, celowe obejście.

Kiedy jeszcze używać git worktree, nie tylko do hotfixów

Zawsze, gdy potrzebujesz dwóch działających checkoutów naraz, nie jednego:

  • Przegląd PR bez utraty miejsca pracy. git worktree add ../myapp-review origin/some-pr-branch daje ci kompilowalną kopię czyjegoś brancha, a twoja własna praca zostaje zacheckoutowana tam, gdzie była.
  • Odpalenie git bisect bez blokowania wszystkiego innego. Bisect przesuwa HEAD na każdym kroku, więc checkout, w którym działa, staje się bezużyteczny do czegokolwiek innego, aż skończysz albo zrobisz reset. Odpal go w dedykowanym worktree (zobacz Git Bisect: Jak Znaleźć Commit, który Wprowadził Buga) i pracuj dalej w głównym.
  • Dwa zadania na repo w tym samym czasie. Długi test suite na jednym branchu, podczas gdy edytujesz drugi, albo dwa agenty AI do kodowania na osobnych zadaniach: każdy potrzebuje swojego katalogu roboczego. Worktree dostarcza go bez drugiego git clone i drugiego, wielogigabajtowego folderu .git.

Kiedy nie używać git worktree

Każdy worktree duplikuje working tree, nie bazę obiektów. Dziesięć worktree repozytorium z 50 MB checkoutem to z grubsza 500 MB plików na dysku, nawet z jednym .git. Na pięciominutowe przełączenie kontekstu git stash jest tańszy i nie zostawia nic do czyszczenia.

Submoduły są tutaj najsłabszym ogniwem. git worktree move nie przeniesie worktree, który zawiera submoduły, a nowy worktree zaczyna z pustymi katalogami submodułów, aż uruchomisz w nim git submodule update --init. Sama dokumentacja Gita nazywa wsparcie dla submodułów w wielu checkoutach niekompletnym, więc dla superprojektu z wieloma submodułami bezpieczniejszym wyborem jest osobny klon.

Część narzędzi też zakłada jeden katalog roboczy na repozytorium. IDE albo file-watcher, który buduje cache na podstawie absolutnej ścieżki repo, może się pogubić, widząc tę samą historię w dwóch miejscach. Otworzenie każdego worktree jako osobnego projektu, a nie jako podfolderu pierwszego, zwykle to rozwiązuje.

Jeśli potrzebujesz tylko odłożyć coś na bok albo cofnąć zmianę w tym, co już masz zacheckoutowane, lżejszym narzędziem jest git stash albo git reset, revert czy restore. Następnym razem, gdy hotfix wyląduje w środku pracy nad funkcjonalnością, spróbuj git worktree add przed git stash i zobacz, po którym łatwiej posprzątać.

Powiązane artykuły