Skip to main content

Різниця між 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 зламає гілки твоїх колег

Швидкий приклад

bash
# Початкова історія: 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 resetgit revert
Переписує історіюТакНі
Безпечний для запушених комітівНіТак
Створює новий комітНіТак
Видаляє комітиТакНі
Змінює вказівник гілкиТакНі
Коли використовуватиЛокальна робота до pushСпільні гілки, продакшн

Як це працює всередині

reset оновлює HEAD і вказівник гілки на попередній коміт. З --hard також переписуються робоча директорія і staging area. revert робить інакше: читає diff цільового коміту, інвертує кожну зміну і зберігає результат як новий коміт. Жодна частина існуючої історії не змінюється.

Типові помилки

Reset на запушеній гілці

bash
# НЕПРАВИЛЬНО git reset --hard HEAD~1 git push -f origin main # Колеги тепер мають коміти яких немає на remote # Їхній push буде відхилено; merge поверне "видалений" коміт # ПРАВИЛЬНО git revert HEAD git push origin main

Плутанина між режимами reset

bash
# --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

bash
# НЕПРАВИЛЬНО: в історії 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

bash
# Ти виконав: 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} # Повернувся до стану до reset

Reflog зберігається тільки локально і за замовчуванням живе 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. Швидкість важлива, але не ціною чужої роботи.

Приклади

Безпечне скасування запушеного коміту

bash
# Баг потрапив на спільну гілку в коміті 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

bash
# Ти виконав це помилково 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

bash
# Чотири брудних коміти локально, жоден не запушений # 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 # Ревьюери бачать одну логічну одиницю роботи

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?