Ответ 1
Возвращение слияния и слияния слияния
Я предполагаю, что вы на самом деле Already-up-to-date
.
Проблема заключается в том, что git revert не отменяет слияние, она отменяет изменения, сгенерированные слиянием. Когда вы создаете фиксацию слияния, вы комбинируете истории фиксации этих двух ветвей.
Слияние
develop
|
A---B---C
\ \
E---F---M
|
newfeature
В приведенном выше случае develop
объединяется в newfeature
, создавая фиксацию M
. Если бы вы выполнили git log newfeature
, вы увидели бы все коммиты из обеих ветвей, однако с точки зрения ветки newfeature
все эти изменения были выполнены с помощью M
commit.
Откат
Команда git revert
не удаляет какие-либо коммиты, вместо этого создает новую фиксацию, которая отменяет изменения, содержащиеся в фиксации. Например, если у вас есть фиксация, содержащая этот diff...
-This is the old sentence.
+This is ne new sentence.
Затем вернет это, команда revert создаст новый коммит, который только что сформировал противоположный diff, он просто переворачивает знаки.
-This is ne new sentence.
+This is the old sentence.
Это действительно полезно для устранения ущерба, вызванного коммитами, которые уже есть у других разработчиков. Он перемещает историю вперед, а не меняет историю.
Возвращение слияния
Однако, в контексте небыстрого слияния он может иметь нежелательный эффект.
develop
|
A---B---C
\ \
E---F---M---W
|
newfeature
Предполагая, что W является фиксацией реверсии, вы можете увидеть, как работает git log newfeature
все равно будет включать все коммиты из ветки разработки. В результате дополнительные слияния из develop
не будут работать, потому что в вашей ветке ничего не видно.
Используя git reset вместо возврата.
В будущем вам может потребоваться использовать git reset --hard <ref>
(где <ref>
- хеш фиксации слияния), чтобы отменить слияние, если это слияние не было передано другим разработчикам. В приведенном выше примере после создания слияния M
выполнение команды git reset --hard F
приведет к следующему.
develop
|
A---B---C
\ \
E---F---M
|
newfeature
Как вы можете видеть, этот метод не уничтожает фиксацию, как некоторые люди склонны думать, она просто переводит вашу ветку обратно в выбранную вами фиксацию. Теперь, если вы запустили git log newfeature
, вы получите только commit F
, E
и A
. Теперь слияние фактически исчезло из истории ваших веток, поэтому более поздние попытки повторного объединения в develop
не вызовут никаких проблем.
Этот метод не лишен своих осложнений. Поймите, что теперь вы изменяете историю, поэтому, если ветвь newfeature
была нажата на удаленную ветвь после слияния M
, тогда git будет думать, что вы просто устарели и говорите, что вам нужно для запуска git pull
. Если вы просто работаете над этой удаленной ветвью, тогда не стесняйтесь force-push
- git push -f <remote> <branch>
. Это будет иметь тот же эффект от reset, но на удаленной ветке.
Если эта ветка используется несколькими разработчиками, которые уже сейчас вытащили из нее, то это плохая идея. Именно по этой причине полезно использовать git revert
, поскольку оно отменяет изменения, не изменяя фактическую историю.
Использование reset в истории действительно только на опции для коммитов, которые не были разделены.
Решение - возврат реверсии.
Если фиксация слияния уже была разделена, лучшим вариантом является использование git revert
в этом объединении. Однако, как мы говорили ранее, вы не можете просто просто объединить ветку и ожидать, что все изменения из этой ветки снова появятся. Ответ заключается в том, чтобы вернуть реверт commit.
Предположим, вы сделали некоторую работу в ветке develop
после того, как почитали слияние в newfeature
. Ваша история будет выглядеть примерно так.
develop
|
A---B---C---D
\ \
E---F---M---W
|
newfeature
Если теперь вы объедините develop
в newfeature
, вы получите только D
, потому что это единственная команда, которая еще не является частью истории ветки newfeature
. Вам также нужно вернуться, чтобы W
commit - git revert W
выполнить трюк, за которым следует git merge develop
.
develop
|
A---B---C-----------D
\ \ \
E---F---M---W---M---G
|
newfeature
Это восстанавливает все изменения, сделанные первоначальной фиксацией слияния, которые были фактически сделаны с помощью C
и B
, но были возвращены в W
, затем он вносит D
через новое объединение слиянием G
Я бы рекомендовал возвратить возврат до слияния в недавних изменениях с develop
, я подозреваю, что выполнение этого в этом порядке будет иметь более низкий шанс вызвать конфликты.
TL; DR
Возвращение создает "revert commit". При отмене возврата вам необходимо запустить команду revert на revert commit, которая была создана, когда вы вернулись в первый раз. Достаточно легко найти, git стремится автоматически комментировать реверты, чтобы они начинались со слова "Отклонено".
git revert <commit>