Избегайте эффектов отката фиксации в другой ветке Git при слиянии

Работа с git flow. У нас есть коллега, который не знаком с Git, который вчера случайно слил разработку в master.

В Develop есть довольно много функций, которые запускаются в нашем следующем выпуске и требуют отмены слияния. Это создало фиксацию, которая отменяет все изменения. Когда мы объединяем master обратно в разработку, откатная фиксация удаляет код, сгенерированный нашими функциями.

Как лучше всего синхронизировать разработку с исправлениями мастера, сохраняя при этом новые функции?

- Изменить - Чтобы уточнить, откат был откатом. I.E. git revert -m 1 <sha>, поскольку фиксация уже была отправлена ​​в удаленный репозиторий.

После публикации этого сообщения я придумал возможное исправление, создав ветвление мастера и вернув откат, однако мне любопытно, есть ли другие возможности, которые могут минимизировать столкновение.


person DivinusVox    schedule 24.07.2013    source источник
comment
Пожалуйста, добавьте подробности о как откат был выполнен (особенно о конкретных используемых командах). Разве принудительный сброс master в предыдущее состояние (вместо возврата) не возможен?   -  person    schedule 25.07.2013
comment
Кроме того, случайное объединение ветки X с веткой Y не должно было стать проблемой, если ваш коллега не смог отправить объединенные результаты в ваше каноническое репо. Пожалуйста, объясните, все ли ваши разработчики используют одно и то же репо или все вы используете свои собственные частные форки. Вы используете запросы на вытягивание через GitHub?   -  person    schedule 25.07.2013
comment
Это не Github, это Gitlab, использующий структуру Git Flow со стандартными рекомендациями по ветвям.   -  person DivinusVox    schedule 25.07.2013
comment
Точная команда была git revert -m 1 ‹sha› для принудительного отката, поскольку фиксация была отправлена ​​в глобальный репозиторий.   -  person DivinusVox    schedule 25.07.2013
comment
Что, если вы сбросите master в состояние до слияния и принудительно нажмете? Это требует, чтобы все снова синхронизировались, но он сохраняет вашу историю   -  person CharlesB    schedule 25.07.2013
comment
возможный дубликат Повторное выполнение отмененного слияния в Git   -  person John Szakmeister    schedule 25.07.2013
comment
Возможно, связано: Отмена фиксации слияния git, а затем отмена возврата.   -  person    schedule 29.04.2014


Ответы (2)


Вариант 1. Аппаратный сброс и принудительное нажатие

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

# On master branch, do a hard reset back to the commit before the merge
git reset --hard <commit of master before the merge>

# Force push to upstream ONLY IF IT'S OK WITH OTHER DEVELOPERS
git push <remote> master --force

Возможный недостаток выполнения аппаратного сброса и принудительного нажатия заключается в том, что, если другие разработчики уже основывали работу на фиксации слияния (т.е. сделали коммиты поверх нее), то им нужно будет повторить ту же самую работу поверх. сбросной головки master. Это может быть, а может и не оказаться для них сложной / дорогостоящей задачей.

Вариант 2. Отменить возврат

Я проверил это с помощью быстрого тестового репо. Я должен подчеркнуть, что это может сработать, я не уверен на 100%, что нет случаев, которые я бы не рассматривал. Поэтому не забудьте сначала протестировать его локально с помощью резервного клона вашего репо. Если вы решите использовать это в своем реальном репо, сделайте это на свой страх и риск.

Кроме того, это может быть не самое легкое / простое решение. Однако его преимущество перед опцией полного сброса состоит в том, что он не заставляет разработчиков повторять работу поверх ветки сброса master.

Хорошо, разобравшись со всем этим, вы можете попробовать объединить master в develop, затем отменить возврат слияния с develop в master, а затем слить develop с master, когда будете готовы. В командах:

# Coworker accidentally merges develop into master before it's ready
git merge --no-ff develop

# You revert the merge in the master branch (this creates commit "ABCDEFG"
git revert -m 1 <sha of merge commit>

# You want to merge fixes from master into develop
git checkout develop
git merge --no-ff master

# But now all that work in develop is reverted, so revert the revert "ABCDEFG"
git revert ABCDEFG

# When you're ready to merge develop into master...
git checkout master
git merge --no-ff develop

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

mkdir practice
cd practice/
git init

touch readme.txt
git add practice.txt
git commit -m "Add practice.txt"

git checkout -b develop

touch feature1.txt
git add feature1.txt
git commit -m "Add feature 1"

touch feature2.txt
git add feature2.txt
git commit -m "Add feature 2"

git checkout master

touch hotfix1.txt
git add hotfix1.txt
git commit -m "Fix issue 1"

git merge --no-ff develop

# Creates commit "ABCDEFG" that reverts the merge
git revert -m 1 head
git checkout develop
git merge --no-ff master
git revert ABCDEFG
git checkout master
git merge --no-ff develop

Вы можете узнать больше о технике «Отмена возврата» на странице официальная документация Git ядра Linux для git revert:

-m parent-number

--mainline parent-number

Обычно вы не можете отменить слияние, потому что не знаете, какую сторону слияния следует считать основной. Эта опция указывает родительский номер (начиная с 1) основной линии и позволяет откатить, чтобы отменить изменение относительно указанного родителя.

Отмена фиксации слияния означает, что вам никогда не понадобятся изменения дерева, внесенные слиянием. В результате более поздние слияния внесут только изменения в дерево, внесенные коммитами, которые не являются предками ранее отмененного слияния. Это может быть то, что вы хотите, а может и не быть.

См. revert-a-faulty -merge How-To для получения более подробной информации.

Ссылка на Как отменить Неправильное слияние настоятельно рекомендуется, если вы полностью хотите понять, как работает этот метод, это несложно для понимания и на самом деле довольно интересно и увлекательно.

person Community    schedule 25.07.2013
comment
Да, это правильно, можно отменить возврат. Исходный откат удаляет содержимое, но сохраняет историю; перед повторным слиянием из той же ветки вы повторно вводите содержимое истории, отменяя возврат. - person ben_h; 25.07.2013
comment
Спасибо! Это сэкономило мне много времени - person Dmitry Nichiporenko; 03.09.2019

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

Вот как я это исправляю, предполагая, что дочерняя ветка («разработка») была обновлена ​​(фиксация M1) до «плохого» слияния (фиксация M2) с мастером:

Состояние проблемы

           ... <-- Work after revert that needs merged to develop
            |
            R  <-- Revert Bad Merge
            |
            A  <-- Commits after merge,
            |    /   but before revert 
           ... </    and needs merged to develop
            |
           M2  <-"bad" merge
  ... ____/ |
   | /      |
   M1       |
   | \____  |
  ...     \...
develop   master 

Шаг 1

# Get latest from both parent and child branches locally

git checkout master
git pull
git checkout develop
git pull


# Merge all code from before revert in master branch to develop
# (not necessary if "bad" merge into master was immediately reverted)

git merge A

Состояние после шага 1:

           ... <-- Work after revert that needs merged to develop
   M3       |
   | \____  R  <-- Revert Bad Merge
   |      \ |
   |        A  <-- Commits after merge,
   |        |    /   but before revert
   |       ... </    and needs merged to develop
   |        |
   |       M2  <-"bad" merge
  ... ____/ |
   | /      |
   M1       |
   | \____  |
  ...     \...
develop   master 

Шаг 2 - ВАЖНАЯ ЧАСТЬ!

# Use "ours" strategy to merge revert commit to develop.
# This doesn't change any files in develop. 
# It simplly tells git that we've already accounted for that change.

git merge R -s ours

Состояние после шага 2

   M4
   | \____  ... <-- Work after revert that needs merged to develop
   M3     \ |
   | \____  R  <-- Revert Bad Merge
   |      \ |
   |        A  <-- Commits after merge,
   |        |    /   but before revert
   |       ... </    and needs merged to develop
   |        |
   |       M2  <-"bad" merge
  ... ____/ |
   | /      |
   M1       |
   | \____  |
  ...     \...
develop   master 

Шаг 3

# Merge as normal, from the tip of master to develop.
# This should now be an "easy" merge, with only "real" conflicts.
#  (Those that have changed in both branches)
#
# Note: I've had issues using origin master to merge from latest on remote, 
#   so instead I just ensure I've pulled the latest from master locally and 
#   merge from there

git merge master

Состояние после шага 3

   M5
   | \_____
   M4      \
   | \____  ... <-- Work after revert that needs merged to develop
   M3     \ |
   | \____  R  <-- Revert Bad Merge
   |      \ |
   |        A  <-- Commits after merge,
   |        |    /   but before revert
   |       ... </    and needs merged to develop
   |        |
   |       M2  <-"bad" merge
  ... ____/ |
   | /      |
   M1       |
   | \____  |
  ...     \...
develop   master 

Теперь develop обновляется последней версией master, без необходимости разрешать повторяющиеся или бессмысленные конфликты слияния. Будущие слияния также будут вести себя нормально.

person kugo2006    schedule 09.10.2017