Перейти до вмісту

Модуль 5: Майстерність багатозадачності — Worktrees та Stashing

Модуль 5: Майстерність багатозадачності — Worktrees та Stashing

Розділ «Модуль 5: Майстерність багатозадачності — Worktrees та Stashing»

Що ви зможете зробити

Розділ «Що ви зможете зробити»

До кінця цього модуля ви зможете:

  • Впровадити git worktree для керування паралельними потоками розробки в кількох гілках без порушення роботи вашого основного робочого каталогу.
  • Діагностувати та вирішити проблеми з покинутими або від’єднаними worktrees за допомогою життєвих команд, таких як prune та remove.
  • Оцінити точні технічні компроміси між git stash, git worktree та декількома клонами репозиторію для вибору оптимальної стратегії перемикання контексту в конкретному сценарії.
  • Виконати розширені операції зі стешем, включаючи ізоляцію невідстежуваних файлів, застосування конкретних стешів зі стеку та відновлення застешених змін в ізольованих гілках.
  • Спроектувати стійкий робочий процес локальної розробки, який запобігає втраті незакомічених станів під час критичних переривань у продакшені.

Це сталося у вівторок пообіді в одній фінтех-компанії середнього розміру. Провідний інженер платформи заглибився у складний рефакторинг конфігурації Kubernetes ingress-контролера. Робочий каталог нагадував поле битви: модифіковані YAML-файли, наполовину написані тести на Go для кастомного оператора та тимчасово підправлені значення Helm. Інженер був повністю зосереджений на складному ланцюжку залежностей між новим проміжним ПЗ (middleware) автентифікації та маршрутами ingress.

Раптом спрацював PagerDuty. Було виявлено критичну вразливість у поточному продакшен-деплої ingress-контролера, і повідомлялося про її активну експлуатацію в реальних умовах. Команда безпеки вимагала негайного випуску хотфіксу в гілку main. У інженера були лічені секунди на реакцію. Панікуючи через можливу втрату складного, незакоміченого локального стану, він виконав git stash. Потім перейшов на main, застосував хотфікс, зробив коміт і пуш. Коли він повернувся до своєї функціональної гілки і виконав git stash pop, його зустріла величезна стіна конфліктів злиття. Хотфікс змінив ті самі блоки конфігурації, які він рефакторив. У поспіху він також забув застешити невідстежувані файли, залишивши своє локальне середовище в несумісному, зламаному стані. Знадобилося чотири години лише на те, щоб розплутати конфлікти стешу та відновити хід думок. Фінансові втрати від початкової вразливості були нульовими завдяки швидкому виправленню, але втрата швидкості розробки та величезне розчарування були колосальними.

Цей сценарій розігрується щодня в інженерних командах по всьому світу. Фундаментальна проблема полягає в тому, що гілки Git за замовчуванням використовують один робочий каталог. Коли потреби реального світу змушують вас швидко перемикати контекст, цей єдиний робочий каталог стає вузьким місцем і значним ризиком для вашої незакоміченої роботи. Цей модуль навчить вас, як повністю усунути це обмеження. Ви дізнаєтеся, як використовувати Git Stash для незначних, тимчасових збережень стану, і, що важливіше, як опанувати Git Worktrees для підтримки кількох паралельних ізольованих робочих каталогів на базі одного локального репозиторію. Опанування цих інструментів перетворить вас із реактивного інженера, що намагається врятувати свій стан, на методичного оператора, який обробляє надзвичайні ситуації в продакшені без жодних перешкод для поточної розробки.

Проблема перемикання контексту

Розділ «Проблема перемикання контексту»

Основна архітектура стандартного клону Git передбачає один каталог .git і одне робоче дерево (actual files you edit). Коли ви перемикаєте гілки за допомогою git checkout або git switch, Git агресивно перезаписує файли у вашому робочому дереві, щоб вони відповідали стану цільової гілки.

Якщо у вас є незакомічені зміни — модифіковані відстежувані файли, підготовлені зміни або невідстежувані файли — Git часто відмовляється перемикати гілки, якщо ці зміни конфліктують із цільовою гілкою. Навіть якщо він дозволяє перемикання, перенесення незакомічених змін між гілками є рецептом для випадкових комітів та пошкодження стану.

Історично розробники використовували два основні обхідні шляхи для подолання цього обмеження при перериваннях:

  1. Стратегія декількох клонів: Кожного разу, коли виникає нове завдання або хотфікс, розробник виконує git clone у абсолютно новий каталог.
  2. Стратегія “Застеш і молися”: Розробник використовує git stash, щоб сховати незакомічені зміни, перемикає гілки, виконує роботу, повертається назад і намагається зробити pop змін.

Обидва підходи є фундаментально недосконалими для професійної високоефективної інженерії.

Справжня ціна декількох клонів

Розділ «Справжня ціна декількох клонів»

Хоча клонування репозиторію кілька разів забезпечує ідеальну ізоляцію, це неймовірно неефективно. Розглянемо великий монорепозиторій, що містить мікросервіси, маніфести Kubernetes та код Terraform. Один клон може споживати кілька гігабайтів дискового простору, а його завантаження може тривати хвилини.

Якщо ви створюєте новий клон для кожного хотфіксу чи рев’ю коду, ви щоразу дублюєте всю історію Git (базу об’єктів у каталозі .git).

Крім того, ці клони повністю від’єднані один від одного локально. Якщо ви завантажите останні зміни з віддаленого репозиторію в Клоні А, Клон Б залишиться про них абсолютно не поінформованим. Ви повинні виконувати мережеві операції в кожному окремому клоні, щоб підтримувати їх синхронізованими. Якщо ви хочете протестувати гілку з Клону А проти конфігурації в Клоні Б, вам доведеться робити пуш у віддалений репозиторій і пулл, або возитися з визначенням локальних remote-посилань. Це кошмар обслуговування, замаскований під рішення.

git stash — це вбудований механізм, який бере “брудний” стан вашого робочого каталогу — ваші модифіковані відстежувані файли та підготовлені зміни — і зберігає їх у стеку незавершених змін, повертаючи робочий каталог до чистого стану, що відповідає коміту HEAD.

Для дуже коротких, локалізованих переривань (наприклад, стягування останніх змін перед пушем), git stash є цілком адекватним. Однак він вкрай погано масштабується, коли використовується як основний інструмент перемикання контексту для складної роботи.

Коли ви стешите зміни, вони втрачають свій безпосередній контекст. Якщо ви застешите роботу, проведете три дні над хотфіксом, а потім спробуєте відновити стеш, ви часто забуваєте, що саме представляють ці застешені зміни. Що критичніше, якщо основна гілка значно просунулася вперед або якщо ви спробуєте застосувати стеш до іншої гілки, ви зіткнетеся з серйозними, іноді невирішуваними конфліктами злиття.

Зупиніться та подумайте: як ви гадаєте, що станеться, якщо ви виконаєте git stash, маючи щойно створені файли, для яких ви ще не виконали git add?

Подумайте про те, як Git відстежує файли, перш ніж читати далі.

За замовчуванням git stash зберігає зміни лише у файлах, які Git уже відстежує. Щойно створені файли залишаються абсолютно незачепленими у вашому робочому каталозі. Це часто призводить до ситуацій, коли розробник думає, що він застешив увесь свій стан, перемикає гілки і виявляє, що його нові файли захаращують гілку хотфіксу, що потенційно спричиняє помилки збірки або випадкове включення файлів у коміт.

Опанування Git Stash для мікро-переривань

Розділ «Опанування Git Stash для мікро-переривань»

Незважаючи на обмеження для тривалого перемикання контексту, git stash є незамінним інструментом для мікро-переривань. Щоб використовувати його безпечно, ви повинні вийти за межі базових команд git stash та git stash pop і зрозуміти, як ефективно керувати стеком стешів.

Створення висококонтекстних стешів

Розділ «Створення висококонтекстних стешів»

Ніколи не запускайте git stash без повідомлення. Стек стешів, заповнений загальними записами WIP on branch-name, стає практично марним уже за кілька годин. Завжди використовуйте підкоманду push із прапорцем -m, щоб надати контекст.

Terminal window
# Погана практика
git stash
# Хороша практика
git stash push -m "Mid-refactor of deployment.yaml resource limits"

Якщо ви працюєте над новою функцією та створили нові маніфести Kubernetes, які ще не відстежуються Git, ви повинні явно наказати команді стешу включити їх, використовуючи прапорець -u (або --include-untracked).

Terminal window
# Стешить відстежувані зміни ТА невідстежувані нові файли
git stash push -u -m "Added new redis-deployment.yaml and modified configmap"

Якщо ви хочете бути неймовірно прискіпливим, ви можете використовувати прапорець -a (або --all), який стешить відстежувані файли, невідстежувані файли і навіть файли, ігноровані у .gitignore. Це рідко буває необхідним, але корисно, якщо вам потрібно повністю очистити каталог для тестування.

Навігація та перегляд стеку стешів

Розділ «Навігація та перегляд стеку стешів»

Кожного разу, коли ви створюєте стеш, він додається у стек. Ви можете переглянути цей стек за допомогою git stash list.

Terminal window
git stash list

Вивід виглядатиме приблизно так:

stash@{0}: On feature-auth: Added new redis-deployment.yaml and modified configmap
stash@{1}: On main: Mid-refactor of deployment.yaml resource limits

Найновіший стеш — це завжди stash@{0}. Коли ви додаєте нові, старіші опускаються нижче по стеку (їхній індекс збільшується).

Перед застосуванням стешу ви часто хочете побачити, які саме зміни він містить. Ви можете використовувати підкоманду show із прапорцем -p (patch) для перегляду точної диференціації (diff) застешених змін.

Terminal window
git stash show -p stash@{1}

Спробуйте зараз: Ініціалізуйте тимчасовий git-репозиторій, створіть файл, закомітьте його, змініть файл і застеште зміни. Виконайте git stash list, потім git stash show -p stash@{0}, щоб побачити ваші застешені зміни у форматі патча.

Зупиніться та поміркуйте: У вас є 3 стеші. Ви застосовуєте stash@{1}, і це спрацьовує ідеально. Яким буде стан вашого стеку стешів тепер? Чи щось змінилося?

Оскільки ви використали apply замість pop, стек стешів залишається точно таким самим. stash@{1} усе ще безпечно перебуває в стеку. Індексні номери ваших стешів не змінюються, що дозволяє вам звертатися до них або видалити їх вручну пізніше.

Відновлення стану: Apply проти Pop

Розділ «Відновлення стану: Apply проти Pop»

Коли ви будете готові продовжити роботу, у вас є два варіанти: apply або pop.

git stash apply бере зміни із зазначеного стешу і застосовує їх до вашого поточного робочого каталогу, але залишає стеш недоторканим у стеку. Це найбезпечніша операція. Якщо застосування призведе до величезних конфліктів і ви перервете процес, ваш застешений стан усе ще буде надійно збережений.

Terminal window
# Застосовує найновіший стеш
git stash apply
# Застосовує конкретний стеш зі стеку
git stash apply stash@{1}

git stash pop застосовує зміни і, якщо застосування успішне (немає конфліктів), негайно видаляє стеш зі стеку. Хоча це зручно, це може бути небезпечно, якщо ви трохи запізно зрозумієте, що застосували стеш не до тієї гілки.

Як загальне правило для критичного коду інфраструктури: завжди використовуйте git stash apply, перевіряйте стан, а потім вручну видаляйте стеш за допомогою git stash drop, коли будете впевнені, що він вам більше не потрібен.

Terminal window
# Видалити конкретний стеш
git stash drop stash@{1}
# Очистити весь стек стешів (використовуйте з обережністю)
git stash clear

Рятувальний люк: створення гілки зі стешу

Розділ «Рятувальний люк: створення гілки зі стешу»

Що станеться, якщо ви застешите складні зміни, попрацюєте тиждень над іншими речами, а потім спробуєте застосувати стеш назад до своєї початкової гілки, але виявите, що гілка настільки еволюціонувала, що конфлікти стали непереборними?

Git надає блискучий рятувальний люк: git stash branch. Ця команда створює абсолютно нову гілку, починаючи з того самого коміту, на якому ви були, коли створювали стеш, застосовує стеш до цієї нової гілки, а потім видаляє його.

Terminal window
git stash branch recovered-auth-work stash@{0}

Це ізолює ваші застешені зміни в безпечному середовищі. Потім ви можете спокійно закомітити їх у нову гілку і вирішити, як їх злити або перебазувати (rebase) у головну гілку у власному темпі, не стикаючись із негайними конфліктами в робочому каталозі.

Міні-вправа: стешинг невідстежуваних файлів

Розділ «Міні-вправа: стешинг невідстежуваних файлів»

Перш ніж перейти до worktrees, давайте потренуємо повний робочий процес стешу, зокрема обробку невідстежуваних файлів та перевірку стеку.

  1. Ініціалізуйте новий репозиторій Git, який буде вашим основним робочим простором:
    Terminal window
    mkdir stash-practice && cd stash-practice
    git init
  2. Створіть початковий коміт, щоб встановити чисте робоче дерево:
    Terminal window
    echo "v1" > config.txt
    git add config.txt
    git commit -m "Initial commit"
  3. Змініть відстежуваний файл і створіть новий, невідстежуваний файл:
    Terminal window
    echo "v2" > config.txt
    echo "secret-key" > .env
  4. Застеште всі зміни, включаючи невідстежуваний файл:
    Terminal window
    git stash push -u -m "WIP on new config and secrets"
  5. Перегляньте стек стешів та вміст останнього стешу:
    Terminal window
    git stash list
    git stash show -p stash@{0}
  6. Відновіть застешені зміни, не видаляючи їх зі стеку:
    Terminal window
    git stash apply stash@{0}
    Зверніть увагу, що ваші модифікації у config.txt та новий файл .env знову з’явилися у вашому робочому каталозі.

Потужність Git Worktrees

Розділ «Потужність Git Worktrees»

Якщо git stash — це тимчасовий пластир, то git worktree — це постійне архітектурне рішення для перемикання контексту.

Впроваджені в Git 2.5, worktrees дозволяють мати кілька незалежних робочих каталогів, підключених до одного репозиторію Git. Це означає, що у вас може бути гілка main в одному каталозі, feature-auth — в іншому, а hotfix-ingress — у третьому, і все це одночасно.

Що важливо, оскільки вони використовують одну спільну базу об’єктів .git:

  1. Вони споживають дуже мало додаткового дискового простору (лише розмір розгорнутих файлів, а не всієї історії).
  2. Вони миттєво діляться мережевим станом. Якщо ви виконаєте git fetch в одному worktree, оновлені віддалені гілки негайно стануть доступними у всіх інших worktrees.
  3. Ви можете легко переносити коміти (cherry-pick) або зливати їх між ними без необхідності пушити у віддалений репозиторій.

Давайте візуалізуємо, як worktrees структуровані на диску.

Коли ви виконуєте git clone, ви створюєте “основне” робоче дерево (main worktree). Усередині цього каталогу знаходиться стандартна папка .git, що містить усі дані репозиторію.

+-------------------------------------------------+
| Main Worktree: /projects/k8s-operator |
| |
| deploy/ |
| src/ |
| go.mod |
| .git/ <-- Справжня база даних репозиторію |
| objects/ |
| refs/ |
| worktrees/ <-- Конфігурації під-worktrees |
+-------------------------------------------------+

Коли ви додаєте нове пов’язане робоче дерево (наприклад, у сусідньому каталозі), Git не копіює репозиторій. Замість цього він створює спеціальний файл .git (не каталог) у новому місці. Цей файл містить один рядок, що вказує на основний репозиторій. Всередині каталогу .git/worktrees/ основного репозиторію Git зберігає специфічний стан HEAD та індексу для цього пов’язаного робочого дерева.

+-------------------------------------------------+
| Linked Worktree: /projects/k8s-operator-hotfix |
| |
| deploy/ |
| src/ |
| go.mod |
| .git <-- ФАЙЛ, що вказує на основний репозиторій|
| (gitdir: /projects/k8s-operator/.git/worktrees/hotfix)
+-------------------------------------------------+

Така архітектура забезпечує ідеальну ізоляцію робочого дерева та області підготовки (індексу), зберігаючи при цьому повністю єдину історію комітів та мережевий стан.

Зупиніться та поміркуйте: Якщо ви виконаєте git fetch у worktree A, чи потрібно вам знову виконувати git fetch у worktree B, щоб побачити оновлені віддалені гілки? Чому так або чому ні?

Ні, вам не потрібно запускати це знову. Оскільки всі пов’язані worktrees використовують одну і ту саму базу об’єктів .git та посилання в основному репозиторії, мережева операція в одному worktree миттєво оновлює стан репозиторію для всіх них.

Створення та керування Worktrees

Розділ «Створення та керування Worktrees»

Для створення нового робочого дерева використовується команда git worktree add. Ви вказуєте шлях, де має бути створений новий каталог, і, опціонально, гілку, яку хочете розгорнути.

Якщо ви працюєте в /projects/k8s-operator і з’являється терміновий баг у гілці main, вам не потрібно стешити поточну роботу. Ви просто створюєте новий worktree для хотфіксу.

Terminal window
# Використання: git worktree add <path> <branch>
# Створити новий каталог поруч із поточним,
# створити нову гілку 'hotfix-cve'
# і розгорнути її, починаючи від 'main'
git worktree add -b hotfix-cve ../k8s-operator-hotfix main

Git виведе:

Preparing worktree (new branch 'hotfix-cve')
HEAD is now at 8f3a9b2 Update ingress documentation

Тепер у вас є абсолютно чистий робочий каталог у ../k8s-operator-hotfix на гілці hotfix-cve. Ваш початковий каталог залишається недоторканим, саме таким, яким ви його залишили. Ви можете відкрити нову вкладку терміналу, перейти до каталогу хотфіксу, виправити вразливість, протестувати її, закомітити та запушити.

Як тільки хотфікс буде злитий, ви просто закриваєте ту вкладку терміналу, повертаєтеся до початкової вкладки і продовжуєте роботу над своєю функцією без жодної паузи.

Перш ніж запустити це, якого результату ви очікуєте, якщо спробуєте створити worktree для гілки, яка вже розгорнута в іншому worktree?

Подумайте про обмеження робочого каталогу.

Git застосовує суворе правило: одна гілка може бути розгорнута лише в одному worktree одночасно. Якщо ви спробуєте виконати git worktree add ../another-dir feature-auth, коли feature-auth уже розгорнута у вашому основному каталозі, Git жорстко відхилить команду. Це запобігає “шизофренічним” станам, коли два різні каталоги намагаються оновити один і той самий покажчик гілки одночасно.

Життєвий цикл Worktree: перегляд та очищення

Розділ «Життєвий цикл Worktree: перегляд та очищення»

Щоб побачити всі активні worktrees, підключені до вашого репозиторію, використовуйте команду list.

Terminal window
git worktree list
/projects/k8s-operator 8f3a9b2 [feature-auth]
/projects/k8s-operator-hotfix 2c9b4e1 [hotfix-cve]

Коли ви закінчили роботу з worktree (наприклад, хотфікс злитий і видалений у віддаленому репозиторії), вам потрібно його прибрати. Правильний спосіб видалення worktree — це команда remove.

Terminal window
# Це видаляє каталог і очищує посилання в основній папці .git
git worktree remove ../k8s-operator-hotfix

Git відмовиться видаляти worktree, якщо в ньому є незакомічені зміни, захищаючи вас від випадкової втрати даних. Ви можете примусово видалити його за допомогою -f, але цього варто уникати.

Сценарій випадкового видалення

Що станеться, якщо ви оминете Git і просто використаєте rm -rf ../k8s-operator-hotfix?

Ваша файлова система видалить каталог, але основний репозиторій Git усе ще вважатиме, що worktree існує. Він зберігатиме метадані в .git/worktrees/hotfix і вперто відмовлятиметься дозволити вам розгорнути гілку hotfix-cve будь-де інде, стверджуючи, що вона вже розгорнута.

Щоб виправити цей стан “сироти”, ви повинні наказати Git очистити внутрішні записи про worktrees, яких більше не існує на диску.

Terminal window
git worktree prune

Запуск prune змушує Git перевірити існування кожного зареєстрованого шляху worktree. Якщо шлях відсутній, Git видаляє внутрішні метадані відстеження, звільняючи гілку для повторного розгортання.

Матриця рішень: Stash проти Worktree проти Clone

Розділ «Матриця рішень: Stash проти Worktree проти Clone»

Розуміння того, коли який інструмент використовувати, є ознакою досвідченого інженера. Використовуйте цю матрицю як орієнтир для ваших робочих процесів.

Зупиніться та поміркуйте: Колега просить вас переглянути його PR. Він змінив 2 файли. У вас немає незакоміченої роботи. Яку стратегію ви оберете і чому?

Якщо у вас немає незакоміченої роботи, вам насправді не потрібні ні stash, ні worktrees для збереження стану! Ви можете просто переключитися на його гілку у поточному каталозі. Проте, якщо ви хочете залишити свою поточну гілку розгорнутою, щоб миттєво повернутися до неї, не шукаючи в історії гілок, створення швидкого worktree все одно буде чудовим вибором для ізоляції контексту рев’ю.

СценарійРекомендована стратегіяТехнічне обґрунтування
Стягування останніх змін перед пушем локальних комітів.git stashПереривання триває секунди. Контекст залишається чітким у пам’яті. Ризик значних конфліктів низький, а stash — це найшвидша локальна операція.
Терміновий хотфікс продакшену посеред розробки фічі.git worktreeПотребує абсолютно чистого стану. Хотфікс може зайняти години або дні, протягом яких ви втратите ментальний контекст стешу. Вам потрібна абсолютна гарантія, що код фічі не потрапить у хотфікс.
Перегляд величезного Pull Request колеги під час роботи над власним кодом.git worktreeРев’ю PR часто вимагає запуску коду, зміни конфігурації та виконання тестів. Стешинг вашої роботи перериває потік думок і створює ризик забруднення тестової бази даних, якщо ви використовуєте спільні змінні середовища. Окремий worktree забезпечує ізоляцію для збірки та тестування PR.
Тестування зовсім іншої версії Kubernetes локально на кодовій базі.git clone (іноді)Хоча worktree ізолює файли, такі речі, як файли .env або глобальні конфігурації IDE, все одно можуть “просочуватися” між каталогами, якщо вони використовують відносні шляхи. Якщо вам потрібна абсолютна, герметична ізоляція (наприклад, повністю різні Docker-середовища, прив’язані до різних каталогів), повний окремий клон може бути виправданим, хоча це трапляється рідко.
Спроба спекулятивного, експериментального рефакторингу, який ви можете викинути.git branch (у поточному дереві)Якщо ви просто хочете щось швидко спробувати, закомітьте поточний стан, створіть нову гілку і починайте кодити. Гілки Git дешеві. Стешинг непотрібний, якщо ви готові робити WIP-коміти (work in progress).

Історія з фронту Kubernetes: Катастрофа оператора

Розділ «Історія з фронту Kubernetes: Катастрофа оператора»

Розглянемо команду, що розробляє складний Kubernetes Operator на Go. Оператор керує кластерами баз даних високої доступності.

Інженер Аліса працює над великою функцією: впровадженням автоматичного резервного копіювання в AWS S3. У її робочому каталозі 15 модифікованих Go-файлів, нові визначення CRD YAML та локальний кластер Minikube, запущений зі специфічною конфігурацією для тестування логіки бекапів.

Виникає критична проблема: Оператор падає у продакшен-середовищі через стан гонитви (race condition) у логіці обрання лідера (leader election). Аліса — єдина, хто розуміє код leader election.

Шлях через Stash (Шлях невдачі): Аліса виконує git stash. Вона перемикається на main. Змінює код leader election, пише тест і пушить виправлення. Потім повертається до своєї гілки бекапів і виконує git stash pop. На жаль, виправлення leader election зачепило ту саму основну послідовність ініціалізації контролера, яку зачіпає її функція бекапів. Вона отримує складні конфлікти в коді Go. Крім того, її локальний Minikube залишився з конфігурацією функції бекапів, яка тепер конфліктує з тестами leader election, які вона намагалася запустити локально. Вона витрачає години на виправлення конфліктів та скидання стану локального кластера.

Шлях через Worktree (Шлях успіху): Аліса залишає свій термінал саме таким, як він є. Вона відкриває новий термінал і виконує git worktree add ../operator-hotfix main. Вона переходить у новий каталог. Виправляє баг leader election, запускає тести (можливо, розгортаючи свіжий ізольований кластер KinD саме для цього каталогу), комітить і пушить. Потім вона видаляє цей worktree. Повертається до свого початкового терміналу. Її 15 модифікованих файлів, незакомічені CRD та специфічна конфігурація Minikube залишилися абсолютно недоторканими, чекаючи саме там, де вона їх залишила. Жодної втрати контексту, жодних конфліктів злиття, жодного змарнованого часу.

  1. Git worktrees були натхненні стороннім скриптом під назвою git-new-workdir, який роками існував у каталозі contrib/ вихідного коду Git, перш ніж бути формалізованим в основному бінарному файлі у 2015 році.
  2. Коли ви використовуєте git stash, Git насправді створює внутрішні коміти. Він створює один коміт для стану вашої області підготовки (index) і ще один коміт для вашого робочого дерева, пов’язуючи їх в унікальну структуру, яка не є частиною жодної історії гілок.
  3. Ви можете налаштувати Git так, щоб він завжди включав невідстежувані файли під час стешингу, встановивши глобальну конфігурацію git config --global stash.showIncludeUntracked true, хоча явні прапорці зазвичай безпечніші, щоб запобігти випадковому застешуванню великих артефактів збірки.
  4. Git заважає вам видалити гілку, якщо вона розгорнута в будь-якому worktree, забезпечуючи важливий рівень безпеки від видалення роботи, яку ви зараз переглядаєте в іншому вікні терміналу.
ПомилкаЧому це трапляєтьсяЯк це виправити
Втрата нових файлів у стешіЗапуск git stash без прапорця -u залишає щойно створені (невідстежувані) файли в робочому каталозі, що призводить до плутанини при перемиканні гілок.Завжди використовуйте git stash push -u -m "msg", коли у вас є створені нові файли.
Амнезія стеку стешівВикористання простого git stash створює загальні записи на кшталт WIP on main. Через три дні ви поняття не матимете, що містить stash@{2}.Ніколи не робіть стеш без повідомлення. Використовуйте git stash push -m "Опис контексту".
Покинуті каталоги worktreeВидалення папки worktree за допомогою rm -rf замість git worktree remove. Git усе ще вважає, що worktree існує, і блокує гілку.Запустіть git worktree prune, щоб змусити Git очистити посилання на відсутні каталоги.
Поппінг на неправильну гілкуВикористання git stash pop, усвідомлення, що ви не на тій гілці, і необхідність розплутувати складні конфлікти, бо стеш був миттєво видалений зі стеку.Використовуйте за замовчуванням git stash apply. Використовуйте git drop лише тоді, коли переконалися, що застосований стан є правильним і стабільним.
Спроба переключитися на заблоковану гілкуСпроба розгорнути гілку, яка вже активна в іншому worktree. Git суворо дотримується ексклюзивності гілок між worktrees.Або переключіть інший worktree на іншу гілку, або закомітьте/застеште зміни і повністю видаліть цей worktree.
Ігнорування “просочування” середовищаПрипущення, що worktrees ізолюють все. Хоча шляхи до файлів ізольовані, глобальні змінні середовища, спільні локальні бази даних або фіксовані порти (наприклад, веб-сервер, що завжди займає 8080) все одно будуть конфліктувати між worktrees.Використовуйте ізольовані середовища для кожного каталогу, наприклад динамічний розподіл портів або окремі мережі контейнерів для локального тестування.

Контрольні запитання

Розділ «Контрольні запитання»
Запитання 1: Ви глибоко занурилися у зміну складного Helm-чарту для нового мікросервісу. PagerDuty сповіщає вас про інцидент Sev-1, що потребує зміни одного рядка конфігурації в гілці `production`. Яка команда є найбезпечнішим та найефективнішим способом ізолювати вашу поточну роботу, поки ви займаєтеся надзвичайною ситуацією?

Відповідь: git worktree add ../incident-response production. Worktree забезпечує ідеальну ізоляцію без накладних витрат на повний клон. Це гарантує, що ваші напівнаписані шаблони Helm не потраплять у хотфікс продакшену, і вам не доведеться мати справу з конфліктами стешу, коли ви повернетеся до своєї фічі. Оскільки робочий каталог повністю відокремлений, ви можете вільно змінювати файли та запускати тести, не впливаючи на ваше основне середовище розробки. Після завершення хотфіксу ви просто видаляєте worktree і відновлюєте попереднє завдання саме там, де зупинилися.

Запитання 2: Ви виконали `git stash` перед перемиканням гілок, щоб допомогти колезі відлагодити проблему. Через два дні ви повертаєтеся до своєї гілки, запускаєте `git stash pop` і отримуєте величезні конфлікти злиття, оскільки за цей час колега влив (merged) великий рефакторинг. Яка команда могла б врятувати вас від ручного вирішення цих негайних конфліктів у робочому каталозі?

Відповідь: git stash branch new-recovery-branch. Якщо ви підозрюєте конфлікти або якщо apply завершується катастрофічно, створення гілки безпосередньо зі стешу ізолює зміни у чисту історію комітів на основі точного моменту часу, коли ви створили стеш. Це дозволяє уникнути негайного конфлікту з поточним станом гілки. Потім ви можете систематично перебазовувати або зливати цю нову гілку, вирішуючи конфлікти по одному коміту за допомогою стандартних інструментів злиття Git, замість того щоб розбиратися з масивним конфліктом у робочому каталозі.

Запитання 3: Ви використали `rm -rf ../testing-env`, щоб видалити каталог worktree, який використовували для тестування деплою Kubernetes. Тепер, коли ви намагаєтеся розгорнути гілку `test-deployment` у своєму основному каталозі, Git скаржиться, що гілка вже розгорнута. Як це виправити?

Відповідь: Запустіть git worktree prune в основному репозиторії. Оминаючи Git та видаляючи каталог через файлову систему, ви залишаєте внутрішні метадані у .git/worktrees/ покинутими. Git усе ще вірить, що worktree існує, оскільки посилальні файли всередині основного каталогу .git не були видалені. Команда prune наказує Git перевірити існування всіх worktrees на диску і безпечно видалити внутрішні записи для тих, які відсутні, що потім розблоковує гілку для використання в іншому місці.

Запитання 4: Ви пишете новий скрипт на Python для автоматизації масштабування кластера. Ви ще не виконали `git add` для нового скрипта. Ви отримуєте термінове прохання переглянути PR, тому запускаєте `git stash`, переходите на гілку PR і раптом бачите свій новий Python-скрипт у каталозі гілки PR. Чому це сталося?

Відповідь: git stash за замовчуванням ігнорує невідстежувані файли. Оскільки новий Python-скрипт ніколи не додавався до індексу, Git не вважав його частиною “брудного” стану, який потрібно застешити. Коли ви змінили гілку, файл просто залишився в робочому каталозі, оскільки він не конфліктував із жодним із відстежуваних файлів у цільовій гілці. Щоб включити його в стеш, ви повинні явно наказати Git захопити невідстежувані файли за допомогою прапорця -u або --include-untracked: git stash push -u -m "saving new script".

Запитання 5: Вам потрібно протестувати скрипт міграції бази даних локально, але ви не хочете порушувати роботу свого поточного середовища. Ви вагаєтеся між виконанням `git clone` у новий каталог або використанням `git worktree add`. Яка фундаментальна архітектурна різниця на диску між цими двома підходами?

Відповідь: Другий git clone дублює всю базу об’єктів (історію, коміти, блоги), створюючи повністю незалежний каталог .git, що споживає значний дисковий простір і потребує власних мережевих операцій. git worktree add створює новий робочий каталог, але використовує крихітний файл .git для вказівки на базу об’єктів оригінального репозиторію. Це означає, що він ділиться всією історією комітів та мережевим станом з вашим основним репозиторієм, зберігаючи дисковий простір, що робить його набагато ефективнішим вибором для локального тестування.

Запитання 6: Ви повертаєтеся до роботи після довгих вихідних і бачите три стеші у своєму стеку. Ви думаєте, що `stash@{1}` містить зміни конфігурації бази даних, які вам потрібні, але хочете бути абсолютно впевнені перед застосуванням їх до вашого поточного робочого каталогу. Яку команду вам слід використати для перевірки вмісту?

Відповідь: git stash show -p stash@{1}. Ця команда працює як git diff, відображаючи формат патча змін, збережених у цьому конкретному стеші. Переглядаючи “сирий” вивід diff, ви можете безпечно перевірити, які саме файли були змінені і які рядки були додані чи видалені, не змінюючи свій поточний робочий каталог. Це запобігає випадковому застосуванню не того стешу та дозволяє уникнути потенційних конфліктів злиття, якщо стеш містить неочікувані зміни.

Практична вправа: Хотфікс під час польоту

Розділ «Практична вправа: Хотфікс під час польоту»

У цій вправі ви змоделюєте реальне переривання роботи з маніфестами Kubernetes, демонструючи, чому worktrees кращі за стешинг для складних перемикань контексту.

Налаштування сценарію

Розділ «Налаштування сценарію»
  1. Ініціалізуйте новий репозиторій Git, який буде вашим основним робочим простором.
    Terminal window
    mkdir k8s-fleet-manager && cd k8s-fleet-manager
    git init
  2. Створіть стабільний базовий стан, що представляє продакшен.
    Terminal window
    cat << 'EOF' > deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: fleet-api
    spec:
    replicas: 2
    template:
    spec:
    containers:
    - name: api
    image: fleet-api:v1.0.0
    EOF
    git add deployment.yaml
    git commit -m "Initial production release v1.0.0"
  3. Створіть і розгорніть нову гілку для великої фічі: додавання лімітів ресурсів та liveness-проб.
    Terminal window
    git checkout -b feature/reliability-upgrade
  4. Почніть свою складну, незавершену роботу. Суттєво змініть деплоймент.
    Terminal window
    cat << 'EOF' > deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: fleet-api
    spec:
    replicas: 2
    template:
    spec:
    containers:
    - name: api
    image: fleet-api:v1.1.0-rc1
    resources:
    requests:
    memory: "64Mi"
    cpu: "250m"
    limits:
    memory: "128Mi"
    cpu: "500m"
    livenessProbe:
    httpGet:
    path: /healthz
    port: 8080
    initialDelaySeconds: 3
    periodSeconds: 3
    EOF
    Не комітьте ці зміни. Це ваш “брудний” робочий стан.

Переривання (Завдання)

Розділ «Переривання (Завдання)»

Надійшло повідомлення про критичний баг у fleet-api:v1.0.0 у продакшені. Вам потрібно негайно оновити версію образу на v1.0.1 у гілці main.

Ваші обмеження: Ви не можете втратити складну конфігурацію ресурсів/проб і не можете ризикувати конфліктами злиття під час застосування хотфіксу.

  • Створіть новий worktree під назвою fleet-manager-hotfix у батьківському каталозі, створивши нову гілку hotfix/image-patch на основі main.
  • Перейдіть до каталогу нового worktree.
  • Переконайтеся, що deployment.yaml у цьому новому каталозі є чистою, оригінальною версією з продакшену (v1.0.0), без жодних ваших оновлень надійності.
  • Оновіть тег образу в каталозі хотфіксу на fleet-api:v1.0.1.
  • Закомітьте хотфікс.
  • Безпечно видаліть worktree хотфіксу за допомогою команд Git (не використовуйте rm -rf).
  • Поверніться до свого початкового каталогу і переконайтеся, що ваші оновлення надійності залишилися точно в такому стані, як ви їх залишили — незакомічені та готові до продовження.
Рішення
  1. Створіть worktree: Залиште свій поточний каталог саме таким, як він є (брудним). Створіть нове середовище.
    Terminal window
    git worktree add -b hotfix/image-patch ../fleet-manager-hotfix main
  2. Перейдіть та перевірте:
    Terminal window
    cd ../fleet-manager-hotfix
    cat deployment.yaml
    # Зверніть увагу, що це оригінальний файл v1.0.0. Ваша складна робота надійно ізольована в іншому місці.
  3. Застосуйте та закомітьте хотфікс:
    Terminal window
    # (Відредагуйте deployment.yaml, щоб змінити образ на v1.0.1, наприклад, за допомогою sed)
    sed -i '' 's/v1.0.0/v1.0.1/g' deployment.yaml # macOS
    # sed -i 's/v1.0.0/v1.0.1/g' deployment.yaml # Linux
    git add deployment.yaml
    git commit -m "Hotfix: Update API image to v1.0.1 to resolve memory leak"
  4. Очистіть worktree:
    Terminal window
    # Вийдіть із каталогу перед його видаленням
    cd ../k8s-fleet-manager
    # Правильно видаліть worktree через Git
    git worktree remove ../fleet-manager-hotfix
  5. Перевірте початковий стан:
    Terminal window
    cat deployment.yaml
    # Ваші складні ліміти ресурсів та liveness-проби все ще тут, незакомічені та недоторкані.
    git status
    # Показує deployment.yaml як модифікований. Ви успішно пережили переривання.