Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Різниця між git reset та git revert?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**git reset** видаляє коміти з історії, переміщуючи вказівник гілки назад. **git revert** зберігає історію, додаючи новий коміт що скасовує зміни. Reset для локальної роботи до push; revert для спільних гілок. ```bash git reset --hard HEAD~1 # останній коміт зник git revert HEAD # новий коміт скасовує попередній ``` **Головне правило:** ніколи не роби reset на тому що колеги вже запулили.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**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 reset | git 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 # Ревьюери бачать одну логічну одиницю роботи ```Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.