Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Не только разработчикам-новичкам, но и ярым профессионалам приходится прибегать к отмене каких-либо изменений. И тогда, первое, что приходит на ум, — это команда git revert
, как самый безопасный способ. И тут есть подводные камни, про которые я хочу рассказать.
Возьмем простую ситуацию: разработчик решает реализовать математические функции. Но на половине пути понимает, что данную задачу было бы хорошо декомпозировать, допустим, на две подзадачи:
- Реализовать арифметические операции (сложение, вычитание, деление и т.д.)
- Реализовать числовые операции (максимальное значение, минимальное значение, модуль числа и т.д.)
Проверять будет проще да и тестировать. Но он уже начал ее реализовывать, коммиты уже созданы, и что же делать? Не переписывать же!
Рассмотрим дерево коммитов. Видим, что наш разработчик создал ветку functions
, класс Arithmetic, отвечающий за реализацию арифметических операций (коммит А), и класс Numerical, отвечающий за реализацию числовых операций (коммит N). Итого два класса и два коммита.
git revert
Решено, дабы ничего не переписывать, наследоваться от functions
и создать две ветки numerical
и arithmetic
. И соответственно отменить ненужные коммиты. То есть выполнить git revert N
в ветке arithmetic и git revert A
в ветке numerical. Гениально и просто!
Работа кипит и осталось дело за малым — смерджить мастер с данными ветками.
И что же мы получили? Ни класса Arithmetic, ни класса Numerical!
А все дело в том, что команда git revert
создает новый коммит с отменой изменений и не удаляет из истории коммиты. И в нашем случае после слияния веток получается 4 коммита:
A ⟶ N ⟶ revert A ⟶ revert N
То есть вариант с отменой изменений с помощью команды revert
вышел нам боком.
git reset
И тут мы вспоминаем, что есть такая команда как reset
, вот она в отличии от revert
точно удаляет коммиты из истории. Но есть одно НО… она сбрасывает все коммиты до указанного. Такое поведение нам не подходит, так как мы хотим выбрать какие коммиты удалить.
git rebase
Есть еще одно решение — использовать команду git rebase
для отмены изменений.
Вернемся к моменту создания двух веток numerical
и arithmetic
и выполним
git rebase -i –root
Теперь на уровне каждого коммита, который мы хотим отменить заменим pick на drop. И тогда выбранные нами коммиты сбросятся из истории. Например в ветке numerical
:
Тогда в истории у нас останутся только нужные нам коммиты.
Теперь при слиянии веток в master
получим оба класса.
Данный метод рабочий, только при условии работы в частной ветке, но если эти манипуляции провести в общей ветке, то при публикации (git push
) git
сообщает, что ветка устарела, так как в ней отсутствуют коммиты и отменяет публикацию.
Чтобы не бороться с git, старайтесь декомпозировать задачи заранее, а то можете словить сюрприз. Сталкивались ли вы с такими ситуациям, и если да, то как выходили из них?