Страницы

Поиск по вопросам

четверг, 19 декабря 2019 г.

git: как “нейтрализовать” коммит?

#git #git_commit


Есть бажный коммит, после него еще несколько коммитов, которые пока нельзя деплоить.
Необходимо как-то выкинуть изменения этого коммита из проекта, затем развернуться из
следующего перед ним коммита, а потом продолжить работу с последнего коммита, но исключая
изменения бажного. Дайте, пожалуйста, последовательность действий.
    


Ответы

Ответ 1



затем развернуться из следующего перед ним коммита Подробная информация в вопросе Как вернуться (откатиться) к более раннему коммиту?. Кратко - когда всё почините, сможете просто перейти в нужный коммит или даже новую ветку создать в нём. выкинуть изменения этого коммита из проекта, Про это будет весь ответ дальше. Самый важный вопрос: Успели ли вы запушить эту ветку на удалённый репозиторий? Возможно ли, что другой разработчик уже получил с удаленного репозитория коммит B или один из последующих и продолжает работать над ним. Если ответ - да, то в общем случае желательно revert, но не rebase, cherry-pick и прочее, что переписывает историю Git, так как это создает большие проблемы с интеграцией. Поскольку вам нужно развернуться из C, не содержащего изменений из B, то почти наверняка историю переписывать придётся. В таком случае предупредите коллег заранее. Им придётся аналогичным образом ребейзить свои изменения, например с коммита D на D'. Обозначим начальную ситуацию на следующей схеме: A - B - C - D ↑ branchname (HEAD) A, B, C, D — коммиты в ветке branchname. B - "плохой коммит", его нам нужно удалить. Коммит C нужно задеплоить. (HEAD) — местоположение указателя HEAD. ↑ обозначает коммит, на который указывает определенная ветка или указатель. Вариант 1 - через rebase -i Плюс - меньше мусора в истории. И можно гордиться, что освоил rebase. Плюс - позволяет развернуться из С, не содержащего изменений из B. Минус - переписывает историю, опасно при командной работе. Команды: git checkout branchname git rebase -i A git checkout -b deployme C' В качестве A мы указываем коммит сразу перед тем, который будем исключать. При этом A останется на месте. Откроется редактор, в нём будут коммиты в обратном порядке. Меняем pick на drop, обозначая что мы хотим выкинуть этот коммит. drop 323d4e6 comment for B pick 31da2b9 comment for C pick 24d420c comment for D # Rebase c8893f9..24d420c onto c8893f9 (3 command(s)) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit Результат A - C' - D' ↑ branchname (HEAD) ↑ deployme (HEAD) У новых коммитов теперь другой предок, поэтому это - другие, новые коммиты (хотя содержимое то же за вычетом B). Новая ветка deployme смотрит на коммит C'. Вариант 2 - через revert Плюс - не переписывает историю и безопасен при командной работе. Проще чем rebase. Минус - ошибочный коммит останется в истории. Плохо, если там информация, которую нельзя показывать или код, который стыдно публиковать. :) Минус - коммит C по-прежнему будет содержать изменения от B. Команды: git checkout branchname git revert B Результат: A - B - C - D - xB ↑ branchname (HEAD) Новый коммит xB содержит изменения, которые отменяют изменения коммита B. Однако у нас есть проблема: коммит C по-прежнему содержит изменения от B. Немного подробнее о revert: Документация тут, пятый пункт. В дополнение: Если в процессе ошибётесь или протеряете не тот коммит: Как отменить откат изменений (восстановить потерянный коммит)? Заодно, при желании, можно что-нибудь сделать и с другими коммитами: Как разделить/склеить старый комит?.

Ответ 2



Создать ветку из нужного вам коммита и продолжить работу в этой ветке. git checkout -b <имя ветки> <номер коммита> Затем замержить в эту ветку нужные вам коммиты. git cherry-pick <номер коммита>

Ответ 3



Коммит, удаляющий изменения, сохраненные нежелательным коммитом git revert HEAD Удаление коммита из ветки git reset --hard

Ответ 4



git revert - создаёт откатывающий коммит, см. https://git-scm.com/docs/git-revert git cherry-pick - позволяет в другом бранче создать Новый коммит с изменениями указанного коммита https://git-scm.com/docs/git-cherry-pick Теоретически этого сочетания должно быть достаточно

Комментариев нет:

Отправить комментарий