В мире Git традиционно сложилась странная ситуация, когда документация на важные команды не полностью объясняет что происходит в репозитарии, и вокруг таких команд появляется много мифов. Это отражается и в сторонних статьях, посвященных таким командам, что только добавляет путанницы.
Одна из таких команд - это команда git reset, а особенно её опция --hard, которой пугают новых пользователей Git. Дескать, она полностью обнуляет историю откаченных коммитов, и вернуть их невозможно. Пользуйтесь ей с осторожностью!
На самом деле, вот что нужно знать об этой команде:
- Есть несколько простых ситуаций, в которые может попасть пользователь-новичек, и из которых естественным образом можно выйти с помощью git reset --hard.
- Жесткий сброс не удаляет коммиты, и их можно свободно поместить в дополнительную ветку.
Вот типичная ситуация, в которой может оказаться программист:
Программист на протяжении нескольких коммитов писал неудачный код в ветке dev. Ему нужно откатиться до некоего предыдущего коммита a1b2c3, сделать развилку так, чтобы новый код продолжил добавляться в ветку dev, а все откаченные изменения оказались бы в ветке badExperiment для истории. Воркфлоу в конторе предполагает, что другие программисты сидят в других ветках, и наш программист полностью владеет веткой dev (это важно, так как любой reset - это откат по истории).
Как проще всего поступить в такой ситуации программисту? Надо дать следующие команды:
git checkout dev - переход на конец ветки dev
git branch badExperiment - создание ветки badExperiment
Первая команда переместит рабочий указатель HEAD на конец ветки dev. Скорее всего, программист и так находится в конце ветки dev. Но если происходило перемещение по истории, или переключение на другую ветку, то эта команда необходима. Далее, находясь на конце ветки dev, дается команда создания ветки badExperiment.
Здесь надо обратить внимание, что команда git branch вызвана без опции -b, то есть ветка создается, но на нее переключения не происходит. Тут нужно напомнить, что имена веток - это просто указатели на коммиты. И после таких команд указатель dev и указатель badExperiment будут указывать на один и тот же последний коммит.
Далее, находясь в ветке dev, нужно сделать хардресет до нужного коммита:
git reset --hard a1b2c3
Указатель dev переместится на этот коммит. А благодаря тому, что была сделана ветка badExperiment, все коммиты, сделанные после a1b2c3 останутся в репозитарии, и их всегда можно будет посмотреть, переключившись на ветку badExperiment.
В общем, после этой команды репозитарий считает, что ветка dev заканчивается на коммите a1b2c3. Об этом изменении надо оповестить удаленный репозитарий. Делается это командой:
git push --force
Опция --force обязательна, так как по сути, происходит откат назад по истории коммитов.
Кроме того, на удаленный репозитарий нужно залить ветку badExperiment чтобы руководитель проекта видел, что программист не балду пинал, а неистово работал, хоть и не плодотворно. Залитие ветки badExperiment в удаленный репозитарий прозводится командами:
# переключение на ветку badExperiment
git checkout badExperiment
# Заливка текущей ветки на удаленный репозитарий origin как badExperiment
git push --set-upstream origin badExperiment
После этих команд можно переключиться на ветку dev и продолжить программировать. Все новые коммиты будут продолжать укладываться в ветку dev.