Как откатить изменения в файле в Git?

Ответ

Есть несколько способов отката изменений в Git, в зависимости от того, на каком этапе находится файл.

1. Откат незакоммиченных изменений в рабочей директории

Если вы еще не добавили файл в индекс (git add), чтобы отменить все локальные правки и вернуть файл к состоянию последнего коммита:

git restore <file>
# Или устаревшая, но знакомая команда:
# git checkout -- <file>

2. Откат изменений, добавленных в индекс (staged)

Если вы выполнили git add, но еще не закоммитили:

# Убираем файл из индекса, но сохраняем изменения в рабочей директории
git restore --staged <file>
# Затем, если нужно, откатываем и сами изменения в файле:
git restore <file>

3. Создание коммита, отменяющего предыдущий (revert)

Безопасный способ отменить изменения, уже попавшие в историю. Создает новый коммит с инверсными изменениями.

# Откатываем конкретный коммит
git revert <commit-hash>
# Откатываем последний коммит
git revert HEAD

4. «Удаление» коммита из истории (reset)

Опасно! Меняет историю. Используйте только в локальной ветке, если изменения не были отправлены в общий репозиторий.

# «Удаляет» последний коммит, но оставляет изменения в рабочей директории
git reset --soft HEAD~
# «Удаляет» последний коммит и убирает изменения из индекса
git reset HEAD~
# «Удаляет» последний коммит и полностью стирает изменения из файлов
git reset --hard HEAD~

5. Поиск и восстановление утерянных коммитов

Если вы уже сделали reset --hard и потеряли коммит, его можно найти и восстановить:

# Показать историю всех действий (включая «удаленные» коммиты)
git reflog
# Восстановить состояние на момент выбранного действия
git reset --hard <hash-from-reflog>

Ответ 18+ 🔞

А, ну вот, опять накосячил с кодом и надо всё откатить? Бывает, чёрт возьми, со всеми случается. Сейчас разберёмся, как из этой жопы вылезти. Главное — не паниковать и не делать резких движений, а то можно так наворотить, что потом неделю откатываться.

Смотри, тут всё зависит от того, на каком этапе ты обосрался. Как будто слоёный пирог из ошибок, только невкусный.

Первый вариант — самый простой. Ты просто в файле что-то натыкал, но ещё даже не добавил это в индекс командой git add. То есть, по сути, ты ещё даже не начал серьёзно косячить. Чтобы всё стереть и вернуться к тому, что было в последнем коммите, делай так:

git restore <file>
# Или, если ты из старых, и эта команда у тебя в подкорке:
# git checkout -- <file>

Всё, и волнение ебать как рукой сняло. Файл станет чистым, как будто ты нихуя и не трогал.

Второй вариант — ты уже успел сделать git add. Вот тут уже интереснее. Ты как бы приготовил свои косяки к отправке, но ещё не отправил. Чтобы их оттуда выковырять:

# Сначала вытаскиваем файл из этого стейджа, но сами правки пока остаются в файле
git restore --staged <file>
# А если ты передумал и хочешь отменить вообще всё — дохуячим вторую команду:
git restore <file>

Понимаешь разницу? Сначала мы говорим «не, это говно не для коммита», а потом, если надо, зачищаем и сами правки.

Третий способ — для уже закоммиченного говна. Вот это уже серьёзно. Твои косяки попали в историю. Самый безопасный и правильный путь — не пытаться их вычеркнуть, а сделать новый коммит, который всё отменит. Это как сказать: «Извините, все, я был не прав, давайте вернём как было».

# Откатываем конкретный коммит по его хешу
git revert <commit-hash>
# Или, если надо откатить самый последний твой «подвиг»
git revert HEAD

Git создаст новый коммит с обратными изменениями. История останется целой, все будут видеть, что ты накосячил, но потом исправился. Честно и прозрачно, доверия ебать ноль, но зато безопасно для команды.

Четвёртый способ — для отчаянных. Это git reset. Ёпта, вот тут надо быть осторожным, как сапёр. Эта команда не создаёт новый коммит, а стирает историю. Если ты уже запушил свои изменения в общий репозиторий, и потом сделаешь reset — будет вам хиросима и нигерсраки, когда ты попробуешь запушить снова. Используй ТОЛЬКО если косяк локальный и ты его никуда не отправлял.

# «Удаляем» последний коммит, но все твои правки остаются в рабочей папке (как будто после git add)
git reset --soft HEAD~
# «Удаляем» коммит и убираем изменения из индекса (как будто до git add)
git reset HEAD~
# «Удаляем» коммит и ВООБЩЕ ВСЁ СТИРАЕМ. Безвозвратно. Нахуй.
git reset --hard HEAD~

Последний вариант, --hard, — это точка невозврата. После него изменения сгорят. Ты уверен? Ну, типа, совсем уверен? Ладно, твоё дело.

И, наконец, пятый — спасательный круг. Допустим, ты уже сделал reset --hard и охренел: «Бля, а там же была нужная фича!». Всё пропало? Не совсем. Git — хитрая жопа, он почти всё помнит какое-то время.

# Эта команда покажет тебе ЛОГ ВСЕХ ТВОИХ ДЕЙСТВИЙ. Где ты был, что делал, куда совался.
git reflog
# Найдёшь в этом списке хеш того состояния, до которого хочешь откатиться, и — бац!
git reset --hard <hash-from-reflog>

Это как машина времени. Главное — успеть, пока мусор не вычистили.

Вот и вся магия. Главное — понимать, на каком ты этапе, и не использовать тяжёлую артиллерию там, где можно просто аккуратно всё отменить. Удачи, не накосячь ещё больше!