Как откатывать изменения в Git
Что проверяют
Различаете ли вы откат, который переписывает историю, и откат, который добавляет новый коммит, и понимаете ли, когда какой допустим. Почти всегда следом спрашивают, что делать, если коммит уже в общей ветке, или как вернуть работу после reset --hard.
Как отвечать
Идите от состояния изменений:
- не добавлены в индекс:
git restore <файл>возвращает файл к версии из индекса. Это современная заменаgit checkout -- <файл>, команда появилась в Git 2.23; - в индексе:
git restore --staged <файл>убирает из индекса, правки остаются в рабочей копии; - последний локальный коммит:
git commit --amend, чтобы поправить его, илиgit reset HEAD~1.--softоставляет изменения в индексе,--mixed(по умолчанию) в рабочей копии,--hardвыбрасывает их; - уже в общей ветке:
git revert <sha>создаёт коммит с обратными изменениями, история не переписывается. Для мерж-коммита нужен-m 1, чтобы указать основную линию; - своя ветка, которую никто не брал:
resetиgit push --force-with-lease. В отличие от--force, он не затрёт чужой коммит, появившийся на сервере после вашего последнего fetch.
Отдельно скажите про спасение. git reflog помнит, куда указывал HEAD, поэтому коммит после reset --hard возвращается через git reset --hard <sha из reflog>. Записи reflog по умолчанию хранятся от 30 до 90 дней. А незакоммиченные правки --hard уничтожает по-настоящему, для них в Android Studio остаётся Local History: её ведёт IDE независимо от Git.
В Android Studio те же операции есть в интерфейсе: Rollback в окне Commit по сути restore, Revert Commit в логе это git revert.
Где спотыкаются
Делают reset и push --force в main или develop. У коллег история расходится, и их следующий пуш либо отклоняется, либо возвращает удалённые коммиты.
Считают reset --hard необратимым для коммитов и паникуют, или наоборот, надеются достать через reflog незакоммиченные изменения.
Откатывают мерж через revert, потом снова мержат ту же ветку и не видят изменений. Git считает эти коммиты уже влитыми, сначала нужно откатить сам revert-коммит.