Повторное выполнение слияния в Git

231

Здесь я столкнулся с небольшой проблемой: 28sв Git была ветвь для конкретной проблемы , которую я слил в общую developветку. Оказывается, я сделал это слишком быстро, поэтому я использовал git-revert, чтобы отменить слияние. Теперь, однако, пришло время , чтобы объединить 28sв develop, но команда ГИТ-слияние видит оригинальное слияние, и с радостью объявляет , что все хорошо и ветви были уже объединены. Что мне теперь делать? Создать 'Revert' Revert '28s -> Develop' '' коммит? Кажется, это не очень хороший способ сделать это, но я не могу представить другого в данный момент.

Как выглядит древовидная структура:

Вывод журнала Git

Томс Микосс
источник
4
Это GitX ( gitx.frim.nl ).
Томс Микосс

Ответы:

169

Вы должны «вернуть вспять». В зависимости от того, как вы вернули оригинал, это может быть не так просто, как кажется. Посмотрите на официальный документ по этой теме .

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

позволять:

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

Но все ли это работает? Конечно, это так. Вы можете отменить слияние, и с чисто технической точки зрения, git сделал это очень естественно и не имел никаких особых проблем.
Он просто посчитал это переходом от «состояния до слияния» к «состоянию после слияния», и на этом все.
Ничего сложного, ничего странного, ничего особо опасного. Git сделает это, даже не думая об этом.

Так что с технической точки зрения нет ничего плохого в обратном слиянии, но с точки зрения рабочего процесса это то, чего вы обычно должны избегать .

Если это вообще возможно, например, если вы столкнулись с проблемой , что получил слиты в основное дерево, а не Возвратить слияния, попробуйте действительно трудно :

  • разделите проблему на ветви, которую вы объединили, и просто исправьте ее,
  • или попытаться отменить отдельный коммит, который его вызвал.

Да, это сложнее, и нет, это не всегда будет работать (иногда ответ: «Ой, я действительно не должен объединить его, потому что он еще не был готов, и мне действительно нужно отменить все из слияние "). Так что тогда вам действительно следует отменить слияние, но если вы хотите повторить слияние, теперь вам нужно сделать это, отменив откат.

J-16 SDiZ
источник
10
Хорошая ссылка (+1). Я позволил себе скопировать часть документа в вашем ответе, чтобы позволить читателям сразу увидеть соответствующие варианты в этом случае. Если вы не согласны, не стесняйтесь отменить.
VonC
5
Мы просто натолкнулись на случай, когда нам нужно было это сделать, и обнаружили, что веселье на этом не заканчивается. Это была длинная ветвь, которая была объединена, поэтому нам нужно было продолжать ее обновлять. Мой подход здесь: tech.patientslikeme.com/2010/09/29/…
jdwyah
я следил за сообщением в блоге @ jdwyah, и это было великолепно (серьезно, это было потрясающе, что это просто сработало).
Hellatan
2
@jdwyah, кажется, неработающая ссылка, но звучит как интересное чтение. Вот зеркало archive.org, но на нем отсутствуют изображения: web.archive.org/web/20111229193713/http://…
Alex KeySmith
15
Сообщение в блоге было воскрешено, спасибо: blog.jdwyah.com/2015/07/dealing-with-git-merge-revisions.html
jdwyah
53

Давайте предположим, что у вас есть такая история

---o---o---o---M---W---x-------x-------*
              /                      
      ---A---B

Где A, B не удалось зафиксировать, а W - вернуть M

Поэтому, прежде чем я начну исправлять найденные проблемы, я делаю вишневый выбор W коммит в мою ветку

git cherry-pick -x W

Затем я возвращаю W коммит на мою ветку

git revert W 

После я могу продолжить исправление.

Финальная история может выглядеть так:

---o---o---o---M---W---x-------x-------*
              /                       /     
      ---A---B---W---W`----------C---D

Когда я отправляю пиар, он ясно показывает, что пиар отменяется, и добавляет новые коммиты.

Максим Котляр
источник
3
Похоже, что это может быть полезно, но настолько скудно по деталям (что такое C, D на последней диаграмме), что это скорее разочаровывает, чем полезно
Isochronous
4
@ Изохронные C и D, по-видимому, являются коммитами, которые решают проблемы, представленные A и B.
Томас
@Томас точно
Максим Котляр
Хорошо, что вы подчеркнули использование PR в этом случае, поскольку он может обеспечить окончательную «проверку работоспособности» перед слиянием с мастером.
Виллем ван
использовать почему вы перезапускаете свою ветку с оригинального W? То есть, пусть ваша тема продолжается с W, с W`, за которым следуют C и D? Это устраняет некоторые дубликаты
Эрик Карстенсен
12

Чтобы отменить возврат, не слишком усложняя рабочий процесс:

  • Создать локальную копию корзины
  • Отменить возврат коммита на локальной копии разработки
  • Объедините эту копию с вашей веткой функций и отправьте свою ветку функций на ваш git-сервер.

Теперь ваша ветвь функций должна быть в состоянии объединяться как обычно, когда вы к этому готовы. Единственным недостатком здесь является то, что у вас будет несколько дополнительных коммитов / слияний в вашей истории.

Сэм Дюфель
источник
Просто, чтобы предотвратить дальнейшие перепутывания, я также создал «мусорную» копию своей функциональной ветви и объединил в нее возвращенную разработку.
19
Спасибо! Это единственный ответ, который фактически объясняет, как это сделать, вместо того, чтобы говорить, что вы не должны этого делать. Действительно полезно.
Эмми
Спасибо, это действительно помогло мне. :)
Даниэль Стракабошко
11

Чтобы отменить возврат в GIT:

git revert <commit-hash-of-previous-revert>
Ричард
источник
1
Используя это в моей рабочей ветке, чтобы отменить возврат, затем создать новый PR. Теперь git видит все изменения, которые были в предыдущем PR, который был отменен. Спасибо.
Данстан
3

Вместо использования git-revertвы могли бы использовать эту команду в develветке, чтобы отбросить (отменить) неправильный коммит слияния (вместо того, чтобы просто вернуть его).

git checkout devel
git reset --hard COMMIT_BEFORE_WRONG_MERGE

Это также изменит содержание рабочего каталога соответствующим образом. Будьте осторожны :

  • Сохраните ваши изменения в ветке разработки (так как неправильное слияние), потому что они тоже будут удалены git-reset. Все коммиты после того, который вы указали в качестве git resetаргумента, пропадут!
  • Кроме того, не делайте этого, если ваши изменения уже были извлечены из других репозиториев, потому что сброс перезапишет историю.

Я рекомендую git-resetвнимательно изучить страницу руководства, прежде чем пытаться это сделать.

Теперь, после сброса, вы можете повторно применить ваши изменения develи затем сделать

git checkout devel
git merge 28s

Это будет реальным слияние с 28sв develкак исходной (который теперь стертого из истории Git и ).

knweiss
источник
8
Для тех, кто не очень хорошо знаком с git и может захотеть следовать этим инструкциям: осторожно с комбинированием reset --hardи push origin. Также имейте в виду, что принудительный толчок к источнику может действительно испортить открытые PR на GitHub.
funroll
Очень полезно для исправления некоторых проблем слияния на частном git-сервере. Спасибо!
mix3d
1
+1 за эту технику. Потенциально разрушительный, но может сэкономить много головной боли (и изуродованной истории) при разумном применении.
silicrockstar
1

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

Вместо этого я проверил коммит, к которому я хотел вернуться, например, ветвь git checkout 123466t7632723. Затем преобразуется в филиал git checkout my-new-branch. Затем я удалил ветку, которую больше не хотел. Конечно, это будет работать только в том случае, если вы сможете отбросить испорченную ветку.

Claire
источник
1
Он git reflogзащитит вас при полной перезагрузке на пару месяцев на случай, если позже вы обнаружите, что вам нужны потерянные коммиты. Рефлог ограничен вашим локальным репо.
Тодд
1

Я бы предложил вам выполнить следующие шаги, чтобы отменить возврат, скажем, SHA1.

git checkout develop #go to develop branch
git pull             #get the latest from remote/develop branch
git branch users/yourname/revertOfSHA1 #having HEAD referring to develop
git checkout users/yourname/revertOfSHA1 #checkout the newly created branch
git log --oneline --graph --decorate #find the SHA of the revert in the history, say SHA1
git revert SHA1
git push --set-upstream origin users/yourname/revertOfSHA1 #push the changes to remote

Теперь создайте пиар для филиала users/yourname/revertOfSHA1

Венкатараман Р
источник
1
  1. создайте новую ветвь при коммите до первоначального слияния - назовите его 'Develop-Base'
  2. выполнить интерактивную перебазировку 'Develop' поверх 'Develop-Base' (даже если она уже на вершине). Во время интерактивного перебазирования у вас будет возможность удалить как коммит слияния, так и коммит, который отменил слияние, т.е. удалить оба события из истории git

На этом этапе у вас будет чистая ветвь «разработки», в которую вы можете объединить свой набор функций, как вы это делаете регулярно.

Миша Мостов
источник
Этот подход создаст проблему, если ветка разработки будет доступна другим.
PSR