Модуль 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 часто відмовляється перемикати гілки, якщо ці зміни конфліктують із цільовою гілкою. Навіть якщо він дозволяє перемикання, перенесення незакомічених змін між гілками є рецептом для випадкових комітів та пошкодження стану.
Історично розробники використовували два основні обхідні шляхи для подолання цього обмеження при перериваннях:
- Стратегія декількох клонів: Кожного разу, коли виникає нове завдання або хотфікс, розробник виконує
git cloneу абсолютно новий каталог. - Стратегія “Застеш і молися”: Розробник використовує
git stash, щоб сховати незакомічені зміни, перемикає гілки, виконує роботу, повертається назад і намагається зробитиpopзмін.
Обидва підходи є фундаментально недосконалими для професійної високоефективної інженерії.
Справжня ціна декількох клонів
Розділ «Справжня ціна декількох клонів»Хоча клонування репозиторію кілька разів забезпечує ідеальну ізоляцію, це неймовірно неефективно. Розглянемо великий монорепозиторій, що містить мікросервіси, маніфести Kubernetes та код Terraform. Один клон може споживати кілька гігабайтів дискового простору, а його завантаження може тривати хвилини.
Якщо ви створюєте новий клон для кожного хотфіксу чи рев’ю коду, ви щоразу дублюєте всю історію Git (базу об’єктів у каталозі .git).
Крім того, ці клони повністю від’єднані один від одного локально. Якщо ви завантажите останні зміни з віддаленого репозиторію в Клоні А, Клон Б залишиться про них абсолютно не поінформованим. Ви повинні виконувати мережеві операції в кожному окремому клоні, щоб підтримувати їх синхронізованими. Якщо ви хочете протестувати гілку з Клону А проти конфігурації в Клоні Б, вам доведеться робити пуш у віддалений репозиторій і пулл, або возитися з визначенням локальних remote-посилань. Це кошмар обслуговування, замаскований під рішення.
Обмеження git stash
Розділ «Обмеження git stash»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, щоб надати контекст.
# Погана практикаgit stash
# Хороша практикаgit stash push -m "Mid-refactor of deployment.yaml resource limits"Якщо ви працюєте над новою функцією та створили нові маніфести Kubernetes, які ще не відстежуються Git, ви повинні явно наказати команді стешу включити їх, використовуючи прапорець -u (або --include-untracked).
# Стешить відстежувані зміни ТА невідстежувані нові файлиgit stash push -u -m "Added new redis-deployment.yaml and modified configmap"Якщо ви хочете бути неймовірно прискіпливим, ви можете використовувати прапорець -a (або --all), який стешить відстежувані файли, невідстежувані файли і навіть файли, ігноровані у .gitignore. Це рідко буває необхідним, але корисно, якщо вам потрібно повністю очистити каталог для тестування.
Навігація та перегляд стеку стешів
Розділ «Навігація та перегляд стеку стешів»Кожного разу, коли ви створюєте стеш, він додається у стек. Ви можете переглянути цей стек за допомогою git stash list.
git stash listВивід виглядатиме приблизно так:
stash@{0}: On feature-auth: Added new redis-deployment.yaml and modified configmapstash@{1}: On main: Mid-refactor of deployment.yaml resource limitsНайновіший стеш — це завжди stash@{0}. Коли ви додаєте нові, старіші опускаються нижче по стеку (їхній індекс збільшується).
Перед застосуванням стешу ви часто хочете побачити, які саме зміни він містить. Ви можете використовувати підкоманду show із прапорцем -p (patch) для перегляду точної диференціації (diff) застешених змін.
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 бере зміни із зазначеного стешу і застосовує їх до вашого поточного робочого каталогу, але залишає стеш недоторканим у стеку. Це найбезпечніша операція. Якщо застосування призведе до величезних конфліктів і ви перервете процес, ваш застешений стан усе ще буде надійно збережений.
# Застосовує найновіший стешgit stash apply
# Застосовує конкретний стеш зі стекуgit stash apply stash@{1}git stash pop застосовує зміни і, якщо застосування успішне (немає конфліктів), негайно видаляє стеш зі стеку. Хоча це зручно, це може бути небезпечно, якщо ви трохи запізно зрозумієте, що застосували стеш не до тієї гілки.
Як загальне правило для критичного коду інфраструктури: завжди використовуйте git stash apply, перевіряйте стан, а потім вручну видаляйте стеш за допомогою git stash drop, коли будете впевнені, що він вам більше не потрібен.
# Видалити конкретний стешgit stash drop stash@{1}
# Очистити весь стек стешів (використовуйте з обережністю)git stash clearРятувальний люк: створення гілки зі стешу
Розділ «Рятувальний люк: створення гілки зі стешу»Що станеться, якщо ви застешите складні зміни, попрацюєте тиждень над іншими речами, а потім спробуєте застосувати стеш назад до своєї початкової гілки, але виявите, що гілка настільки еволюціонувала, що конфлікти стали непереборними?
Git надає блискучий рятувальний люк: git stash branch. Ця команда створює абсолютно нову гілку, починаючи з того самого коміту, на якому ви були, коли створювали стеш, застосовує стеш до цієї нової гілки, а потім видаляє його.
git stash branch recovered-auth-work stash@{0}Це ізолює ваші застешені зміни в безпечному середовищі. Потім ви можете спокійно закомітити їх у нову гілку і вирішити, як їх злити або перебазувати (rebase) у головну гілку у власному темпі, не стикаючись із негайними конфліктами в робочому каталозі.
Міні-вправа: стешинг невідстежуваних файлів
Розділ «Міні-вправа: стешинг невідстежуваних файлів»Перш ніж перейти до worktrees, давайте потренуємо повний робочий процес стешу, зокрема обробку невідстежуваних файлів та перевірку стеку.
- Ініціалізуйте новий репозиторій Git, який буде вашим основним робочим простором:
Terminal window mkdir stash-practice && cd stash-practicegit init - Створіть початковий коміт, щоб встановити чисте робоче дерево:
Terminal window echo "v1" > config.txtgit add config.txtgit commit -m "Initial commit" - Змініть відстежуваний файл і створіть новий, невідстежуваний файл:
Terminal window echo "v2" > config.txtecho "secret-key" > .env - Застеште всі зміни, включаючи невідстежуваний файл:
Terminal window git stash push -u -m "WIP on new config and secrets" - Перегляньте стек стешів та вміст останнього стешу:
Terminal window git stash listgit stash show -p stash@{0} - Відновіть застешені зміни, не видаляючи їх зі стеку:
Зверніть увагу, що ваші модифікації у
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:
- Вони споживають дуже мало додаткового дискового простору (лише розмір розгорнутих файлів, а не всієї історії).
- Вони миттєво діляться мережевим станом. Якщо ви виконаєте
git fetchв одному worktree, оновлені віддалені гілки негайно стануть доступними у всіх інших worktrees. - Ви можете легко переносити коміти (cherry-pick) або зливати їх між ними без необхідності пушити у віддалений репозиторій.
Анатомія Worktree
Розділ «Анатомія Worktree»Давайте візуалізуємо, як 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 для хотфіксу.
# Використання: git worktree add <path> <branch>
# Створити новий каталог поруч із поточним,# створити нову гілку 'hotfix-cve'# і розгорнути її, починаючи від 'main'git worktree add -b hotfix-cve ../k8s-operator-hotfix mainGit виведе:
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.
git worktree list/projects/k8s-operator 8f3a9b2 [feature-auth]/projects/k8s-operator-hotfix 2c9b4e1 [hotfix-cve]Коли ви закінчили роботу з worktree (наприклад, хотфікс злитий і видалений у віддаленому репозиторії), вам потрібно його прибрати. Правильний спосіб видалення worktree — це команда remove.
# Це видаляє каталог і очищує посилання в основній папці .gitgit worktree remove ../k8s-operator-hotfixGit відмовиться видаляти worktree, якщо в ньому є незакомічені зміни, захищаючи вас від випадкової втрати даних. Ви можете примусово видалити його за допомогою -f, але цього варто уникати.
Сценарій випадкового видалення
Що станеться, якщо ви оминете Git і просто використаєте rm -rf ../k8s-operator-hotfix?
Ваша файлова система видалить каталог, але основний репозиторій Git усе ще вважатиме, що worktree існує. Він зберігатиме метадані в .git/worktrees/hotfix і вперто відмовлятиметься дозволити вам розгорнути гілку hotfix-cve будь-де інде, стверджуючи, що вона вже розгорнута.
Щоб виправити цей стан “сироти”, ви повинні наказати Git очистити внутрішні записи про worktrees, яких більше не існує на диску.
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 залишилися абсолютно недоторканими, чекаючи саме там, де вона їх залишила. Жодної втрати контексту, жодних конфліктів злиття, жодного змарнованого часу.
Чи знали ви?
Розділ «Чи знали ви?»- Git worktrees були натхненні стороннім скриптом під назвою
git-new-workdir, який роками існував у каталозіcontrib/вихідного коду Git, перш ніж бути формалізованим в основному бінарному файлі у 2015 році. - Коли ви використовуєте
git stash, Git насправді створює внутрішні коміти. Він створює один коміт для стану вашої області підготовки (index) і ще один коміт для вашого робочого дерева, пов’язуючи їх в унікальну структуру, яка не є частиною жодної історії гілок. - Ви можете налаштувати Git так, щоб він завжди включав невідстежувані файли під час стешингу, встановивши глобальну конфігурацію
git config --global stash.showIncludeUntracked true, хоча явні прапорці зазвичай безпечніші, щоб запобігти випадковому застешуванню великих артефактів збірки. - 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 кращі за стешинг для складних перемикань контексту.
Налаштування сценарію
Розділ «Налаштування сценарію»- Ініціалізуйте новий репозиторій Git, який буде вашим основним робочим простором.
Terminal window mkdir k8s-fleet-manager && cd k8s-fleet-managergit init - Створіть стабільний базовий стан, що представляє продакшен.
Terminal window cat << 'EOF' > deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: fleet-apispec:replicas: 2template:spec:containers:- name: apiimage: fleet-api:v1.0.0EOFgit add deployment.yamlgit commit -m "Initial production release v1.0.0" - Створіть і розгорніть нову гілку для великої фічі: додавання лімітів ресурсів та liveness-проб.
Terminal window git checkout -b feature/reliability-upgrade - Почніть свою складну, незавершену роботу. Суттєво змініть деплоймент.
Не комітьте ці зміни. Це ваш “брудний” робочий стан.
Terminal window cat << 'EOF' > deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: fleet-apispec:replicas: 2template:spec:containers:- name: apiimage: fleet-api:v1.1.0-rc1resources:requests:memory: "64Mi"cpu: "250m"limits:memory: "128Mi"cpu: "500m"livenessProbe:httpGet:path: /healthzport: 8080initialDelaySeconds: 3periodSeconds: 3EOF
Переривання (Завдання)
Розділ «Переривання (Завдання)»Надійшло повідомлення про критичний баг у 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). - Поверніться до свого початкового каталогу і переконайтеся, що ваші оновлення надійності залишилися точно в такому стані, як ви їх залишили — незакомічені та готові до продовження.
Рішення
- Створіть worktree: Залиште свій поточний каталог саме таким, як він є (брудним). Створіть нове середовище.
Terminal window git worktree add -b hotfix/image-patch ../fleet-manager-hotfix main - Перейдіть та перевірте:
Terminal window cd ../fleet-manager-hotfixcat deployment.yaml# Зверніть увагу, що це оригінальний файл v1.0.0. Ваша складна робота надійно ізольована в іншому місці. - Застосуйте та закомітьте хотфікс:
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 # Linuxgit add deployment.yamlgit commit -m "Hotfix: Update API image to v1.0.1 to resolve memory leak" - Очистіть worktree:
Terminal window # Вийдіть із каталогу перед його видаленнямcd ../k8s-fleet-manager# Правильно видаліть worktree через Gitgit worktree remove ../fleet-manager-hotfix - Перевірте початковий стан:
Terminal window cat deployment.yaml# Ваші складні ліміти ресурсів та liveness-проби все ще тут, незакомічені та недоторкані.git status# Показує deployment.yaml як модифікований. Ви успішно пережили переривання.