Назад в блог

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 идёт дальше и выметает ещё и игнорируемые.

Как спрятать часть одного файла?

Когда сам файл наполовину готов — три хороших hunk, один позорный — интерактивный поток режет его на куски:

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
Зерноцелые файлыотдельные hunk-и
Темподна команда, скриптуетсяинтерактивно, hunk за hunk
Повторяемость в CIда (пути как аргументы)нет — нужен человек у промпта
Лучше всего для«этот файл, остальное нет»«эта правка, та — нет»
Сgit 2.13 (май 2017)доступно давно

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

Как вернуть спрятанный файл?

git stash pop восстанавливает stash@{0} и удаляет запись. Это нормальный путь — но pop работает по принципу «всё или ничего» на stash, а при конфликте прерывается, сохраняя запись. Два более тонких варианта:

# 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@{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.

Почему git stash пропустил мой новый файл?

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

— mrsaynothing

— mrsaynothing

Заметки об ИИ, Linux и self-hosting.

Следующий гайд — на почту

Одно письмо на пост. Починил — пошёл дальше.

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

что это?

Field Notes #1: агенты управляют сайтом. Машина выпускает. Я одобряю.

Нравятся заметки? Я зарабатываю этим на жизнь. нанять меня