Удалить объединенную функцию и отключить эту функцию во всех последующих коммит

#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.