Олег Марков
Временное сохранение изменений - git stash
Введение
При работе с Git почти у каждого разработчика возникает ситуация, когда нужно срочно переключиться на другую задачу, но текущие изменения еще не готовы для коммита. Коммитить «сырую» работу не хочется, а выбрасывать изменения тем более.
Здесь на помощь приходит команда git stash. Она позволяет временно убрать изменения «в сторону», очистить рабочую директорию и вернуться к ним позже. Смотрите, я покажу вам, как это работает, как устроен стек сохранений и какие возможности кроме простого сохранения и восстановления изменений вы получаете.
В этой статье мы разберем:
- что такое stash и как он хранится в репозитории;
- базовые команды git stash и их различия;
- как сохранять только часть изменений;
- как работать с несколькими stash-записями;
- как сравнивать, переименовывать и переносить stashes между ветками;
- типичные ошибки и как их избежать.
Теперь давайте по шагам разберем все возможности git stash.
Что такое git stash и как он работает
Концепция временного сохранения
Git stash — это механизм временного сохранения незакоммиченных изменений. Можно представить его как отдельный стек «черновиков», в который вы складываете свои правки, чтобы освободить рабочую директорию.
Важно понимать несколько моментов:
- stash сохраняет изменения относительно последнего коммита в текущей ветке;
- сохранения организованы в виде стека — последняя запись сверху;
- stash не привязан жестко к ветке — его можно применять в другой ветке (но нужно следить за конфликтами);
- каждое сохранение — это по сути пара (или три) служебных коммитов в специальной области
refs/stash.
Какие файлы попадают в git stash
По умолчанию git stash:
- сохраняет:
- изменения в уже отслеживаемых файлах (modified);
- удаленные отслеживаемые файлы (deleted);
- не затрагивает:
- неотслеживаемые файлы (untracked,
??вgit status); - игнорируемые файлы (ignored, указанные в
.gitignore).
- неотслеживаемые файлы (untracked,
Но эти ограничения можно менять флагами, о которых мы поговорим далее.
Давайте перейдем к базовым командам.
Базовое использование git stash
Классический сценарий применения
Представьте, что вы работаете над фичей в ветке feature/login, правите несколько файлов, но тут приходит запрос: «Срочно поправь баг в main». Изменения еще не готовы к коммиту.
Пошаговый сценарий:
- Сохранить текущие изменения во временное хранилище.
- Очистить рабочую директорию до состояния последнего коммита.
- Переключиться на другую ветку, сделать правку, закоммитить.
- Вернуться на исходную ветку и восстановить свои изменения.
Пример:
# Проверяем текущий статус
git status
# Временно убираем изменения
git stash
# Переключаемся на основную ветку
git checkout main
# Фиксим баг, коммитим и пушим
# ...
# Возвращаемся к своей ветке
git checkout feature/login
# Достаем сохраненные изменения
git stash pop
Комментарии к примеру:
git stashсоздаст новую запись в стеке и очистит рабочую директорию.git stash pop:- применит последние сохраненные изменения;
- удалит соответствующую запись из стека.
git stash save и git stash (различия)
Раньше основная форма выглядела так:
git stash save "Сообщение"
Сейчас рекомендуемая и более современная форма — просто:
git stash push -m "Сообщение" # с явным указанием subcommand
или даже:
git stash # сокращение для git stash push
Разница:
git stashбез аргументов =git stash push;git stash saveсчитается устаревающим стилем и повторяет поведениеgit stash push.
Чтобы не путаться, лучше запомнить: используете git stash push и git stash pop/apply.
Различия между git stash pop и git stash apply
Это один из частых вопросов, давайте разберемся.
git stash apply
- применяет изменения из stash к рабочей директории;
- не удаляет запись из стека.
Пример:
# Смотрим список сохранений
git stash list
# Применяем конкретное сохранение, но не удаляем его
git stash apply stash@{2}
Здесь:
stash@{2}— это третье по счету сохранение в вашем стеке;- после команды
applyэта запись по-прежнему останется вgit stash list.
apply удобно использовать, когда вы:
- хотите применить один и тот же stash в несколько веток;
- не уверены, все ли пройдет без конфликтов, и хотите иметь резерв.
git stash pop
- делает то же самое, что
apply, но удаляет запись из стека при успешном применении.
Пример:
# Применяем последнее сохранение и удаляем его из стека
git stash pop
Если при pop возникнут конфликты при слиянии, stash все равно будет удален, если Git посчитает применение успешным на уровне рефов. Из-за этого многие предпочитают безопасный подход:
git stash apply stash@{0} # используем apply
# решаем конфликты, проверяем работу
git stash drop stash@{0} # вручную удаляем, когда все ок
Так меньше шансов случайно потерять изменения.
Создание stash с разными опциями
Простое сохранение: git stash push
Базовая форма:
git stash push
Эта команда:
- сохраняет изменения в отслеживаемых файлах;
- убирает их из рабочей директории;
- оставляет неотслеживаемые файлы как есть.
Часто хочется подписать сохранение:
git stash push -m "Черновик формы логина"
Комментарий:
- флаг
-mзадает человекочитаемое описание; - позже вы увидите его в
git stash list.
Сохранение вместе с неотслеживаемыми файлами
Иногда вы создаете новые файлы, которые еще не добавляли в индекс (git add), но хотите тоже их сохранить во временное хранилище. Тогда используйте -u или --include-untracked:
git stash push -u -m "Изменения + новые файлы"
Что произойдет:
- все изменения в отслеживаемых файлах сохранятся;
- все неотслеживаемые файлы тоже попадут в stash;
- в рабочей директории станет «чисто» (как после
git statusбез изменений).
Сохранение с игнорируемыми файлами
Реже, но все же бывает, что нужно stash-ить даже игнорируемые файлы (например, временные конфиги разработчика, которые не должны попадать в репозиторий, но вы не хотите их потерять).
В этом случае:
git stash push -a -m "Сохранить все вообще"
Флаг -a или --all:
- включает и неотслеживаемые, и игнорируемые файлы;
- это максимально «глубокое» сохранение состояния рабочей директории.
Сохранение только индексированных изменений
Иногда вы уже сделали git add для части файлов, а другая часть еще в рабочей директории как modified. Смотрите, как можно сохранить только те изменения, которые уже добавлены в индекс:
git stash push --keep-index -m "Проверить только закоммичиваемые изменения"
Что делает --keep-index:
- сохраняет незакоммиченные изменения, которые не в индексе;
- изменения, которые вы уже добавили в индекс, оставляет нетронутыми.
Типичный сценарий:
- Вы готовите коммит, делаете
git addнужных файлов. - Хотите запустить тесты только для будущего коммита без «лишних» правок.
- Делаете
git stash push --keep-index. - Запускаете тесты.
- Делаете
git stash pop(илиapply), чтобы вернуть остальные изменения.
Теперь давайте посмотрим, как работать с несколькими сохранениями.
Работа со стеком сохранений
Просмотр списка сохранений
Чтобы посмотреть, какие временные сохранения у вас есть, используйте:
git stash list
Вы увидите что-то вроде:
stash@{0}: On feature/login: Черновик формы логина
stash@{1}: On main: Фикс стилей шапки
stash@{2}: On feature/profile: Рефакторинг профиля пользователя
Обратите внимание:
stash@{0}— самое последнее сохранение;stash@{1},stash@{2}и так далее — более старые;- после
On <ветка>указано сообщение, которое вы передали через-m.
Просмотр содержимого конкретного stash
Иногда вы хотите понять, что именно лежит в конкретном сохранении, прежде чем его применять. Здесь я размещаю пример, чтобы вам было проще понять:
# Сравнить stash@{1} с текущим состоянием HEAD
git stash show stash@{1}
Эта команда покажет короткий список измененных файлов. Чтобы увидеть полный diff, добавьте -p:
git stash show -p stash@{1}
Комментарий:
- это удобно, когда у вас много сохранений, и вы хотите вспомнить, что внутри;
- флаг
-p(или--patch) показывает построчные изменения.
Применение конкретного stash
По умолчанию git stash pop и git stash apply работают с последним сохранением (stash@{0}), но вы можете явно указать запись:
# Применяем второе по счету сохранение, но не удаляем его
git stash apply stash@{1}
# Применяем и удаляем
git stash pop stash@{1}
Если вы применяете не верхний элемент стека через pop, Git:
- попытается применить указанный stash;
- после успеха удалит именно его, а не
stash@{0}; - остальные записи сдвинет (индексы пересчитаются).
Удаление отдельных и всех сохранений
Если сохранение больше не нужно, его можно убрать:
# Удалить конкретный stash
git stash drop stash@{2}
# Удалить последний (аналог drop stash@{0})
git stash drop
Удалить все сохранения разом:
git stash clear
С этой командой нужно быть аккуратнее — она безвозвратно очищает весь стек.
Частичное сохранение изменений (stash только части файлов)
Бывает, что в рабочей директории намешано много всего, а stash-ить нужно только часть изменений. Давайте разберемся на примере.
Использование git stash push с указанием файлов
Вы можете явно указать, какие файлы попадут в stash:
git stash push -m "Только изменения в login.go" path/to/login.go
В этом случае:
- изменения в
path/to/login.goсохранятся в stash; - остальные изменения останутся в рабочей директории;
- stash будет содержать только указанный файл.
Можно указать несколько файлов или каталогов:
git stash push -m "Фронтенд изменения" src/frontend/ package.json
Комбинация с индексом (staging area)
Есть полезный прием:
- Добавить в индекс только те изменения, которые вы хотите stash-ить.
- Использовать
--keep-index, чтобы разделить изменения.
Пример:
# Добавляем изменения, которые хотим временно убрать
git add src/feature_a/
# Сохраняем их в stash, но при этом оставляем их в индексе
git stash push --keep-index -m "Временный stash feature_a"
# Теперь можно сделать, например, коммит по остальной части кода
# или наоборот - по этим изменениям
Но чаще --keep-index применяют именно для временного удаления неиндексированных изменений, чтобы тестировать только «почти готовый» коммит.
Работа со stash и ветками
Применение stash в другой ветке
Ситуация: вы сделали временное сохранение в ветке feature/login, а потом решили, что эти изменения нужно перенести в новую ветку feature/new-login. Покажу вам, как это реализовано на практике.
Пошагово:
# Находимся на feature/login и делаем временное сохранение
git stash push -m "Черновик нового логина"
# Создаем новую ветку от нужной базы
git checkout -b feature/new-login origin/main
# Применяем сохранение в новую ветку
git stash pop stash@{0}
Важно:
- git stash не «привязан» жестко к ветке, но его содержимое — это изменения относительно конкретного базового коммита;
- если вы применяете stash в ветке с сильно отличающейся историей, возможны конфликты.
Создание ветки из stash: git stash branch
Отдельная полезная команда — git stash branch. Она берет:
- базовый коммит, от которого был сделан stash;
- сам stash;
и создает на их основе новую ветку. Это удобно, когда:
- вы что-то накидали «на коленке»;
- вдруг поняли, что из этого получится нормальная фича;
- хотите оформить ее в отдельную ветку.
Пример:
# Смотрим список временных сохранений
git stash list
# Создаем ветку из второго stash
git stash branch feature/async-login stash@{1}
Что произойдет:
- Git найдет коммит, относительно которого был сделан
stash@{1}. - Создаст от него новую ветку
feature/async-loginи переключится на нее. - Попробует применить
stash@{1}к этой ветке. - При успешном применении удалит
stash@{1}из стека.
Если применение не удалось (слишком много конфликтов), stash не будет удален.
Конфликты при применении git stash
Почему возникают конфликты
Конфликты при git stash apply или pop — обычное явление, особенно если вы:
- долго держали изменения в stash;
- в базовой ветке успело многое поменяться;
- применяете stash в ветку, отличающуюся от исходной.
По сути, Git выполняет мини-слияние:
- берет базовый коммит;
- берет изменения из stash;
- берет текущее состояние рабочей ветки;
- пытается совместить их.
Если изменения затрагивают одни и те же строки в файлах, возникают конфликты.
Как решать конфликты после git stash apply/pop
Здесь алгоритм такой же, как при обычном конфликте слияния:
# Применили stash и получили конфликты
git stash apply stash@{0}
# Git покажет, что есть конфликтующие файлы
git status
# Открываем конфликтующие файлы, вручную правим <<<<<<< HEAD и >>>>>>>
# После правок помечаем файл как решенный
git add path/to/conflicted-file
# Когда все конфликты решены, можно продолжить работу
# Например, сделать коммит с восстановленными правками
git commit -m "Восстановить изменения из stash и разрешить конфликты"
Если вы использовали git stash pop:
- при возникновении конфликтов stash обычно все равно считается примененным, и запись удаляется;
- чтобы подстраховаться, многие командой
popпользуются реже, предпочитаяapply+drop, как мы уже обсуждали.
Stash и разные области изменений: рабочая директория и индекс
Что именно сохраняет git stash внутри
Давайте посмотрим чуть глубже. Внутри один stash — это:
- один коммит с изменениями рабочей директории (modified/removed файлы);
- один коммит с изменениями индекса (staged часть), если они есть;
- иногда третий объект для неотслеживаемых файлов.
То есть git stash умеет раздельно сохранять:
- то, что уже было добавлено в индекс (staged);
- то, что просто изменено в рабочей копии (unstaged).
Из-за этого при применении stash состояние индекса и рабочей директории тоже восстанавливается примерно в том виде, в каком вы его сохраняли.
Пример с изменениями в индексе и рабочей директории
Давайте посмотрим, что происходит в типичной ситуации:
# Меняем два файла
vim a.go
vim b.go
# Добавляем в индекс только a.go
git add a.go
# Смотрим статус
git status
# Вы увидите:
# изменения для коммита: a.go
# неиндексированные изменения: b.go
# Делаем обычный stash
git stash push -m "Изменения в a.go и b.go"
Что сохранится:
- и staged, и unstaged изменения попадут в stash;
- рабочая директория станет чистой, индекс — тоже.
При git stash apply:
- файл
a.goвернется в состояние «изменен и уже добавлен в индекс»; - файл
b.goвернется как «изменен, но не в индексе».
Просмотр и анализ stash через git show и git diff
Детальный просмотр содержимого stash
Мы уже смотрели на git stash show -p, но можно использовать и обычные инструменты Git:
# Показать полное содержимое stash как обычный коммит
git show stash@{0}
Обратите внимание, как этот фрагмент кода решает задачу диагностики:
git showпоказывает diff и метаинформацию;- вы видите точное состояние изменений, которые собираетесь восстановить.
Сравнение двух stash-записей
Иногда бывает полезно сравнить разные временные сохранения между собой:
git diff stash@{2} stash@{0}
Так вы увидите, чем отличаются два «черновика». Это не самый частый кейс, но полезен, когда вы, например, экспериментировали с разными подходами в коде и сохранили их в несколько stashes.
Частичные stashes через интерактивный режим (патчи)
Git stash не имеет отдельного интерактивного флага, как git add -p, но вы можете комбинировать его с индексом.
Прием: git add -p + git stash
Смотрите, я покажу вам пошаговый пример:
# У вас есть большой файл с разными изменениями
vim app.go
# Добавляем в индекс только часть изменений интерактивно
git add -p app.go # выбираете hunks, которые хотите временно убрать
# Теперь в индексе только часть изменений
git status
# Используем stash как механизм временного перемещения
git stash push -m "Часть изменений app.go"
# В результате:
# - выбранные куски переместились в stash
# - остальные изменения остались в рабочем файле
То есть через git add -p вы решаете, какие hunks попадут в stash, а какие останутся. Это гибкий способ частичного временного сохранения без создания лишних локальных веток.
Риски при использовании git stash и как их уменьшить
Основные риски
Основные проблемы, с которыми сталкиваются разработчики:
- забытые stashes, которые копятся месяцами;
- применение stash в «не той» ветке и конфликты, которые сложно разрулить;
- потеря изменений из-за неосторожного
git stash clearили из-за конфликтногоgit stash pop.
Практичные рекомендации
Давайте осмысленные сообщения
Используйте
-m, чтобы через месяц понимать, что было внутри:git stash push -m "WIP - валидация формы регистрации"Не превращайте stash в долговременное хранилище
Если понимаете, что работа затягивается, лучше:
- создать отдельную ветку;
- применить stash туда;
- сделать один или несколько рабочих коммитов.
Предпочитайте apply + drop для важных изменений
Вместо:
git stash popможно использовать:
git stash apply stash@{0} # проверить, что все в порядке git stash drop stash@{0}Так меньше шансов случайно потерять изменения.
Периодически проверяйте git stash list
Если видите старые записи:
- или удалите их (
git stash drop,git stash clear); - или превратите в отдельные ветки (
git stash branch).
- или удалите их (
Практические сценарии использования git stash
Быстро переключиться на горячий фикс (hotfix)
Сценарий:
- Работаете над новой фичей в
feature/checkout. - Появляется срочный баг в
main.
Действия:
# Сохраняем текущие изменения, в том числе новые файлы
git stash push -u -m "WIP checkout improvements"
# Переключаемся на main
git checkout main
# Создаем ветку для hotfix
git checkout -b hotfix/cart-bug
# Фиксим баг, коммитим, вливаем в main
# ...
# Возвращаемся к своей работе
git checkout feature/checkout
# Восстанавливаем изменения
git stash pop
Разделить большую задачу на несколько веток
Иногда вы начали делать одну большую задачу, но в процессе понимаете, что часть работы — это отдельная фича. Тогда удобно:
# Находясь в feature/large-feature
git stash push -m "Подзадача: новый компонент профиля"
# Создаете новую ветку
git checkout -b feature/profile-component
# Применяете stash в новую ветку
git stash pop
# Оформляете отдельные коммиты и PR
Временное скрытие экспериментального кода
Бывает, вы экспериментировали с подходом, результат пока неясен, но нужно на время вернуться к чистому состоянию. Тогда stash работает как «быстрая заморозка»:
git stash push -m "Экспериментальный алгоритм поиска"
# Поработали с чистым кодом
git stash pop # когда хотите вернуть эксперимент
Заключение
Git stash — это не просто «корзина» для временного кода, а полноценный инструмент управления незакоммиченными изменениями. Он позволяет:
- безопасно переключаться между ветками и задачами;
- временно убирать «сырой» код, не засоряя историю коммитов;
- хранить сразу несколько наборов изменений и по необходимости к ним возвращаться;
- переносить черновики между ветками и даже создавать новые ветки прямо из stash.
Ключевые моменты, которые стоит запомнить:
git stash push— базовая команда для сохранения изменений;git stash applyприменяет изменения, но не удаляет их;git stash popприменяет и удаляет запись (используйте осторожнее);-uи-aуправляют тем, какие файлы попадут в stash (включая неотслеживаемые и игнорируемые);git stash branchудобен, когда из черновика выросла полноценная фича.
Чем лучше вы понимаете, как именно git stash сохраняет и восстанавливает состояние (рабочая директория + индекс), тем увереннее будете пользоваться им в реальных проектах.
Частозадаваемые технические вопросы по теме и ответы
1. Как восстановить stash, если я случайно сделал git stash clear?
Если вы уже выполнили git stash clear, стандартными средствами Git восстановить записи практически невозможно. Однако иногда объекты еще есть в базе, и помогает просмотр reflog:
# Смотрим историю перемещений ссылок
git reflog
# Ищем ссылки вида stash@{...} или коммиты, соответствующие stash
# Берем нужный хеш и создаем от него ветку
git branch restore-from-stash <hash>
Если ссылки на stash не сохранились в reflog, восстановление, как правило, невозможно.
2. Можно ли переименовать уже созданный stash?
Напрямую — нет. Но можно создать новый stash с нужным именем на основе старого и удалить оригинал:
# Применяем старый stash без удаления
git stash apply stash@{1}
# Создаем новый с нужным сообщением
git stash push -m "Новое понятное имя"
# Удаляем старый
git stash drop stash@{1}
Так вы получите функциональный аналог «переименования».
3. Как сохранить stash только для неотслеживаемых файлов?
Напрямую Git не умеет stash-ить строго только неотслеживаемые файлы, но можно использовать обходной путь:
# Временно добавляем только неотслеживаемые файлы
git add -N .
# Теперь они считаются измененными отслеживаемыми
git stash push -m "Только ранее неотслеживаемые файлы"
# По желанию можно сбросить индекс
git reset
Команда git add -N помечает файлы как отслеживаемые без фактического добавления содержимого.
4. Что делать, если после git stash pop остались конфликты и непонятное состояние?
Алгоритм такой:
Посмотрите статус:
git statusДля каждого конфликтующего файла:
- откройте его;
- вручную решите конфликтные участки
<<<<<<<,=======,>>>>>>>; отметьте файл как решенный:
git add path/to/file
После всех правок сделайте коммит, чтобы зафиксировать итоговое состояние.
Если все совсем плохо и вы хотите откатиться:
git merge --abort # если Git считает, что вы в процессе слияния
git reset --hard # вернет к последнему коммиту (осторожно, потеряете незакоммиченные изменения)
5. Можно ли автоматически применять stash после успешного мержа или переключения ветки?
Прямого встроенного механизма нет, но можно использовать хуки Git (например, post-checkout или post-merge) и там вызывать свои скрипты:
# .git/hooks/post-checkout (сделайте исполняемым)
#!/bin/sh
# Пример - если есть stash, выводим напоминание
if git stash list | grep -q "WIP"; then
echo "Есть незакрытые WIP-stash записи"
fi
Через хуки вы можете реализовать любую автоматизацию вокруг git stash, но стоит делать это аккуратно, чтобы не ломать ожидаемое поведение Git.
Постройте личный план изучения Git до уровня Middle — бесплатно!
Git — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Git
Лучшие курсы по теме

Основы Git
Антон Ларичев
TypeScript с нуля
Антон Ларичев