Это пример того, где дизайн gitне соответствует git-flowрабочему процессу -ish, который все используют. Если вы сделали developэто, вы, конечно , хотите вернуть ветку 2-коммитов, в которой появилась ошибка, а не ветка с общим временем разработки. Чувствует себя нелепо, когда его нужно выбрать -m 1.
Пкамб
2
Еще одно предложение, которое мне никогда не приходило в голову - если один из списков коммитов веток мал, вам может быть удобнее возвращать отдельные коммиты вместо целой ветви коммитов.
Шридхар Сарнобат
Ответы:
1156
-mПараметр определяет родительский номер . Это потому, что коммит слияния имеет более одного родителя, и Git не знает автоматически, какой родитель был основной линией, и какой родитель был ветвью, которую вы хотите удалить.
Когда вы просматриваете коммит слияния в выводе git log, вы увидите его родителей в строке, которая начинается с Merge:
commit 8f937c683929b08379097828c8a04350b9b8e183
Merge: 8989ee0 7c6b236
Author: Ben James <ben@example.com>
Date: Wed Aug 17 22:49:41 2011 +0100
Merge branch 'gh-pages'
Conflicts:
README
В этой ситуации, git revert 8f937c6 -m 1вы получите дерево, как оно было 8989ee0, и git revert -m 2восстановите дерево, как оно было 7c6b236.
Чтобы лучше понять родительские идентификаторы, вы можете запустить:
Находясь в поисках лучшего объяснения, я нашел эту статью, которая, как мне показалось, отлично проработала детали. После прочтения я обнаружил, что на самом деле я искал команду RESET с последующим принудительным нажатием. Может быть, это поможет кому-то еще. atlassian.com/git/tutorials/…
Funktr0n
46
@ArupRakshit, если вы запускаете, git log 8989ee0и git log 7c6b236вы должны знать ответ.
BMW
4
git log - объединяет для просмотра всех слияний и git log --no-merges для просмотра истории без слияний. Слияние ветки приводит историю слитой ветки к цели и
усложняет
370
Вот полный пример в надежде, что это кому-то поможет:
Где <commit-hash>находится хеш коммита слияния, который вы хотели бы вернуть, и, как указано в пояснении к этому ответу , -m 1указывает, что вы хотите вернуться к дереву первого родителя до слияния.
git revert ...Линия по существу совершает изменения в то время как вторая линия делает ваши изменения общественности, вставив их в удаленный филиал.
Я полагал, что git revertкоманда уже передала созданный объект коммита. Чтобы этого не произошло, вам нужно будет ввести --no-commitфлаг
Delfic
2
Как упомянул @Delfic, коммит уже управляется первой строкой (мне нужно было: wq для его проверки), поэтому вторая строка не нужна.
eka808
1
это смущает. там только 2 строки и нет git commit .. может кто-нибудь пожалуйста отредактировать.
Джей Рэндом
176
Бен рассказал вам, как отменить коммит слияния, но очень важно, чтобы вы понимали, что при этом
«... объявляет, что вы никогда не захотите изменений дерева, внесенных слиянием. В результате, последующие слияния будут вносить только изменения дерева, внесенные коммитами, которые не являются предками ранее отмененного слияния. Это может или не может быть что вы хотите. " (страница справочника git-merge) .
В сообщении статьи / списка рассылки, связанном со страницей руководства, подробно описываются соответствующие механизмы и соображения. Просто убедитесь, что вы понимаете, что если вы отмените коммит слияния, вы не сможете просто слить ветку позже и ожидать, что те же изменения вернутся.
Но вы можете отменить возврат, чтобы вернуть их, если это действительно необходимо.
Далоре
5
Спасибо. Очень полезно знать, как вариант использования для отмены слияния - скажем, из-за ошибки - и затем повторного слияния всей ветви, как только ошибка исправлена, является распространенным.
Компонент 10
3
Если вы похожи на меня и позже хотите слияния, вы можете либо отменить возврат, либо черри выбрать изменение, которое вы отменили.
UnitasBrooks
В моей ситуации я столкнулся с необходимостью «отменить возврат», чтобы получить свои изменения назад. Сбор вишни может быть аккуратнее? Я попробую это в следующий раз ...
Стивен Андерсон
79
Вы можете выполнить эти шаги, чтобы отменить неправильные коммиты или вернуть удаленную ветвь обратно в правильный HEAD / состояние.
Оформить заказ на удаленную ветку в локальный репо. git checkout development
скопировать хеш коммита (т.е. идентификатор коммита непосредственно перед неправильным коммитом) из журнала git
git log -n5
сбросить ветку на хеш коммита, скопированный на предыдущем шаге git reset <commit-hash> (i.e. 3779ab50e72908da92d2cfcd72256d7a09f446ba)
запустить, git statusчтобы показать все изменения, которые были частью неправильного коммита.
просто запустите, git reset --hardчтобы отменить все эти изменения.
принудительно перенесите вашу локальную ветку на удаленный компьютер и обратите внимание, что история ваших изменений чиста, как это было до ее загрязнения. git push -f origin development
Подсказка: если вы делаете это в своей компании, у вас может не быть разрешения.
eneski
3
никогда не делайте push -fрепо в общем репо
Батист Милле-Матиас
17
Иногда самый эффективный способ отката - сделать шаг назад и заменить.
git log
Используйте хэш 2-го коммита (полный хеш, тот, к которому вы хотите вернуться, до того, как ошибка была указана), а затем выполните повторную разметку оттуда.
git checkout -b newbranch <HASH>
Затем удалите старую ветку, скопируйте новую ветку на место и перезапустите оттуда.
Предупреждение о трансляции должно быть более ясным о том, насколько ужасна эта идея. Это повредит все версии этой ветки и будет действительно полезным, только если вы работаете с удаленным репозиторием (github / bitbucket), к которому только у вас есть доступ.
RobbyD
Не так плохо, как отправка измененных файлов конфигурации в поток. Он не будет поврежден, это просто переопределение предыдущей фиксации, так что это обходной способ переместить указатель веток на более раннюю версию. Надеюсь, это
повлияет
5
Если вы хотите отменить mergeкоммит, вот что вам нужно сделать.
Сначала проверьте, git logчтобы найти идентификатор вашего слияния. Вы также найдете несколько родительских идентификаторов, связанных с объединением (см. Изображение ниже).
Запишите идентификатор фиксации слияния, показанный желтым цветом. Родительские идентификаторы - это те, которые записаны в следующей строке как Merge: parent1 parent2. Сейчас же...
Короткий рассказ:
Переключитесь на ветку, на которой было произведено слияние. Затем просто сделайте то, git revert <merge commit id> -m 1что откроет viконсоль для ввода сообщения коммита. Написать, сохранить, выйти, готово!
Длинная история:
Переключитесь на ветку, на которой было произведено слияние. В моем случае это testветка, и я пытаюсь удалить feature/analytics-v3из нее ветку.
git revertэто команда, которая отменяет любой коммит Но при отмене mergeкоммита есть неприятный трюк . Вам нужно ввести -mфлаг, иначе он не удастся. С этого момента вам необходимо решить, хотите ли вы вернуть свою ветку и сделать так, чтобы она выглядела именно так, как она была, parent1или parent2через нее :
git revert <merge commit id> -m 1(возвращается к parent2)
git revert <merge commit id> -m 2(возвращается к parent1)
Вы можете git войти эти родители, чтобы выяснить, каким путем вы хотите пойти, и это корень всей путаницы.
Все ответы уже охватывали большинство вещей, но я добавлю свои 5 центов. Короче говоря, отменить коммит слияния довольно просто:
git revert -m 1 <commit-hash>
Если у вас есть разрешение, вы можете отправить его прямо в «главную» ветку, в противном случае просто переместите его в свою «возвратную» ветку и создайте запрос на извлечение.
Я обнаружил, что создание обратного патча между двумя известными конечными точками и применение этого патча будет работать. Это предполагает, что вы создали моментальные снимки (теги) из своей основной ветви или даже резервную копию своей основной ветви, скажем, master_bk_01012017.
Скажем, ветвь кода, которую вы объединили в master, была mycodebranch.
Оформить заказ мастеру.
Создайте полное двоичное обратное исправление между мастером и резервной копией.
git diff --binary master..master_bk_01012017 > ~/myrevert.patch
Применить патч с подписью
git am --signoff < myrevert.patch
Если вам нужно будет снова ввести этот код, как только он будет исправлен, вам нужно будет разветвиться от возвращенного мастера и извлечь ветку исправлений
git branch mycodebranch_fixgit checkout mycodebranch_fix
Здесь вам нужно найти ключ SHA для возврата и отменить возврат
git revert [SHA]
Теперь вы можете использовать mycodebranch_fix для исправления проблем, фиксации и повторного слияния с мастером после завершения.
Правильно отмеченный ответ сработал для меня, но мне пришлось потратить некоторое время, чтобы определить, что происходит .. Поэтому я решил добавить ответ с простыми простыми шагами для случаев, подобных моему ..
Допустим, у нас есть ветви A и B .. Вы слили ветвь A в ветвь B и подтолкнули ветвь B к себе, так что теперь слияние является частью этого ... Но вы хотите вернуться к последнему коммиту перед слиянием .. Что делать вы делаете?
Перейдите в корневую папку вашего git (обычно это папка проекта) и используйте git log
Вы увидите историю последних коммитов - коммиты имеют свойства commit / author / date, а слияния также имеют свойство merge - так что вы видите их так:
Используйте git log <parentHashA>и git log <parentHashB>- вы увидите истории коммитов этих родительских веток - первые коммиты в списке самые последние
Возьмите <commitHash>коммит, который вы хотите, перейдите в вашу корневую папку git и используйте git checkout -b <newBranchName> <commitHash>- это создаст новую ветку, начиная с того последнего коммита, который вы выбрали до слияния. Вуаля, готово!
Я также столкнулся с этой проблемой на PR, который был объединен с главной веткой репозитория GitHub.
Так как я только хотел изменить некоторые измененные файлы , но не целые изменения ПР принесло, я должен был с .amendmerge commitgit commit --am
шаги:
Перейдите в ветку, в которую вы хотите изменить / отменить некоторые измененные файлы.
Сделайте необходимые изменения в соответствии с измененными файлами
запустить git add *илиgit add <file>
запустить git commit --amи проверить
запустить git push -f
Почему это интересно:
Сохраняет фиксацию автора PR без изменений
Это не ломает мерзкое дерево
Вы будете помечены как коммиттер (автор коммитов слияния останется без изменений)
Git действует так, как будто вы разрешаете конфликты, он удаляет / изменяет код в измененных файлах, как если бы вы вручную указали GitHub не объединять его как есть.
Я нашел хорошее объяснение для « Как отменить слияние» по этой ссылке, и я скопировал и вставил объяснение ниже, и это было бы полезно на тот случай, если ссылка ниже не работает.
Как отменить ошибочное слияние, Алан (alan@clueserver.org) сказал:
У меня есть мастер ветка. У нас есть ветка, над которой работают некоторые разработчики. Они утверждают, что это готово. Мы объединяем это в главную ветку. Это что-то ломает, поэтому мы отменяем слияние. Они вносят изменения в код. они получают его до такой степени, что говорят, что все в порядке, и мы снова сливаемся. При рассмотрении мы обнаруживаем, что изменения кода, сделанные до возврата, находятся не в основной ветви, а изменения кода после находятся в основной ветви. и попросил помощи в восстановлении после этой ситуации.
История сразу после «возврата к слиянию» будет выглядеть так:
---o---o---o---M---x---x---W
/
---A---B
где A и B находятся на стороне развития, которая была не очень хорошей, M - это слияние, которое вносит эти преждевременные изменения в основную линию, x - это изменения, не связанные с тем, что боковая ветвь сделала и уже сделала на основной линии, а W - это " возврат слияния М "(разве W не смотрит на М с ног на голову?). IOW, "diff W ^ .. W" похож на "diff -RM ^ .. M".
Такой «возврат» слияния может быть сделан с помощью:
$ git revert -m 1 M
После того, как разработчики боковой ветки исправят свои ошибки, история может выглядеть так:
где C и D должны исправить то, что было сломано в A и B, и у вас уже могут быть некоторые другие изменения в магистрали после W.
Если вы объедините обновленную боковую ветвь (с D на кончике), ни одно из изменений, сделанных в A или B, не будет в результате, потому что они были отменены W. Это то, что Алан видел.
Линус объясняет ситуацию:
Отмена обычного коммита просто эффективно отменяет то, что сделал этот коммит, и довольно проста. Но возвращение коммита слияния также отменяет данные, которые коммит изменил, но это абсолютно не влияет на историю, которую слияние имело. Таким образом, слияние все еще будет существовать, и оно все равно будет рассматриваться как объединение двух ветвей, и будущие слияния будут видеть, что слияние является последним общим состоянием - и обратный процесс, который отменил введенное слияние, не повлияет на это вообще. Таким образом, «возврат» отменяет изменения данных, но это очень не«отмена» в том смысле, что она не отменяет влияния коммита на историю репозитория. Так что если вы думаете о «возврате» как об «отмене», то вы всегда будете пропускать эту часть возвратов. Да, это отменяет данные, но нет, это не отменяет историю. В такой ситуации вы бы хотели сначала вернуть предыдущий возврат, что бы история выглядела следующим образом:
Как упоминал Райан, это git revertможет затруднить слияние в будущем, поэтому, git revertвозможно, это не то, что вы хотите. Я обнаружил, что использование git reset --hard <commit-hash-prior-to-merge>команды более полезно здесь.
После того, как вы выполнили часть аппаратного сброса, вы можете принудительно нажать на удаленную ветвь, то есть там git push -f <remote-name> <remote-branch-name>, где <remote-name>часто называют origin. С этого момента вы можете повторно объединить, если хотите.
Все, что связано с форсированными ударами, является плохой идеей, если вы не единственный, кто использует репо, и вы точно не знаете, что делаете. Возврат с помощью git revert, а затем, возможно, возвращение возврата с помощью git revert (если вам нужно вернуть вещи обратно) - гораздо более безопасная альтернатива.
git
не соответствуетgit-flow
рабочему процессу -ish, который все используют. Если вы сделалиdevelop
это, вы, конечно , хотите вернуть ветку 2-коммитов, в которой появилась ошибка, а не ветка с общим временем разработки. Чувствует себя нелепо, когда его нужно выбрать-m 1
.Ответы:
-m
Параметр определяет родительский номер . Это потому, что коммит слияния имеет более одного родителя, и Git не знает автоматически, какой родитель был основной линией, и какой родитель был ветвью, которую вы хотите удалить.Когда вы просматриваете коммит слияния в выводе
git log
, вы увидите его родителей в строке, которая начинается сMerge
:В этой ситуации,
git revert 8f937c6 -m 1
вы получите дерево, как оно было8989ee0
, иgit revert -m 2
восстановите дерево, как оно было7c6b236
.Чтобы лучше понять родительские идентификаторы, вы можете запустить:
а также
источник
8989ee0
,7c6b236
какой из них идти. Как бы я понял?git log 8989ee0
иgit log 7c6b236
вы должны знать ответ.Вот полный пример в надежде, что это кому-то поможет:
Где
<commit-hash>
находится хеш коммита слияния, который вы хотели бы вернуть, и, как указано в пояснении к этому ответу ,-m 1
указывает, что вы хотите вернуться к дереву первого родителя до слияния.git revert ...
Линия по существу совершает изменения в то время как вторая линия делает ваши изменения общественности, вставив их в удаленный филиал.источник
git revert
команда уже передала созданный объект коммита. Чтобы этого не произошло, вам нужно будет ввести--no-commit
флагБен рассказал вам, как отменить коммит слияния, но очень важно, чтобы вы понимали, что при этом
В сообщении статьи / списка рассылки, связанном со страницей руководства, подробно описываются соответствующие механизмы и соображения. Просто убедитесь, что вы понимаете, что если вы отмените коммит слияния, вы не сможете просто слить ветку позже и ожидать, что те же изменения вернутся.
источник
Вы можете выполнить эти шаги, чтобы отменить неправильные коммиты или вернуть удаленную ветвь обратно в правильный HEAD / состояние.
git checkout development
скопировать хеш коммита (т.е. идентификатор коммита непосредственно перед неправильным коммитом) из журнала git
git log -n5
сбросить ветку на хеш коммита, скопированный на предыдущем шаге
git reset <commit-hash> (i.e. 3779ab50e72908da92d2cfcd72256d7a09f446ba)
git status
чтобы показать все изменения, которые были частью неправильного коммита.git reset --hard
чтобы отменить все эти изменения.git push -f origin development
источник
источник
Чтобы сохранить журнал в чистоте, так как ничего не произошло (с некоторыми недостатками при таком подходе (из-за нажатия -f)):
'commit-hash-before-merge' приходит из журнала (git log) после слияния.
источник
push -f
репо в общем репоИногда самый эффективный способ отката - сделать шаг назад и заменить.
git log
Используйте хэш 2-го коммита (полный хеш, тот, к которому вы хотите вернуться, до того, как ошибка была указана), а затем выполните повторную разметку оттуда.
git checkout -b newbranch <HASH>
Затем удалите старую ветку, скопируйте новую ветку на место и перезапустите оттуда.
Если он был передан, то удалите старую ветку из всех репозиториев, переместите переделанную ветвь в самую центральную и отведите ее обратно ко всем.
источник
Если вы хотите отменить
merge
коммит, вот что вам нужно сделать.git log
чтобы найти идентификатор вашего слияния. Вы также найдете несколько родительских идентификаторов, связанных с объединением (см. Изображение ниже).Запишите идентификатор фиксации слияния, показанный желтым цветом. Родительские идентификаторы - это те, которые записаны в следующей строке как
Merge: parent1 parent2
. Сейчас же...Короткий рассказ:
git revert <merge commit id> -m 1
что откроетvi
консоль для ввода сообщения коммита. Написать, сохранить, выйти, готово!Длинная история:
Переключитесь на ветку, на которой было произведено слияние. В моем случае это
test
ветка, и я пытаюсь удалитьfeature/analytics-v3
из нее ветку.git revert
это команда, которая отменяет любой коммит Но при отменеmerge
коммита есть неприятный трюк . Вам нужно ввести-m
флаг, иначе он не удастся. С этого момента вам необходимо решить, хотите ли вы вернуть свою ветку и сделать так, чтобы она выглядела именно так, как она была,parent1
илиparent2
через нее :git revert <merge commit id> -m 1
(возвращается кparent2
)git revert <merge commit id> -m 2
(возвращается кparent1
)Вы можете git войти эти родители, чтобы выяснить, каким путем вы хотите пойти, и это корень всей путаницы.
источник
Все ответы уже охватывали большинство вещей, но я добавлю свои 5 центов. Короче говоря, отменить коммит слияния довольно просто:
Если у вас есть разрешение, вы можете отправить его прямо в «главную» ветку, в противном случае просто переместите его в свою «возвратную» ветку и создайте запрос на извлечение.
Вы можете найти более полезную информацию по этому вопросу здесь: https://itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html
источник
Я обнаружил, что создание обратного патча между двумя известными конечными точками и применение этого патча будет работать. Это предполагает, что вы создали моментальные снимки (теги) из своей основной ветви или даже резервную копию своей основной ветви, скажем, master_bk_01012017.
Скажем, ветвь кода, которую вы объединили в master, была mycodebranch.
git diff --binary master..master_bk_01012017 > ~/myrevert.patch
git apply --check myrevert.patch
git am --signoff < myrevert.patch
git branch mycodebranch_fix
git checkout mycodebranch_fix
git revert [SHA]
источник
Правильно отмеченный ответ сработал для меня, но мне пришлось потратить некоторое время, чтобы определить, что происходит .. Поэтому я решил добавить ответ с простыми простыми шагами для случаев, подобных моему ..
Допустим, у нас есть ветви A и B .. Вы слили ветвь A в ветвь B и подтолкнули ветвь B к себе, так что теперь слияние является частью этого ... Но вы хотите вернуться к последнему коммиту перед слиянием .. Что делать вы делаете?
git log
Вы увидите историю последних коммитов - коммиты имеют свойства commit / author / date, а слияния также имеют свойство merge - так что вы видите их так:
commit: <commitHash> Merge: <parentHashA> <parentHashB> Author: <author> Date: <date>
Используйте
git log <parentHashA>
иgit log <parentHashB>
- вы увидите истории коммитов этих родительских веток - первые коммиты в списке самые последние<commitHash>
коммит, который вы хотите, перейдите в вашу корневую папку git и используйтеgit checkout -b <newBranchName> <commitHash>
- это создаст новую ветку, начиная с того последнего коммита, который вы выбрали до слияния. Вуаля, готово!источник
git doc о git revert -m предоставьте ссылку, чтобы объяснить это: https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt
источник
Я также столкнулся с этой проблемой на PR, который был объединен с главной веткой репозитория GitHub.
Так как я только хотел изменить некоторые измененные файлы , но не целые изменения ПР принесло, я должен был с .
amend
merge commit
git commit --am
шаги:
git add *
илиgit add <file>
git commit --am
и проверитьgit push -f
Почему это интересно:
источник
Я нашел хорошее объяснение для « Как отменить слияние» по этой ссылке, и я скопировал и вставил объяснение ниже, и это было бы полезно на тот случай, если ссылка ниже не работает.
Как отменить ошибочное слияние, Алан (alan@clueserver.org) сказал:
У меня есть мастер ветка. У нас есть ветка, над которой работают некоторые разработчики. Они утверждают, что это готово. Мы объединяем это в главную ветку. Это что-то ломает, поэтому мы отменяем слияние. Они вносят изменения в код. они получают его до такой степени, что говорят, что все в порядке, и мы снова сливаемся. При рассмотрении мы обнаруживаем, что изменения кода, сделанные до возврата, находятся не в основной ветви, а изменения кода после находятся в основной ветви. и попросил помощи в восстановлении после этой ситуации.
История сразу после «возврата к слиянию» будет выглядеть так:
где A и B находятся на стороне развития, которая была не очень хорошей, M - это слияние, которое вносит эти преждевременные изменения в основную линию, x - это изменения, не связанные с тем, что боковая ветвь сделала и уже сделала на основной линии, а W - это " возврат слияния М "(разве W не смотрит на М с ног на голову?). IOW, "diff W ^ .. W" похож на "diff -RM ^ .. M".
Такой «возврат» слияния может быть сделан с помощью:
$ git revert -m 1 M После того, как разработчики боковой ветки исправят свои ошибки, история может выглядеть так:
где C и D должны исправить то, что было сломано в A и B, и у вас уже могут быть некоторые другие изменения в магистрали после W.
Если вы объедините обновленную боковую ветвь (с D на кончике), ни одно из изменений, сделанных в A или B, не будет в результате, потому что они были отменены W. Это то, что Алан видел.
Линус объясняет ситуацию:
Отмена обычного коммита просто эффективно отменяет то, что сделал этот коммит, и довольно проста. Но возвращение коммита слияния также отменяет данные, которые коммит изменил, но это абсолютно не влияет на историю, которую слияние имело. Таким образом, слияние все еще будет существовать, и оно все равно будет рассматриваться как объединение двух ветвей, и будущие слияния будут видеть, что слияние является последним общим состоянием - и обратный процесс, который отменил введенное слияние, не повлияет на это вообще. Таким образом, «возврат» отменяет изменения данных, но это очень не«отмена» в том смысле, что она не отменяет влияния коммита на историю репозитория. Так что если вы думаете о «возврате» как об «отмене», то вы всегда будете пропускать эту часть возвратов. Да, это отменяет данные, но нет, это не отменяет историю. В такой ситуации вы бы хотели сначала вернуть предыдущий возврат, что бы история выглядела следующим образом:
где Y - это возврат к W. Такой «возврат к возврату» можно сделать с помощью:
$ git revert W Эта история (игнорируя возможные конфликты между изменениями W и W..Y) будет эквивалентна отсутствию W или Y в истории:
и повторное объединение боковой ветви не приведет к конфликту, связанному с более ранним возвратом и восстановлением возврата.
Конечно, изменения, сделанные в C и D, все еще могут конфликтовать с тем, что было сделано любым из x, но это обычный конфликт слияния.
источник
Как упоминал Райан, это
git revert
может затруднить слияние в будущем, поэтому,git revert
возможно, это не то, что вы хотите. Я обнаружил, что использованиеgit reset --hard <commit-hash-prior-to-merge>
команды более полезно здесь.После того, как вы выполнили часть аппаратного сброса, вы можете принудительно нажать на удаленную ветвь, то есть там
git push -f <remote-name> <remote-branch-name>
, где<remote-name>
часто называютorigin
. С этого момента вы можете повторно объединить, если хотите.источник