Как удалить или изменить коммит, находящийся далеко в истории Git
Что проверяют
Умеете ли вы переписывать историю осознанно: различаете rebase, reset и revert и знаете, когда переписывать нельзя. Следом почти всегда спрашивают, что делать, если коммит уже в общей ветке или в нём оказался секрет.
Как отвечать
Разделите два случая: ветка только ваша или уже опубликована.
Личная ветка:
git rebase -i <hash>^: открывается список коммитов начиная с нужного.editостанавливает rebase на коммите, вы правите файлы, делаетеgit commit --amendиgit rebase --continue;rewordменяет только сообщение;dropили удалённая строка убирают коммит;git commit --fixup=<hash>и затемgit rebase -i --autosquash <hash>^: способ дописать исправление в старый коммит без ручной перестановки строк;- отправка: история переписана, поэтому нужен
git push --force-with-lease. В отличие от--force, он откажется пушить, если на сервере появились коммиты, которых у вас нет.
Общая ветка (main, develop):
git revert <hash>: новый коммит, отменяющий изменения. История не переписывается, коллегам ничего пересобирать не нужно.
В Android Studio то же доступно в окне Git: на коммите есть пункты интерактивного rebase, правки сообщения и удаления. Отдельный случай для Android-проекта: в историю попали keystore, пароли подписи в gradle.properties или ключи в local.properties. Здесь rebase мало, файл остаётся во всех клонах и форках. Историю чистят git filter-repo, а сам ключ считают скомпрометированным и перевыпускают.
Где спотыкаются
Предлагают git reset --hard <hash> как способ «удалить старый коммит». Он отбрасывает и все коммиты после него, а заодно незакоммиченные правки. Коммиты ещё можно вернуть через git reflog, незакоммиченные изменения уже нет.
Переписывают опубликованную общую ветку и пушат --force. У коллег история расходится, а их коммиты, запушенные за это время, стираются.
Чистят секрет через rebase и считают вопрос закрытым. Старые объекты остаются в клонах, форках и кэшах CI, поэтому ключ всё равно отзывают.