Когда нужен stash
Git stash — это «полка» для незаконченных правок: команда git stash убирает изменения из рабочей папки, чтобы можно было переключиться на другую ветку, а потом вернуть их обратно. Вы спрячете недоделанные стили подвала, срочно поправите главную в main и вернёте правки на место.
Вы уже встречали ошибку would be overwritten: Git не пускает в другую ветку, пока в папке есть незакоммиченные правки. Коммитить половину работы не хочется, а терять её — тем более.
Простыми словами
Вы месите тесто, и тут звонок в дверь. Тесто — в холодильник, руки помыли, открыли. Вернулись — достали тесто и продолжили. git stash — такой холодильник для правок.
Ситуация
Создайте ветку feature/footer-style и добавьте в конец style.css стиль подвала: отступ сверху и тонкую линию.
footer {
margin-top: 40px;
border-top: 1px solid #ddd;
}
$ git switch -c feature/footer-style
Switched to a new branch 'feature/footer-style'
$ git add style.css
$ git commit -m "Добавить стили подвала"
[feature/footer-style 2bc48f1] Добавить стили подвала
1 file changed, 4 insertions(+)
Продолжаете работу: добавляете в тот же блок цвет и размер текста, но ещё не закоммитили:
footer {
margin-top: 40px;
border-top: 1px solid #ddd;
color: #666;
font-size: 0.9rem;
}
И тут срочное дело: в разделе «Обо мне» на главной надо дописать фразу, и сделать это нужно в main. Пробуем перейти:
$ git switch main
error: Your local changes to the following files would be overwritten by checkout:
style.css
Please commit your changes or stash them before you switch branches.
Aborting
Разбор по строкам
would be overwritten by checkout: style.css— вmainфайлstyle.cssдругой (там нет блокаfooter), и переход затёр бы вашу правку.Please commit your changes or stash them— Git сам предлагает два выхода: закоммитить или спрятать (stash).
git stash push -m
Прячем правки с понятной подписью. Команда git stash push (stash — «припрятать») берёт все незакоммиченные изменения отслеживаемых файлов, кладёт их в отдельную запись и возвращает файлы к последнему коммиту. Флаг -m — подпись, как у коммита:
$ git stash push -m "Цвет и размер подвала"
Saved working directory and index state On feature/footer-style: Цвет и размер подвала
$ git status
On branch feature/footer-style
nothing to commit, working tree clean
$ git stash list
stash@{0}: On feature/footer-style: Цвет и размер подвала
Разбор по строкам
Saved working directory and index state— «сохранил состояние рабочей папки и индекса»: правки и то, что было в индексе.On feature/footer-style: Цвет и размер подвала— на какой ветке сделана запись и ваша подпись.nothing to commit, working tree clean— правок в папке больше нет:style.cssснова как в коммите2bc48f1.stash@{0}— номер записи. Записи лежат стопкой:0— самая свежая. Спрячете ещё что-то — новая станетstash@{0}, а эта сдвинется наstash@{1}.
Без подписи и в старых статьях
Просто git stash делает то же, что git stash push, но в списке появится WIP on feature/footer-style: 2bc48f1 Добавить стили подвала — это подпись последнего коммита, а не ваших правок: через неделю не вспомните, что там. Подписывайте через -m. В старых статьях встречается git stash save "подпись" — эта форма устарела, вместо неё git stash push -m.
Теперь папка чистая, и Git пускает в main. Делаем срочную правку: в index.html в разделе «Обо мне» дописываем вторую фразу.
$ git switch main
Switched to branch 'main'
$ git diff
...
- <p>Учусь программировать и делаю свой первый сайт.</p>
+ <p>Учусь программировать и делаю свой первый сайт. Историю версий веду в Git.</p>
...
$ git add index.html
$ git commit -m "Дополнить раздел «Обо мне»"
[main 5ef5a2f] Дополнить раздел «Обо мне»
1 file changed, 1 insertion(+), 1 deletion(-)
Вернуть: pop и apply
Срочное сделано. Возвращаемся в ветку и достаём правки с полки командой git stash pop:
$ git switch feature/footer-style
Switched to branch 'feature/footer-style'
$ git stash pop
On branch feature/footer-style
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: style.css
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (279acbaba33ac1f216770618c25e2d7ec10a6f3f)
$ git stash list
$
Разбор по строкам
- Сначала Git показывает
git status:modified: style.css— правки снова в рабочей папке. Dropped refs/stash@{0} (279acba...)— запись удалена с полки: правки вернулись, хранить её больше незачем.- Пустой
git stash list— полка пуста.
Проверьте git diff: в нём ваши две строки color и font-size. Доделайте работу и закоммитьте «Доделать стили подвала».
Кроме pop есть apply: он тоже возвращает правки, но запись на полке оставляет. Это удобно, если одну и ту же заготовку нужно применить в двух ветках. Ненужную запись удаляют git stash drop:
| Команда | Правки в папку | Запись на полке |
|---|---|---|
git stash pop | возвращает | удаляется |
git stash apply | возвращает | остаётся |
git stash drop | не возвращает | удаляется |
drop — без возврата
git stash drop удаляет запись вместе с правками, и вернуть их обычными командами не получится. Прежде чем удалять, посмотрите, что в записи: git stash show stash@{0} покажет файлы и число изменённых строк.
Конфликт при pop
Если пока правки лежали на полке, те же строки поменялись в ветке, pop закончится конфликтом. Например, вы спрятали белый фон, а потом закоммитили серый:
$ git stash pop
Auto-merging style.css
CONFLICT (content): Merge conflict in style.css
...
The stash entry is kept in case you need it again.
<<<<<<< Updated upstream
background: #f0f0f0;
=======
background: #ffffff;
>>>>>>> Stashed changes
Разбор по строкам
<<<<<<< Updated upstream— сверху то, что сейчас в ветке (из последнего коммита).>>>>>>> Stashed changes— снизу то, что было на полке.The stash entry is kept in case you need it again.— «запись оставлена на случай, если понадобится снова»: при конфликтеpopеё не удаляет.
Решается так же, как конфликт слияния: оставьте нужную строку, удалите маркеры и выполните git add style.css. Запись больше не нужна — удалите её git stash drop.
Неотслеживаемые файлы
По умолчанию stash берёт только правки файлов, которые Git уже отслеживает. Новый файл, который вы ни разу не добавляли, останется в папке. Проверим на пробу (на main с чистым статусом, например после практики): создайте пустой черновик draft.html и допишите любую строку в style.css. Короткий статус git status --short печатает по строке на файл: M — изменён, ?? — неотслеживаемый.
$ git status --short
M style.css
?? draft.html
$ git stash push -m "Черновик"
Saved working directory and index state On main: Черновик
$ git status --short
?? draft.html
Разбор по строкам
- После
git stashправкаstyle.cssушла на полку, а?? draft.htmlостался: новый файл stash не тронул.
Чтобы забрать и новые файлы, добавьте флаг -u (--include-untracked, «включая неотслеживаемые»). Верните прошлую запись (git stash pop) и спрячьте всё разом:
$ git stash push -u -m "Черновик со страницей"
Saved working directory and index state On main: Черновик со страницей
$ git status --short
$
Разбор по строкам
- Пустой
git status --short— в папке не осталось ни правок, ни нового файла: всё на полке. - Файлы из
.gitignore(например, ваша папкаnotes/) stash не трогает и с-u.
Опыт закончен — приберитесь: git stash pop вернёт обе правки, затем удалите draft.html и отмените строку в стилях: git restore style.css.
Подробно — в документации git stash.
Альтернатива: коммит-черновик
Stash хорош на несколько минут. Если уходите надолго, честнее закоммитить недоделку прямо в своей ветке: git commit -m "Черновик стилей подвала". Ветка ваша, никто не пострадает, а коммит не потеряется и виден в git log. Вернувшись, доделайте работу и поправьте этот коммит через git commit --amend — им вы уже исправляли последний коммит. Записи stash, наоборот, легко забыть: в git log их не видно.
Практика у себя
Шаг 1. На main с чистым статусом создайте feature/footer-style, добавьте блок footer с двумя свойствами и закоммитьте «Добавить стили подвала».
Шаг 2. Допишите в блок color: #666; и font-size: 0.9rem;, не коммитьте. Попробуйте git switch main — увидите would be overwritten.
Шаг 3. git stash push -m "Цвет и размер подвала", затем git stash list — должна быть одна запись stash@{0}.
Шаг 4. git switch main, допишите в «Обо мне» фразу «Историю версий веду в Git.» и закоммитьте «Дополнить раздел «Обо мне»».
Шаг 5. git switch feature/footer-style, git stash pop — увидите Dropped refs/stash@{0}. Закоммитьте «Доделать стили подвала».
Шаг 6. Слейте ветку: git switch main, git merge feature/footer-style (сохраните сообщение в редакторе), git branch -d feature/footer-style. История:
$ git log --oneline --graph
* 8f03c75 (HEAD -> main) Merge branch 'feature/footer-style'
|\
| * 7aeb0d8 Доделать стили подвала
| * 2bc48f1 Добавить стили подвала
* | 5ef5a2f Дополнить раздел «Обо мне»
|/
* 9a283db Merge branch 'feature/subtitle'
...
Проверьте себя
git stash listничего не выводит: полка пуста.- В истории есть
Merge branch 'feature/footer-style', а под ним — два коммита стилей и «Дополнить раздел «Обо мне»». - В браузере подвал серый, чуть мельче основного текста и отделён линией.
git status:nothing to commit, working tree clean.
Частые ошибки
Забытые записи. Спрятали, ушли, забыли — через неделю правки «пропали». Загляните в git stash list: они там. Посмотреть запись — git stash show stash@{1}, вернуть — git stash pop stash@{1}. Лучшая профилактика — подпись через -m и привычка не держать на полке ничего дольше дня.
pop не в той ветке. Правки применяются туда, где вы стоите, а не туда, где их прятали. Перед pop смотрите первую строку git status. Ошиблись — правки ещё не закоммичены: снова git stash push -m, перейдите в нужную ветку и pop там.
Новый файл не спрятался. Без -u stash не берёт неотслеживаемые файлы, и draft.html поедет за вами в другую ветку. Нужен git stash push -u -m "...".
No local changes to save. Прятать нечего: правок нет или они только в игнорируемых файлах. Это не ошибка.
Что важно запомнить
git stash push -m "подпись"убирает незакоммиченные правки на полку, папка становится чистой.git stash list— что лежит на полке;stash@{0}— самая свежая запись.pop— вернуть и удалить запись,apply— вернуть и оставить,drop— удалить без возврата.- Конфликт при
popрешается как конфликт слияния, а запись после него остаётся — удалите еёdrop. - Новые файлы — только с
-u. Надолго — лучше коммит-черновик в своей ветке.
Теперь у вас весь набор для работы с ветками: создать, слить, решить конфликт, отложить правки. В практикуме модуля соберёте всё вместе — сами проведёте две ветки к конфликту и решите его.