Программирование и IT

git stash

Заначка — временная полка для незаконченных правок. Ты кладёшь туда всё, что наработал, получаешь чистую рабочую копию, делаешь срочное дело и возвращаешь отложенное обратно. Полка общая на весь репозиторий и устроена как стопка: последнее положенное лежит сверху.

Обновлено
В этой статье

Когда это нужно#

Типичная ситуация: ты на середине правки, и тут приходит срочная задача в
другой ветке. Коммитить полуфабрикат не хочется, терять — тем более.
Заначка снимает изменения с рабочей копии и сохраняет их в репозитории как
обычные объекты git, то есть надёжно.

Второй повод — переключение ветки, которое git не пропускает из-за
конфликтующих правок. Третий — необходимость посмотреть, как программа ведёт
себя без твоих изменений: спрятал, проверил, вернул.

Важная оговорка: по умолчанию прячутся только изменения в отслеживаемых
файлах. Новый файл, который git ещё не видел, останется лежать в папке, и это
регулярно удивляет.

Синтаксис#

git stash push -m "половина формы оплаты"   # спрятать с понятной подписью
git stash push -u                           # вместе с новыми файлами
git stash push -- src/api.py                # спрятать только указанные пути
git stash list                              # что лежит на полке
git stash show -p stash@{1}                 # посмотреть содержимое записи
git stash apply stash@{1}                   # вернуть, оставив запись на полке
git stash pop                               # вернуть верхнюю и снять её с полки
git stash drop stash@{0}                    # выбросить запись
git stash branch fix-payment stash@{0}      # новая ветка из заначки

Короткое git stash без слов — то же, что git stash push. Подпись через
-m стоит писать всегда: через два дня записи без подписи различаются только
номерами и хешами.

Пример: отложить и вернуть#

$ git status -s
 M templates/checkout.html
 M billing/forms.py
$ git stash push -m "половина формы оплаты"
Saved working directory and index state On main: половина формы оплаты
$ git status -s
$ git stash list
stash@{0}: On main: половина формы оплаты

Рабочая копия чистая, можно спокойно переключаться и чинить срочное. Когда
вернулись:

$ git stash pop
On branch main
Changes not staged for commit:
        modified:   billing/forms.py
        modified:   templates/checkout.html

Dropped refs/stash@{0} (1f9a3b8c4d2e5f60718293a4b5c6d7e8f9a0b1c2)

Правки на месте, запись с полки снята. Хеш в последней строке — не украшение:
по нему запись можно вернуть, даже если её сняли по ошибке.

Пример: заначка с новыми файлами#

$ git status -s
 M report.py
?? templates/pdf.html
$ git stash push -u -m "черновик печати"
Saved working directory and index state On main: черновик печати
$ git status -s
$

Без -u файл templates/pdf.html остался бы в папке. С флагом — уехал на
полку вместе с остальным. Если нужны и игнорируемые файлы, есть более широкий
-a, но с ним легко утащить на полку папку сборки на сотни мегабайт.

Pop или apply#

Обе команды достают содержимое записи. Разница в том, что происходит с самой
записью: pop её удаляет, apply оставляет.

Аккуратнее работать через apply, а drop делать после того, как убедились:
правки встали куда надо и проект собирается. Тогда любая неожиданность —
применили не на той ветке, разрешили конфликт неудачно — стоит одной команды
git checkout ., потому что копия по-прежнему на полке.

При конфликте pop ведёт себя осторожно: конфликтные метки появляются в
файлах, но запись с полки не снимается. Разрешается такой конфликт ровно
так же, как любой другой, — порядок описан в статье о
конфликте слияния.

Ещё один аккуратный вариант — сразу завести ветку:

$ git stash branch feature-pdf stash@{0}

Git создаст ветку от того коммита, на котором делалась заначка, применит
правки и снимет запись. Это лучший выход, когда отложенное пролежало долго и
на текущую вершину уже не ложится.

Частые ошибки#

Забыли, что полка общая. Заначки не привязаны к ветке: положили на одной,
достали на другой — git не возразит. Подпись с именем ветки в тексте спасает
от путаницы.

git stash pop после переключения на другую ветку. Правки применятся
туда, где ты стоишь сейчас. Если это не то, что нужно, верни как было:
git stash push -m "не туда" и доставай уже на правильной ветке.

Запись удалена по ошибке. git stash drop и git stash clear выводят
хеш удалённого объекта, и объект живёт в базе до сборки мусора. Восстановить
можно так:

$ git stash drop
Dropped refs/stash@{0} (1f9a3b8c4d2e5f60718293a4b5c6d7e8f9a0b1c2)
$ git stash apply 1f9a3b8c4d2e5f60718293a4b5c6d7e8f9a0b1c2

Хеш потерялся вместе с окном терминала — остаётся поиск среди недостижимых
объектов: git fsck --unreachable | grep commit. Работает не всегда, поэтому
лучше не полагаться на этот путь.

Заначка вместо ветки. Полка хороша для часов, а не для недель: содержимое
не видно в истории, не отправляется на сервер и теряется вместе с диском.
Работа, которая переживает день, заслуживает коммита в отдельной ветке —
создать её можно за секунду, см. git checkout.

План по этапам

  1. Посмотреть, что прячешьgit status -s: есть ли среди правок новые файлы — от этого зависит флаг -u.
  2. Спрятать с подписьюgit stash push -m "понятный текст", при необходимости с -u.
  3. Сделать срочное делоРабочая копия чистая: переключение веток и сборка проходят без помех.
  4. Вернуть отложенноеgit stash list, затем git stash apply stash@{N} на нужной ветке.
  5. Прибрать полкуУбедиться, что всё встало верно, и git stash drop; длинную работу перевести в ветку.

Начать изучать эту тему у себя

План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.

Начать план

Проверь себя

1.Чем git stash pop отличается от git stash apply?

2.Какой флаг нужен, чтобы спрятать вместе с правками новый, ещё не отслеживаемый файл?

3.Отложенная работа лежит неделю и уже не ложится на текущую вершину. Что удобнее всего сделать?

Источники

Было полезно?

Ещё темы

Программирование и IT git push Пока ты не выполнил git push, твои коммиты существуют только на твоём диске. Команда отправляет их в удалённый репозиторий и сдвигает там указатель ветки — поэтому она же чаще всего и отказывает, если кто-то успел отправить своё раньше. Программирование и IT git pull Команда git pull приносит из удалённого репозитория чужие коммиты и сразу вливает их в твою текущую ветку. Это две операции подряд, и почти все трудности с pull растут из второй — из того, каким способом он соединяет истории. Программирование и IT Как создать репозиторий с нуля Репозиторий — это папка проекта плюс скрытая папка `.git`, в которой хранится вся история. Создаётся одной командой, но между ней и первым осмысленным коммитом есть несколько шагов, которые потом трудно переделать: имя ветки, список игнорируемых файлов, привязка к серверу. Программирование и IT git merge Слияние переносит работу из одной ветки в другую. Команда git merge берёт указанную ветку и соединяет её историю с текущей — иногда просто сдвигая указатель, иногда создавая отдельный коммит, а иногда останавливаясь и прося помощи. Программирование и IT git commit Коммит — это сохранённое состояние проекта с автором, временем и сообщением. Команда git commit берёт то, что ты заранее отобрал командой git add, и записывает это в историю одной неделимой порцией. Программирование и IT git clone Команда git clone забирает репозиторий с сервера целиком — со всей историей, ветками и тегами — и кладёт копию в новую папку на твоём компьютере. С неё начинается работа с любым уже существующим проектом, своим или чужим.

Ещё сценарии