Назад до блога

git stash: один файл, не чіпаючи решти

21 вересня 2026 р.

Приходить code review, а три файли недоправлені — і ворушитися може лише один. Сховати все в stash і переписувати решту двох — ритуал, за яким ніхто не скучає.

TL;DR: git stash push -m "чому" -- <шлях> ховає рівно вказані шляхи і лишає решту вашого брудного дерева в спокої. Зміни повертаються через git stash pop (або окремий файл із будь-якого stash витягується через git restore --source stash@{0} -- <шлях>). Форма з pathspec прийшла в git 2.13, випущений у травні 2017 — будь-який інструментарій останніх восьми років її має.

git stash push -m "app.conf prod tweak" -- app.conf
git stash list
# stash@{0}: On main: app.conf prod tweak
git stash pop

Ховай файл, а не дерево.

Як сховати в stash лише один файл у git?

Голий git stash вимітає все робоче дерево — кожна відстежена зміна йде в stash, усе повертається до HEAD. Це неправильна форма, коли брудне дерево змішане: один файл готовий до передачі, решта чесно недороблена. Відповідь — дієслово push з pathspec, за документацією git-stash:

# до: три брудні файли
$ git status --short
 M app.conf
 M notes.md
 M main.py

# сховати лише app.conf
$ git stash push -m "app.conf prod tweak" -- app.conf
Saved working directory and index state On main: app.conf prod tweak

$ git status --short
 M notes.md
 M main.py

app.conf повернувся до закоміченого стану і осів у stash@{0}; notes.md і main.py не рушили. Повідомлення -m необов’язкове, але варте своїх трьох секунд, щойно git stash list покаже більше одного запису — stash під ім’ям «WIP» старіють погано.

Два деталі, що мають значення:

  • Pathspec іде після --. Усе після подвійного тире — це шляхи, а не прапорці. Та сама конвенція, що й git checkout -- <шлях>, і вона не декоративна: у старіших версіях git stash push -- main.py і git stash push main.py відрізнялися — голий шлях могли зчитати неправильно.
  • Невідстежувані файли вимагають -u. У новонародженого файлу немає відстеженої історії, яку можна сховати, тож звичайний push його пропускає. git stash push -u -- newfile.py його включає; -a іде далі й вимітає ще й ігноровані.

Як сховати частину одного файлу?

Коли сам файл напівготовий — три гарні hunks, один сороміцький — інтерактивний потік його розрізає:

git stash -p            # або: git stash push -p

Git проходить кожен hunk і питає Stash this hunk [y,n,q,a,d,j,g,/,e,p,?]?. Відповідайте y для hunk-ів, що йдуть у stash, n для тих, що лишаються. Результат — stash лише зі схваленим, решта файлу лишається брудною в дереві. Та сама hunk-за-hunk-машина крутить і git add -p, тож рефлекс переноситься напряму.

git stash push -- <шлях>git stash -p
Зерноцілі файлиокремі hunks
Темподна команда, скриптуєтьсяінтерактивно, hunk за hunk
Повторюваність у CIтак (шляхи як аргументи)ні — потрібна людина біля промпта
Найкраще для«цей файл, не решта»«ця зміна, не та»
Зgit 2.13 (травень 2017)доступно давно

Практичне правило з моделі самої документації: pathspec, коли межа — це файл, -p, коли межа всередині нього.

Як повернути stash-нутий файл?

git stash pop відновлює stash@{0} і видаляє запис. Це нормальний шлях — але pop працює за принципом «все або нічого» на stash, і конфлікт перериває pop, лишаючи запис. Дві тонші опції:

# 1. застосувати без видалення (безпечно повторювано)
git stash apply stash@{0}

# 2. витягти ОДИН файл зі stash, запис лишається
git restore --source stash@{0} -- app.conf
# старіший запис тієї самої операції (до 2.23):
git checkout stash@{0} -- app.conf

Форма restore/checkout відповідає на випадок «сховав три зміни разом, а потрібна тепер одна» — копіює stash-нутий вміст цього шляху в робоче дерево і лишає stash@{0} на ногах. Зверніть увагу: вона перезаписує копію в робочому дереві; якщо поточні правки на цьому шляху цінні, спершу diff:

git diff stash@{0} -- app.conf

Stash-и зберігаються як справжні коміти на стеку, схожому на reflog — тому stash@{0} приймає будь-який commit-ish синтаксис, а випадково скинутий stash можна витягти з reflog, доки його не з’їсть збирач сміття.

Коли stash — неправильний інструмент?

Stash — це чорновик, не гілка: немає імені в git branch, немає review, немає показаного за замовчуванням diff, а записи мовчки громздяться до забуття. Якщо робота в процесі має пережити зміни контексту між машинами чи днями, комітьте її в гілку — прикріплена історія краща за безіменний стек. Коли ті припарковані коміти матимуть сісти в іншому місці, перевезе їх git cherry-pick. А якщо мета — скасувати, а не паркувати, діє дерево рішень із скасувати останній коміт.

Чесна книга поламок — усе з задокументованої поведінки:

СимптомПричинаФікс
Файлу немає після stashневідстежувані шляхи пропускаютьсяgit stash push -u -- <шлях>
error: Your local changes ... would be overwritten на popшлях змінився від часів stashзакомітьте або сховайте новий стан, потім pop
Повернуті зміни зниклиpop наткнувся на конфлікт і перервавсярозʼяжіть, потім git stash apply
«Котрий це був stash?»безіменна купа stash-івповідомлення -m, щоразу

Травнева примітка 2017 року, що додала pathspec до git stash push, має вісім років, і більшість мʼязової памʼяті git stash старіша за неї. Варто перевчитись: вимітання цілого дерева — сьогодні окремий випадок, не типовий режим.

FAQ

Як сховати в stash лише один файл у git?

git stash push -m "нотатка" -- шлях/до/файлу — форма з pathspec ховає лише вказані шляхи і не чіпає решту змінених файлів. Потрібен git 2.13 або новіший (травень 2017).

Як витягти окремий файл зі stash?

git restore --source stash@{0} -- шлях/до/файлу (або старіший запис git checkout stash@{0} -- шлях/до/файлу). Копіює stash-нуту версію у ваше робоче дерево, не видаляючи запис stash.

Чому git stash проігнорував мій новий файл?

Невідстежувані (untracked) файли не входять до звичайного stash. Додайте -u: git stash push -u -- шлях/до/файлу. Ігноровані файли вимагають -a.

— mrsaynothing

— mrsaynothing

Польові нотатки про ШІ, Linux і self-hosting.

Наступний гайд — на email

Один лист на пост. Полагодили — і далі.

self-hosted · без третіх сторін · відписка в один клік

що це таке?

«Польові нотатки» #1 із сайту агентів: машина випускає. Я затверджую.

Читається добре? Таке я будую за гроші. найміть мене