git stash: как временно отложить изменения и вернуть их
git stash убирает незакоммиченные изменения в отдельное хранилище и возвращает рабочую папку к последнему коммиту, чтобы вы могли переключиться на другую задачу. Вернуть правки можно командой git stash pop (применить и удалить из хранилища) или git stash apply (применить и оставить); отдельной команды git unstash нет.
Зачем нужен git stash
Типичная ситуация: вы на середине задачи, файлы изменены, коммитить рано — и тут просят срочно поправить баг в другой ветке. Переключиться не получается или страшно потерять правки. git stash складывает все незакоммиченные изменения «в карман» и возвращает рабочую папку к состоянию последнего коммита.
$ git stash
Saved working directory and index state WIP on feature/login: 3f2a1c4 Форма входа
$ git status
On branch feature/login
nothing to commit, working tree clean
Теперь можно переключиться, исправить баг, вернуться и достать отложенное. Каждое сохранение — это запись в стеке stash, внутри Git хранит её как особый коммит, поэтому данные надёжны и не зависят от ветки.
Как сохранить изменения: основные варианты
С понятным описанием
Стандартное описание «WIP on ветка» через неделю ничего не скажет. Подписывайте:
git stash push -m "валидация формы, не доделан e-mail"
git stash без аргументов — это сокращение для git stash push. Устаревшая форма git stash save "сообщение" ещё работает, но в новых сценариях используйте push -m.
Вместе с новыми файлами
По умолчанию stash забирает только отслеживаемые файлы — изменённые и добавленные в индекс. Новые файлы, которые ещё ни разу не были в git add, остаются в рабочей папке. Это частый сюрприз.
git stash -u # --include-untracked: плюс неотслеживаемые файлы
git stash -a # --all: плюс файлы из .gitignore
С -a осторожнее: в карман уедут и node_modules, и сборки, и локальные конфиги. Обычно хватает -u.
Только часть изменений
git stash push -m "конфиг" src/config.js # только указанные файлы
git stash -p # выбрать фрагменты интерактивно
git stash --staged # только то, что в индексе (Git 2.35+)
git stash --keep-index # отложить всё, но оставить индекс в папке
--keep-index полезен перед коммитом: вы оставляете в рабочей папке только то, что собираетесь закоммитить, прогоняете тесты и убеждаетесь, что коммит самодостаточен.
Как вернуть изменения (git unstash)
Команды git unstash в Git не существует — так обычно ищут способ достать отложенное. Для этого есть две команды.
| Команда | Что делает | Запись в стеке |
|---|---|---|
git stash pop | Применяет последние отложенные изменения | Удаляется, если применилось без конфликтов |
git stash apply | Применяет последние отложенные изменения | Остаётся |
git stash pop stash@{2} | Применяет конкретную запись | Удаляется |
git stash apply --index | Восстанавливает и разделение на индекс и рабочую папку | Остаётся |
$ git stash pop
On branch feature/login
Changes not staged for commit:
modified: src/auth.js
modified: src/form.js
Dropped refs/stash@{0} (8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d)
Обратите внимание: по умолчанию даже то, что было в индексе на момент stash, возвращается как обычные изменения. Если важно сохранить подготовленный индекс, добавьте --index.
pop или apply
Для повседневной работы удобен pop: достали и забыли. apply выбирайте, когда хотите применить одни и те же изменения в нескольких ветках или не уверены, что всё пройдёт гладко, — запись останется страховкой, а удалить её можно потом через git stash drop.
Работа со списком отложенного
$ git stash list
stash@{0}: On feature/login: валидация формы, не доделан e-mail
stash@{1}: WIP on main: 9b7e0d2 Обновить зависимости
stash@{2}: On feature/api: эксперимент с кэшем
Стек работает по принципу «последним положил — первым достал»: stash@{0} всегда самая свежая запись, и номера сдвигаются после каждого push и drop.
| Команда | Назначение |
|---|---|
git stash show | Краткая статистика изменений последней записи |
git stash show -p stash@{1} | Полный diff конкретной записи |
git stash drop stash@{1} | Удалить одну запись |
git stash clear | Удалить все записи разом |
git stash branch имя stash@{0} | Создать ветку от коммита, на котором делался stash, применить запись и удалить её |
Чтобы git stash show по умолчанию показывал не статистику, а полный diff и заодно неотслеживаемые файлы, есть настройки stash.showPatch и stash.showIncludeUntracked.
Пошаговый сценарий: срочный баг посреди задачи
- Отложите текущую работу вместе с новыми файлами:
git stash push -u -m "логин: черновик". - Переключитесь на основную ветку и создайте ветку для исправления:
git switch main,git pull,git switch -c hotfix/null-email. - Исправьте ошибку, закоммитьте, отправьте на ревью.
- Вернитесь к задаче:
git switch feature/login. - Достаньте правки:
git stash pop. Проверьтеgit status— всё на месте.
Сейчас многие для этого сценария используют git worktree: вторая рабочая папка для той же репы позволяет вообще ничего не откладывать. Но для быстрого переключения на пять минут stash по-прежнему проще.
Конфликты при применении stash
Если после stash в ветке изменились те же строки, применение закончится конфликтом:
$ git stash pop
Auto-merging src/auth.js
CONFLICT (content): Merge conflict in src/auth.js
The stash entry is kept in case you need it again.
Запись в этом случае не удаляется, даже при pop. Разрешите конфликт в файле как обычно, затем выполните git add для пометки решения (или git restore --staged, если не хотите оставлять изменения в индексе) и удалите ставшую ненужной запись через git stash drop.
Если конфликт сложный, удобнее обходной путь: git stash branch tmp-login. Git создаст ветку от того самого коммита, на котором вы делали stash, — там изменения применятся без конфликтов, а с основной веткой вы их сольёте уже обычным merge.
Как восстановить случайно удалённый stash
Выполнили git stash drop или clear по ошибке — не всё потеряно. Запись была коммитом, и пока сборщик мусора его не удалил, его можно найти среди «висячих» объектов:
git fsck --no-reflog | grep "dangling commit"
git show 8c1d2e3 # проверить, тот ли это stash
git stash apply 8c1d2e3
Если вы только что удалили запись через drop или pop, хеш напечатан прямо в выводе команды — в строке Dropped refs/stash@{0} (...). Его достаточно передать в git stash apply.
Как stash устроен внутри
Понимание устройства снимает страх потерять данные. Каждая запись stash — это обычный коммит, на который указывает ссылка refs/stash. У него два родителя: коммит HEAD, на котором вы стояли, и отдельный коммит с состоянием индекса. При -u добавляется третий родитель с неотслеживаемыми файлами. Список stash@{N} — это просто журнал (reflog) ссылки refs/stash.
Отсюда несколько практических следствий. Stash можно передать любой команде, которая принимает коммит: git diff stash@{0}, git show stash@{0}:src/auth.js (содержимое одного файла из записи) или git checkout stash@{0} -- src/auth.js, чтобы достать один файл, не применяя всю запись. А удалённая запись остаётся в базе объектов, пока её не уберёт сборка мусора.
Stash и другие команды Git
Некоторые команды умеют прятать изменения сами. git rebase --autostash и git pull --rebase --autostash перед началом откладывают незакоммиченные правки и возвращают их после окончания. Включить это поведение постоянно можно настройками rebase.autoStash true и merge.autoStash true. Если при возврате возникнет конфликт, Git сохранит запись в обычном стеке stash и сообщит об этом.
Переключение веток через git switch тоже не всегда требует stash: если ваши изменения не пересекаются с файлами, которые отличаются между ветками, Git просто перенесёт их с собой. Stash нужен, когда Git отвечает «Your local changes would be overwritten by checkout» или когда вы не хотите тащить правки в другую ветку.
Типичные ошибки
- Новые файлы «не спрятались». Они не отслеживаются, нужен
-u. - Stash как долговременное хранилище. Через месяц в списке десять безымянных «WIP on main», и никто не помнит, что там. Для долгой работы делайте коммит в отдельной ветке — его хотя бы можно запушить.
- Забыли, что запись осталась после конфликта, и спустя время применили её ещё раз. После разрешения конфликта всегда делайте
drop. - Stash не синхронизируется с сервером. Он хранится только в вашем локальном репозитории,
git pushего не отправляет. При удалении папки проекта stash пропадёт. - Применили не ту запись. Перед
popпосмотритеgit stash listиgit stash show -p.
Итог
git stash — быстрый способ освободить рабочую папку, не теряя незакоммиченных правок: git stash push -u -m "описание", чтобы отложить, и git stash pop, чтобы вернуть. Используйте apply, когда нужна страховка, git stash list и show -p, чтобы не запутаться, и не превращайте stash в склад — для всего долгого есть коммиты и ветки. Переключение между задачами со stash отрабатывается на практике в курсе по Git.
Частые вопросы
Можно ли применить stash в другой ветке?
Да, stash не привязан к ветке: переключитесь в нужную и выполните git stash pop или apply. Если изменения не накладываются, возникнет обычный конфликт.
Сохраняет ли git stash изменения в индексе?
Сохраняет, но при обычном pop или apply всё вернётся как неподготовленные изменения. Чтобы восстановить и индекс, используйте git stash apply --index.
Сколько записей можно хранить в stash?
Жёсткого ограничения нет, но записи старше срока хранения reflog могут быть удалены при сборке мусора. На практике держите в стеке не больше пары свежих записей.
Как сделать stash одного файла?
Укажите путь после двух дефисов или прямо после push: git stash push -m описание -- src/config.js. В stash уйдёт только этот файл, остальные правки останутся в рабочей папке.
Чем stash отличается от временного коммита?
Коммит живёт в ветке, его можно отправить на сервер и потом поправить через amend или rebase. Stash хранится только локально в отдельном стеке и удобен для коротких переключений.
Эта тема подробно разобрана с практикой в курсе «Git с нуля до уверенного разработчика».
Перейти к курсу