Все главы учебника
Содержание учебника
Глава 11 / Git

Cherry-pick и stash: перенести правку, отложить черновик

18 мин чтенияКонтент v0.10.0

Нужен один фикс, а не вся ветка

В экспериментальной ветке нашли опечатку в инструкции. Остальные её изменения ещё не готовы. Если слить всю ветку, main получит незаконченные правила. Cherry-pick переносит изменение выбранного коммита в текущую линию и обычно создаёт новый коммит. Он не объявляет всю исходную ветку объединённой.

Перед переносом прочитайте show выбранного коммита и проверьте зависимости. Если исправление использует файл, добавленный предыдущей записью той ветки, одной выбранной правки может быть недостаточно. Git умеет применить текст, но не проверяет полноту бизнес-логики. Руководство cherry-pick задаёт продолжение и отмену при конфликте.

Другая ситуация: вам срочно нужно переключиться, а рабочий текст ещё не готов к осмысленному commit. Stash сохраняет временное состояние для последующего применения. По умолчанию неотслеживаемые файлы не включаются; -u добавляет их. Ignored-файлы требуют другого выбора и в этой лаборатории не нужны. Stash находится локально, не отправляется обычным push и не заменяет долговременную резервную копию.

Перенесите отдельный коммит

lab=$(mktemp -d "${TMPDIR:-/tmp}/git-11.XXXXXX")
cd "$lab"
git init -b main
git config user.name "Учебный автор"
git config user.email "learner@example.invalid"
git config commit.gpgsign false
printf 'Run localy\n' > README.txt
git add README.txt
git commit -m "Describe launch"
git switch -c experiment
printf 'Run locally\n' > README.txt
git add README.txt
git commit -m "Fix launch spelling"
fix=$(git rev-parse HEAD)
printf 'unfinished rule\n' > experiment.txt
git add experiment.txt
git commit -m "Draft experimental rule"
git switch main
printf 'queue=16\n' > limits.txt
git add limits.txt
git commit -m "Add stable limit"
git cherry-pick "$fix"
cat README.txt
git ls-tree --name-only HEAD
git log --graph --oneline --all

В main опечатка исправлена, limits.txt сохранён, experiment.txt отсутствует. Cherry-pick создал исправление на другом родителе, поэтому его хеш отличается от исходного. Мы специально добавили независимый коммит в main: при полностью совпавших метаданных и исходной базе некоторые простые воспроизведения могут дать тот же объект, поэтому сравнивайте модель, а не обещайте изменение любого хеша без условий.

При конфликте разрешайте результат, добавляйте файл и вызывайте git cherry-pick --continue. Если перенос не нужен, git cherry-pick --abort возвращает состояние до операции. Позже merge исходной ветки может столкнуться с уже перенесённым изменением. Отсутствие конфликта в простом тексте не превращает cherry-pick в запись о слиянии всей линии.

Отложите незавершённый текст

printf 'Run locally\nDraft explanation\n' > README.txt
printf 'question for later\n' > scratch.txt
git stash push -u -m "Draft launch explanation"
git status --short
git stash list
git stash show --stat 'stash@{0}'
git stash apply 'stash@{0}'
git status --short
cat scratch.txt
git stash drop 'stash@{0}'

После push дерево чистое: оба учебных изменения отложены. После apply они возвращаются, а запись stash пока остаётся. Только после чтения файлов мы вызываем drop. Это удобнее для первого опыта, чем сразу pop, который при успешном применении ещё и удаляет запись. Stash подробно описывает область сохраняемых файлов и применение.

Применение поверх другой версии может конфликтовать. Сначала читайте status, сохраняйте нужные варианты и разрешайте содержимое. У stash нет команды stash --continue, аналогичной rebase. Если pop остановился на конфликте, запись обычно остаётся; не удаляйте её только ради короткого списка.

Проверьте зависимость и область временного хранения

Исправление меняет строку в новом файле, которого main ещё не знает. Даже если вы выбрали самый маленький коммит, перенос может конфликтовать или оказаться бессмысленным. Прочитайте предыдущую историю пути и назовите необходимую основу. Иногда правильнее подготовить самостоятельный фикс для старой версии, чем переносить чужой коммит буквально.

Для stash задайте другой вопрос: вы хотите отложить только исходники или ещё учебную заметку? Проверьте status до и после и назовите выбранную область. Наличие сообщения stash в списке не доказывает, что заметка включена. Обычный push не передаст её другому клону.

Попробуйте объяснить эти случаи одной общей привычкой: перед командой назвать содержимое, которое будет перенесено, затем проверить его после действия. У cherry-pick единицей выбора является сохранённая правка коммита, у stash — временное состояние выбранных файлов. Они не заменяют друг друга, хотя оба позволяют продолжить работу на другой основе.

Самостоятельная лаборатория

Практика — 40–60 минут. Создайте ветку с двумя коммитами: самостоятельное исправление и незаконченная функция в отдельном файле. В main сделайте независимую правку и перенесите только исправление. Докажите, что второй файл не вошёл в снимок, а основной текст сохранил оба готовых изменения.

После этого измените tracked-файл и создайте untracked-заметку. Сначала попробуйте stash без -u, посмотрите, что осталось, примените обратно и разберите результат. Затем повторите с -u. Проверьте каждый файл до удаления временной записи. Сравните, что будет с локальными stash после clone в другую папку: обычный клон не получает ваш список таких черновиков.

Критерии готовности

Вы выбираете коммит по содержимому, а не по последнему месту в log. Перенос не добавил незавершённый файл. Stash включает ровно выбранную область, её применение проверено до drop. Можете объяснить различие apply и pop и назвать способ отменить конфликтующий cherry-pick.

Разбор

Первая часть лаборатории оставляет main с готовым исправлением и собственной независимой записью. Во второй без -u заметка остаётся в рабочей папке: это ожидаемая граница, а не потеря stash. После успешного apply запись всё ещё существует, пока вы её явно не убрали.

Если перенесённый фикс не работает без предыдущей записи experiment, условие независимости нарушено. Нужно пересмотреть набор изменений или исправить зависимость, а не скрывать ошибку повторным add. Если stash list пуст после clone, это не проблема удалённой синхронизации.

Дальше найдём первую поломку через bisect. Первичные источники текущего урока — cherry-pick и stash по приведённым ссылкам. Сохраните краткую причину выбора одного коммита: в настоящем ревью она помогает понять, почему весь эксперимент остался за пределами main.