#git #git-flow #revert
#git #git-flow #отменить
Вопрос:
Я новичок в git, не могу найти ответ в Интернете с моими условиями на этот вопрос, но, вероятно, его задавали.
Итак, допустим, моя ветка defaut develop
. Я создал ветку из вызываемой разработки feature/test
, выполнил несколько коммитов в этой ветке, а затем объединил ее develop
.
---1---2---3---4---M---5---6---7--- (develop)
/
A---B (feature/new)
После слияния M
я продолжаю свой проект в разработке с несколькими коммит.
Но теперь я хочу отключить ветку функций от всех коммитов, следующих за веткой, например, если ветка develop
никогда не сливалась feature/new
.
Так что это то, что мне нравится иметь :
---1---2---3---4---5'---6'---7'--- (develop)
A---B (feature/new)
Как вы можете видеть, все следующие коммиты M
изменены, чтобы отменить изменения, внесенные удаленным слиянием.
Возможно ли это сделать и какую команду мне следует использовать?
Спасибо
Ответ №1:
Есть несколько способов сделать это.
Чтобы получить историю, которую вы описываете на своем изображении, требуется, чтобы вы переписали историю. Вы должны знать, что если это репозиторий используется совместно с другими, и если история, которую вы хотите переписать, была передана (передана удаленно), то для правильного выполнения требуется определенная координация — потому что перезапись общей истории приводит к ошибочным условиям, которые при неправильном разрешении приведут к отмене вашей работы.
Тем не менее, чтобы избежать перезаписи истории, которую вы бы использовали git revert
(или эквивалент). Возврат слияния также требует затрат, и эти затраты применяются независимо от того, делились ли вы историей с другими.
Так что в целом лучше, если вы сможете избежать слияния ветвей, которые вам, возможно, придется «отменить» позже. Но, не имея возможности изменить прошлое, вам придется использовать все имеющиеся у вас варианты.
Чтобы решить, следует ли вам переписывать историю, я бы обратился к git rebase
документам (https://git-scm.com/docs/git-rebase ) в разделе «Восстановление после вышестоящей перебазировки». Вы также можете посмотреть git revert
документы, касающиеся слияний (https://git-scm.com/docs/git-revert ). Затем, в зависимости от того, что вы решите, вы можете выполнить одно из следующих действий:
История перезаписи
Итак: самый простой способ сделать то, что вы просили, это
git rebase --onto develop~4 develop~3 develop
Это берет коммиты, которые вы хотите сохранить, вычисляет для них исправления и применяет эти исправления к новому родительскому элементу; некоторые подробности:
Выражения develop~4
и develop~3
специфичны для вашего примера.
develop~4
ссылается на коммит, который вы находите, следуя указателям «первого родителя» четыре раза, начиная с коммита, на который указывает develop
. Это приводит к 4
. Указав это в качестве --onto
аргумента, вы сообщаете rebase
, что исправления, которые он вычисляет, должны применяться, начиная с этого.
Аналогично develop~3
приводит к M
, так что это «восходящий поток». Это означает, что ни M
один, ни какой-либо коммит, доступный из M
(по родительским указателям), не будут использоваться для создания исправлений. (Если вы не использовали --onto
upsteram, это также сыграло бы роль в применении исправлений; но здесь мы использовали --onto
so, это не имеет значения.)
При применении исправлений могут возникать конфликты. Это потому, что что-то в 5
, 6
, или 7
может редактировать строку, которая также была отредактирована M
(или строка, «достаточно близкая» к редактированию M
, что заставляет git сомневаться в наличии проблемы). Любой надежный метод выполнения того, что вы просите, приведет к тем же конфликтам, поэтому вам просто нужно выяснить, как «должно было» выглядеть изменение, если слияния никогда не происходило.
Если develop
она существует на удаленном компьютере и если M
она уже была отправлена на этот удаленный, то по умолчанию git будет сопротивляться отправке результата этого изменения (поскольку оно удаляется M
из истории ветвей). Вы можете переопределить это с --force-with-lease
помощью опции для push
команды. (Некоторые люди говорят, что нужно использовать эту -f
опцию, но, хотя ее проще вводить, она также менее безопасна. -f
не будет проверять, были ли отправлены новые коммиты, о которых вы не знаете develop
; --force-with-lease
будет.)
Без перезаписи истории
Если вы не можете (или не хотите) координировать перезапись истории, тогда вы должны признать, что любая история, которую вы нажали, неизменна. В этом случае вы можете отменить слияние.
git revert -m 1 develop~3
-m
Опция сообщает git, к какому из родительских элементов слияния вы «возвращаетесь»; таким образом, говоря -m 1
, вы эффективно отменяете изменения из ветки.
Так же, как и подход с перезаписью истории, это может привести к конфликту и потребовать разрешения конфликта вручную. Конечный результат будет
1 -- 2 -- 3 -- 4 -- M -- 5 -- 6 -- 7 -- !AB <--(develop)
/
A --- B <--(feature/new)
где !AB
отменяет изменения из A
и B
(которые были объединены в at M
).
Поскольку A
и B
все еще находятся в истории develop
, если вы позже захотите их повторно объединить, это не так просто. Вам придется либо отменить !AB
, либо использовать rebase -f
для перезаписи истории feature/new
перед mreging.