Как удалить коммиты из origin/master
Реальный случай. Один разработчик трижды слил ветку task5 c задачей в мастер и отправил изменения в репозиторий в origin/master. Спустя 3 дня другой разработчик начинает готовить релиз, находит эту ветку в мастере и понимает, что с этой веткой task5 в мастере выкатываться нельзя. Эти коммиты нужно убрать, а ветку task5 вернуть на доработку.
Навали git push -f
Все осложняется тем, что task5 лежит в мастере уже 3 дня и другие разработчики могли обновить свои локальные мастера
и получить этот злополучный task5 в свой мастер и свои новосозданные ветки, ответвленные от мастера.
Это значит, что если просто удалить коммиты и перезаписать историю через git push -f
, то любой разработчик,
кто уже подсосал изменения вновь их запушит на сервер, сам того не подозревая.
Давай git revert
Плюс как я уже писал выше, есть merge-коммиты, которые также нужно отменить. А merge-коммиты, как известно
имеют двух родителей, и такой коммит нельзя просто отменить командой git revert
, как обычный коммит.
Нужно явно указывать, какого именно родителя мы хотим отменить:
И тонкость здесь в том, что если при сливании ветки разработчик разрешал некоторые конфликты, то для того, чтобы отменить merge, эти конфликты нужно разрешать в обратном порядке. В итоге, спустя несколько часов, мне так и не удалось в помощью git revert вернуть ветку в нужное состояние, все время были какие-то отличия.
Решение
В итоге было найдено решение с cherry-pick. Сперва мы все же перезаписываем мастер:
После этого все ветки всех разработчиков, которые содержат коммиты task5 нужно пересоздать. Каждый разработчик обновляет перезаписанный мастер: git fetch
Находит список коммитов в своей ветке:
После этого находим те коммиты, которые сделал разработчик в текущей ветке (первые три коммита в нашей ситуации будут из ветки task5), и переносим их в отдельную ветку.
Дополнительно
Получить список веток, которые нужно обновить (нужен список хешей коммитов, от которых избавляемся):
Список коммитов в текущей ветке через пробел:
К недостаткам данного метода можно отнести то, что это должен делать каждый разработчик со всеми своими ветками. Если кто-то этого не сделает, или пропустит ветку, то позже благополучно запушит изменения в мастер.
Скорее всего нечто подобное можно реализовать и через git revert
и через git rebase
, но кунг-фу автора
не хватило, чтобы осилить эти способы. git cherry-pick
был последним вариантом, который мы пробовали, и который почти
сразу у нас получился.