Різниця між git reset та git revert?
git reset і git revert - два способи скасувати коміти в Git. Reset видаляє коміти з історії. Revert додає новий коміт що їх скасовує.
Теорія
TL;DR
resetпереміщує вказівник гілки назад, стираючи коміти з історіїrevertдодає новий коміт з оберненими змінами, зберігаючи всю історію- Аналогія: reset - це Ctrl-Z для твоєї git-історії; revert - це написати "беру свої слова назад" в новому повідомленні
- Правило: reset для локальної роботи до push; revert для всього що вже на спільній гілці
- Force-push після reset зламає гілки твоїх колег
Швидкий приклад
# Початкова історія: A -> B -> C
# Хочеш скасувати коміт C
# reset: C зникає з історії
git reset --hard HEAD~1
# Історія: A -> B
# revert: C залишається, новий коміт D скасовує зміни C
git revert HEAD
# Історія: A -> B -> C -> D (D має обернені зміни відносно C)Дві команди, два абсолютно різних результати. Перша - машина часу. Друга - документальний слід.
Головна різниця
reset змінює куди вказує твоя гілка. З --hard він також переписує робочу директорію і staging area під той старий коміт, стираючи все що між ними. revert читає цільовий коміт, обчислює обернені зміни і зберігає їх як новий коміт. Попередня історія залишається незмінною.
Коли що використовувати
- Локальні коміти до push:
resetщоб почистити, об'єднати або переорганізувати - Коміти вже запушені на спільну гілку:
revert, завжди - Відкат на продакшені з CI/CD:
revert, щоб журнал змін залишався читабельним - Хочеш об'єднати останні 3 локальні коміти в один:
git reset --soft HEAD~3, потім один коміт
Три режими reset:
--softзберігає зміни в staging area (готові до коміту)--mixedпереміщує зміни до робочої директорії, але не стейджить (поведінка за замовчуванням)--hardповністю видаляє зміни
Таблиця порівняння
| Аспект | git reset | git revert |
|---|---|---|
| Переписує історію | Так | Ні |
| Безпечний для запушених комітів | Ні | Так |
| Створює новий коміт | Ні | Так |
| Видаляє коміти | Так | Ні |
| Змінює вказівник гілки | Так | Ні |
| Коли використовувати | Локальна робота до push | Спільні гілки, продакшн |
Як це працює всередині
reset оновлює HEAD і вказівник гілки на попередній коміт. З --hard також переписуються робоча директорія і staging area. revert робить інакше: читає diff цільового коміту, інвертує кожну зміну і зберігає результат як новий коміт. Жодна частина існуючої історії не змінюється.
Типові помилки
Reset на запушеній гілці
# НЕПРАВИЛЬНО
git reset --hard HEAD~1
git push -f origin main
# Колеги тепер мають коміти яких немає на remote
# Їхній push буде відхилено; merge поверне "видалений" коміт
# ПРАВИЛЬНО
git revert HEAD
git push origin mainПлутанина між режимами reset
# --soft: зміни залишаються в staging area
git reset --soft HEAD~1
# git status → "Changes to be committed"
# --mixed (за замовчуванням): зміни в робочій директорії, не застейджені
git reset HEAD~1
# git status → "Changes not staged for commit"
# --hard: зміни видалено
git reset --hard HEAD~1
# git status → чистоНеправильний діапазон у revert
# НЕПРАВИЛЬНО: в історії A -> B -> C, хочемо скасувати B і C
git revert B..C
# Скасовує тільки C (початок діапазону виключається)
# ПРАВИЛЬНО
git revert B^..C
# Або окремо: спочатку git revert C, потім git revert BДумати що reset --soft завжди безпечний
Якщо ти зробив reset --soft і потім випадково запустив reset --hard до коміту, зміни зникнуть. Їх немає в жодному коміті. Staging area це не резервна копія.
Відновлення після випадкового hard reset
# Ти виконав: git reset --hard HEAD~5
# І зрозумів що ці коміти потрібні
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~5
# def5678 HEAD@{1}: commit: feature: add auth
git reset --hard HEAD@{1}
# Повернувся до стану до resetReflog зберігається тільки локально і за замовчуванням живе 90 днів.
Де зустрічається на практиці
- Feature-гілки:
resetперед фінальним push щоб прибрати WIP-коміти - main/master: тільки
revert, ніколиreset - GitHub UI: кнопка "Revert" на змерженому PR створює новий PR з revert-комітом
- CI/CD пайплайни: автоматичні відкати через
revertщоб зберегти читабельну deploy-історію - Дебагінг:
resetлокально для перегляду старих комітів;revertдля фіксу в продакшені
Питання на співбесіді
Q: Що станеться якщо зробити reset на коміті який колеги вже запулили?
A: Їхня локальна гілка матиме коміти яких немає на remote. Git відхилить їхній push. Якщо вони зроблять merge, видалений коміт повернеться. Якщо reset, вони втратять власну роботу.
Q: Чи можна зробити revert від revert?
A: Так. git revert D створює коміт E що скасовує D, повертаючи зміни які D видалив. Корисно якщо помилково зревертив щось потрібне.
Q: В чому різниця між git reset HEAD~1 і git reset --mixed HEAD~1?
A: Жодної. --mixed це поведінка за замовчуванням. Обидві команди скасовують коміт і залишають зміни незастейдженими в робочій директорії.
Q: Я втратив коміти після reset --hard. Можна їх повернути?
A: Зазвичай так. git reflog покаже хеш потрібного коміту, після чого git reset --hard <hash> поверне тебе туди. Працює доки не запущено garbage collection і не минуло 90 днів.
Q: Навіщо reset --soft якщо є git commit --amend?
A: --amend змінює тільки останній коміт. git reset --soft HEAD~3 об'єднує останні 3 коміти в один. Стейджиш усе і комітиш раз. Зручно щоб прибрати WIP-коміти перед push.
Q: (Senior) Ти на main, щойно змержився коміт що ламає продакшн. 30 секунд. Reset чи revert?
A: Revert. Reset переписав би історію main і зламав локальні гілки всіх в команді плюс CI/CD що вже підхопив коміт. Revert створює новий коміт що прибирає проблему і можна пушити без force. Швидкість важлива, але не ціною чужої роботи.
Приклади
Безпечне скасування запушеного коміту
# Баг потрапив на спільну гілку в коміті abc123
# Reset тут вимагав би force-push і зламав би колег
git revert abc123
# Git відкриє редактор для commit message
# Прийми дефолтне повідомлення або напиши своє
# Результат: новий коміт def456 що скасовує зміни abc123
git push origin feature/auth
# Колеги пулять і автоматично отримують виправлення
# Історія показує що сталося і коли:
# ... -> abc123 (баг) -> def456 (reverts abc123) -> ...Без force-push. Без зламаної історії. По коміту видно де був баг і коли його виправили.
Відновлення комітів після reset --hard
# Ти виконав це помилково
git reset --hard HEAD~5
# П'ять комітів зникли з історії
# Reflog відстежує кожен рух HEAD
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~5
# def5678 HEAD@{1}: commit: feature: add auth
# ghi9012 HEAD@{2}: commit: fix: validation bug
# Відновлення
git reset --hard HEAD@{1}
# Повернувся. Всі 5 комітів знову на місці.
# Важливо: reflog тільки локальний, зберігається 90 днів за замовчуваннямReflog це одна з тих речей яку починаєш цінувати після першого випадкового hard reset на щось важливе.
Очищення локальних комітів перед push
# Чотири брудних коміти локально, жоден не запушений
# git log показує:
# abc001 (HEAD) fix typo again
# abc000 fix typo
# ab9999 wip: auth maybe working
# ab9998 start auth feature
# Об'єднуємо в один чистий коміт
git reset --soft HEAD~4
# Всі зміни тепер в staging area, без зайвих комітів
git commit -m "feat: add authentication"
# Один чистий коміт в історії
git push origin feature/auth
# Ревьюери бачать одну логічну одиницю роботиКоротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.