Небольшая статья, посвященная вопросу отката коммитов в GitHub.
В чем заключается вопрос, собственно? В том, что имеется определенный репозиторий, размещенный на сервере GitHub. У этого удаленного репозитория есть локальная синхронизированная версия на рабочей машине автора. Этот репозиторий изменяется с большей или меньшей периодичностью; все изменения фиксируются соответствующими коммитами.
И вот в один прекрасный момент в репозиторий было внесено изменение, которое затем было закоммичено и отправлено на GitHub. Однако, от этого изменения нужно избавиться - оно ошибочное.
Но как это сделать, если коммит уже находится на GitHub? В интерфейсе сервиса GitHub я не нашел нужной кнопки, чтобы удалять конкретный коммит и тем самым возвращать репозиторий до нужного состояния.
Это потому, что управление коммитами на GitHub производится через локальный репозиторий. Ниже приведу три несложных шага для того, чтобы показать, каким образом это выполняется.
Шаг первый
Первое - необходимо получить список hash-сумм последних коммитов репозитория. Это и понятно - нужно иметь перед собой дерево коммитов, чтобы видеть - куда двигаться. В дереве коммитов hash-суммы являются опорными точками, идентификационными номерами каждого из коммитов:
Ниже показан краткий вывод команды git log - четыре самых поздних коммита репозитория:
Мне нужно вернуть репозиторий из состояния, описанного в коммите ee3a2ae6888fb87d, в состояние, зафиксированное в коммите 6d92268e42eace0c.
Шаг второй
Для этого я воспользуюсь командой reset, с ключом –hard. Эта команда мне подходит потому, что я не собираюсь сохранять изменения, зафиксированные в коммите ee3a2ae6888fb87d, так как они полностью ошибочны.
Как подробно описывается в статье Отмена изменений в Git, такую задачу можно выполнить командой:
где 6d92268e42eace0c - начальные 16 символов hash-суммы коммита, на который я хочу “перепрыгнуть”. Полный вид hash-суммы в 40 символов можно не использовать - достаточно 16 символов для надежной идентификации конкретного коммита.
После выполнения этой команды локальный репозиторий будет сброшен к состоянию, зафиксированному в коммите 6d92268e42eace0c. Другими словами, я избавился от последних ошибочных изменений и вернул репозиторий в предыдущее его состояние.
Однако, это всего лишь половина дела, так как откат коснулся только локального репозитория. В этой статье речь идет прежде всего об удаленном репозитории, размещенном на GitHub. Как добиться внесения аналогичных изменений на GitHub?
Казалось бы - просто! Достаточно выполнить команду:
Но, на самом деле это не получится сделать - Git не позволит это выполнить. По той причине, что на данный момент состояние локального репозитория имеет более раннюю версию, нежели состояние удаленного репозитория.
Вместо этого Git предложит выполнить комнаду git pull, чтобы привести локальный репозиторий к удаленному.
Шаг третий
Чтобы заставить Git выполнить обратную задачу - привести удаленный репозиторий к локальному, необходимо использовать ключ -f.
То есть, форсировать внесение изменений и тем самым “сказать” Git - синхронизировать удаленный репозиторий с локальным репозиторием несмотря на то, что последний имеет более ранюю версию:
Заключение
Теперь, если проверить состояние удаленного репозитория на сервере GitHub, то увидим, что оно идентично состоянию локального репозитория. Но самое главное - удален последний ошибочный коммит, чего я и добивался.
На этом все.