Як повернути комісію злиття, яка вже перенесена на віддалену гілку?


959

git revert <commit_hash>поодинці не вийде. -mтреба вказати, і я дуже збентежений у цьому.

Хтось раніше це відчував?


3
Подивіться на відповідь на це питання: stackoverflow.com/questions/2318777/…
eugen


Посилання тут - найкращий приклад, який ілюструє повернення об'єднаного комітету: christianengvall.se/undo-pushed-merge-git
SK Venkat

Це приклад того, коли дизайн gitне відповідає git-flowпоточному робочому процесу, який користуються всі. Якщо ви developзареєструвались, звичайно, ви хочете відновити гілку функції 2-фіксації, яка ввела помилку, а не багаторічну гілку розробників. Відчуває себе смішним, коли потрібно його забрати -m 1.
pamamb

2
Ще одна пропозиція, яка мені раніше не приходила - якщо один із переліків філій невеликий, ви можете почувати себе зручніше повертати окремі комісії замість цілої гілки комітетів.
Шрідхар Сарнобат

Відповіді:


1152

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

Щоб краще зрозуміти батьківські ідентифікатори, ви можете запустити:

git log 8989ee0 

і

git log 7c6b236

127
з двох чисел 8989ee0, 7c6b236яке саме піти. Як би я зрозумів?
Arup Rakshit

12
Після відновлення я не думаю, що хтось зможе легко виправити код у вихідній гілці та знову об'єднатись? kernel.org/pub/software/scm/git/docs/howto/…
IsmailS

10
Поки гуглилися навколо пошуків кращого пояснення, я знайшов цю статтю, яку, на мою думку, зробив чудову роботу, перебираючи деталі. Після прочитання я виявив, що насправді шукав команду RESET, за якою послідував силовий натиск. Можливо, це допоможе комусь іншому. atlassian.com/git/tutorials/…
Funktr0n

46
@ArupRakshit, якщо ви запустите git log 8989ee0і git log 7c6b236, вам слід знати відповідь.
BMW

4
git log - merges, щоб побачити всі злиття, а git log --no-merges, щоб бачити історію без злиття. Об’єднання гілки приводить об’єднану історію гілки до цілі та ускладнює її
розбір

369

Ось повний приклад з надією, що він комусь допоможе:

git revert -m 1 <commit-hash> 
git push -u origin master

Де <commit-hash>знаходиться хеш злиття злиття, який ви хочете відновити, і як зазначено в поясненні цієї відповіді , -m 1вказується, що ви хочете повернутись до дерева першого з батьків до злиття.

git revert ...Лінія по суті робить зміни в той час як друга лінія робить ваші зміни громадськості, вставивши їх в віддалений філія.


21
Я вважав, що git revertкоманда вже заповнила створений об'єкт. Щоб цього не сталося, вам доведеться ввести --no-commitпрапор
Delfic

2
Як зазначав @Delfic, комісія вже керується першим рядком (мені знадобилося: wq, щоб перевірити його), тому другий рядок не потрібен.
eka808

1
це заплутано. є лише 2 рядки, і жодна git фіксація .. може хтось, будь ласка, відредагуйте.
Jay Random

176

Бен розповів вам, як повернути об'єкт злиття, але це дуже важливо, ви розумієте, що роблячи це

"... заявляє, що ви ніколи не захочете змін дерев, внесених при злитті. В результаті пізніші злиття принесуть лише зміни дерев, введені комітетами, які не є предками раніше поверненого злиття. Це може бути, а може і не бути що ви хочете. " (сторінка людини git-merge) .

Повідомлення зі статтею та списком розсилки, пов’язане із підручною сторінкою, детально описує механізми та міркування, які стосуються. Просто переконайтеся, що ви розумієте, що якщо ви скасуєте комісію злиття, ви не зможете просто знову об'єднати гілку пізніше і очікувати повернення тих же змін.


80
Але ви можете повернути повернення, щоб повернути їх, якщо вони справді потрібні.
dalore

5
Дякую. Дуже корисно знати, як випадок використання для скасування злиття - скажімо, через помилку, скажімо, - а потім повторне об’єднання всієї гілки, коли помилка виправлена, є загальним.
Компонент 10

3
Якщо ви схожі на мене і пізніше хотіли злиття, ви можете або повернути назад, або вишнею вибрати зміну, яку ви відмінили.
UnitasBrooks

У моїй ситуації я відчув необхідність "повернути відновлення", щоб отримати мою проблему змін. Збір вишні може бути акуратнішим способом? Я спробую це наступного разу ...
Стівен Андерсон,

79

Ви можете виконати ці кроки, щоб скасувати неправильні комісії або скинути віддалену гілку назад, щоб виправити HEAD / state.

  1. замовити віддалене відділення до місцевого репо.
    git checkout development
  2. скопіюйте хеш комісії (тобто ідентифікатор комісії безпосередньо перед неправильним фіксацією) з журналу git git log -n5

    вихід:

    зробити 7cd42475d6f95f5896b6f02e902efab0b70e8038 "Об'єднати гілку" неправильно-зробити "в" розвиток ""
    зробити f9a734f8f44b0b37ccea769b9a2fd774c0f0c012 "це неправильне
    "

  3. скинути гілку на хеш комітів, скопійований на попередньому кроці
    git reset <commit-hash> (i.e. 3779ab50e72908da92d2cfcd72256d7a09f446ba)

  4. запустіть, git statusщоб показати всі зміни, які були частиною неправильної комісії.
  5. просто запустіть, git reset --hardщоб відновити всі ці зміни.
  6. змушуйте натиснути локальну гілку на віддалене місце і помітити, що історія ваших чинів чиста, як була до забруднення.
    git push -f origin development

4
що робити, якщо тим часом 20 розробників витягнули останнє об'єднання розробників?
Евокс,

2
Я б не змушував натискати галузь розвитку, коли в команді працює 20 розробників, які використовують цю гілку. :) У такому випадку розумно просто зробити повернення.
ssasi

4
Це дуже гарне рішення, коли ви працюєте самостійно або ви впевнені, що ніхто з інших чортів не стягнув з вас зобов’язань
Кайл Б


30

Щоб зберегти журнал чистим, як нічого не сталося (з деякими недоліками при такому підході (через push -f)):

git checkout <branch>
git reset --hard <commit-hash-before-merge>
git push -f origin HEAD:<remote-branch>

'commit-hash-before-merge' походить з журналу (git log) після злиття.


Підказка: Якщо ви робите це у вашій компанії, у вас може не бути дозволу.
eneski

3
ніколи не push -f
Baptiste Mille-Mathias

17

Іноді найефективніший спосіб відкату - це відступити і замінити.

git log

Використовуйте хеш 2-го фіксації (повний хеш, той, до якого ви хочете повернутись, перш ніж вказана помилка), а потім перезавантажте звідти.

git checkout -b newbranch <HASH>

Потім видаліть стару гілку, скопіюйте її на її місце і перезапустіть звідти.

git branch -D oldbranch
git checkout -b oldbranch newbranch

Якщо його транслювали, видаліть стару гілку з усіх сховищ, висуньте перероблену гілку до самого центрального та потягніть її назад до всіх.


4
Попередження про трансляцію справді повинно бути більш явним щодо того, наскільки це жахлива ідея. Це пошкодить всі версії цієї гілки і є корисними лише у тому випадку, якщо ви працюєте з віддаленим сховищем (github / bitbucket), до якого ви маєте доступ.
RobbyD

Не так вже й погано, як підштовхування модифікованих конфігураційних файлів у потоці до виробництва. Він не буде корумпованим, його просто перезавантажити на попередню версію, так що це шлях для переходу вказівника гілок на більш ранню версію. Сподіваємось, це вплине лише на локальне сховище
ppostma1

5

Якщо ви хочете повернути mergeкомісію, ось що вам потрібно зробити.

  1. Спочатку поставте прапорець, git logщоб знайти ідентифікатор комісії злиття. Ви також знайдете кілька батьківських ідентифікаторів, пов’язаних зі злиттям (див. Зображення нижче).

введіть тут опис зображення

Запишіть ідентифікатор комірок злиття, показаний жовтим кольором. Батьківські ідентифікатори - це ті, що записані в наступному рядку як Merge: parent1 parent2. Тепер ...

Коротка розповідь:

  1. Перехід на гілку, на якій було здійснено злиття. Потім просто зробіть те, git revert <merge commit id> -m 1що відкриє viконсоль для введення повідомлення про фіксацію. Пишіть, зберігайте, виходьте, готово!

Довга історія:

  1. Перехід на гілку, на якій було здійснено злиття. У моєму випадку це testгілка, і я намагаюся видалити feature/analytics-v3гілку з неї.

  2. git revert- це команда, яка повертає будь-яку команду. Але є гарна хитрість при поверненні mergeкомітету. Вам потрібно ввести -mпрапор, інакше він не вдасться. З цього моменту вам потрібно вирішити, чи хочете ви відновити свою філію і зробити так, щоб вона виглядала так, як саме вона була parent1або parent2через:

git revert <merge commit id> -m 1(повертається до parent2)

git revert <merge commit id> -m 2(повертається до parent1)

Ви можете вписати цих батьків, щоб зрозуміти, яким шляхом ви хочете піти, і це корінь усієї плутанини.


5

Усі відповіді вже охоплювали більшість речей, але я додам свої 5 центів. Коротше кажучи, повернення комісії злиття досить просте:

git revert -m 1 <commit-hash>

Якщо у вас є дозвіл, ви можете натиснути його безпосередньо на "головну" гілку, інакше просто натисніть її на "повернути" гілку і створіть запит на тягу.

Ви можете знайти більше корисної інформації з цього приводу тут: https://itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html


1

Я виявив, що створити зворотний патч між двома кінцевими точками відомості та застосувати цей патч буде спрацьовувати. Це передбачає, що ви створили знімки (теги) з вашого головного відділення або навіть резервну копію вашого головного відділення, наприклад, master_bk_01012017.

Скажімо, гілка коду, яку ви об'єднали в головну, була моєю кодовою галуззю.

  1. Майстер замовлення
  2. Створіть повний бінарний зворотний патч між головним і резервним копієм. git diff --binary master..master_bk_01012017 > ~/myrevert.patch
  3. Перевірте свій патч git apply --check myrevert.patch
  4. Застосувати патч із відходом git am --signoff < myrevert.patch
  5. Якщо вам потрібно буде знову ввести цей код, як тільки він буде виправлений, вам потрібно буде відгалужити повернутий головний майстер і оформити гілку виправлення git branch mycodebranch_fix git checkout mycodebranch_fix
  6. Тут потрібно знайти ключ SHA для повернення та повернути назад git revert [SHA]
  7. Тепер ви можете використовувати мій mycodebranch_fix для виправлення неполадок, фіксації та повторного об’єднання в програму.

1

Правильно позначена відповідь працювала для мене, але мені довелося витратити певний час, щоб визначити, що відбувається. Тому я вирішив додати відповідь простими прямими кроками для таких випадків, як моя ..

Скажімо, у нас є гілки A і B .. Ви об'єднали гілку A у гілку B і відсунули гілку B до себе, тож тепер злиття є її частиною .. Але ви хочете повернутися до останнього комітету перед злиттям. Що робити ти робиш?

  1. Перейдіть у свою кореневу папку git (зазвичай проектну папку) та використовуйте git log
  2. Ви побачите історію останніх комітетів - у комітетів є властивості commit / author / date, тоді як у злиття також є властивість злиття, тож ви бачите їх такими:

    commit: <commitHash> Merge: <parentHashA> <parentHashB> Author: <author> Date: <date>

  3. Використовуйте git log <parentHashA>та git log <parentHashB>- ви побачите історію фіксації цих батьківських гілок - перші переліки в списку є останніми

  4. Візьміть потрібну <commitHash>комісію, перейдіть до вашої кореневої папки git і використовуйте git checkout -b <newBranchName> <commitHash>- це створить нову гілку, починаючи з того останнього комітету, який ви вибрали перед об'єднанням. Voila, готово!


0

Я також зіткнувся з цим питанням щодо PR, який був об'єднаний у головну гілку репо GitHub.

Так як я тільки хотів змінити деякі змінені файли , але не цілі зміни ПР принесло, я повинен був з .amendmerge commitgit commit --am

Кроки:

  1. Перейдіть до гілки, яку потрібно змінити / повернути деякі модифіковані файли
  2. Виконайте потрібні зміни відповідно до змінених файлів
  3. бігати git add *абоgit add <file>
  4. запустити git commit --amта перевірити
  5. бігати git push -f

Чому це цікаво:

  • Це залишає автори PR-зобов'язань незмінними
  • Це не порушує дерево git
  • Вас позначають як виконавці (автор злиття комітету залишиться незмінним)
  • Git поводиться так, ніби ви вирішили конфлікти, він видалить / змінить код у модифікованих файлах, як якщо б ви вручну сказали GitHub не зливати його як є

0

Я знайшов гарне пояснення для того, як повернути Злиття з цього посилання, і я скопіював вкладене пояснення нижче, і було б корисно про всяк випадок, якщо посилання нижче не працює.

Як відновити несправне злиття Алан (alan@clueserver.org) сказав:

У мене є майстер відділення. У нас є відгалуження того, над чим працюють деякі розробники. Вони стверджують, що вона готова. Ми об'єднуємо його в головну гілку. Це щось порушує, тому ми повертаємо злиття. Вони вносять зміни в код. вони дістають це до того моменту, коли кажуть, що це нормально, і ми знову зливаємось. Перевіряючи, ми виявляємо, що зміни коду, внесені до відновлення, не в головній гілці, а зміни коду після того, як у головній гілці. і попросив допомоги видужати від цієї ситуації.

Історія відразу після "відновлення злиття" виглядатиме так:

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

де A і B знаходяться на стороні розвитку, що було не так добре, M - це злиття, яке приносить ці передчасні зміни в магістраль, x - зміни, не пов'язані з тим, що зробили бічні гілки і вже зроблені на магістралі, а W - " повернення злиття M "(не виглядає ли W вниз головою?). IOW, "diff W ^ .. W" схоже на "diff -RM ^ .. M".

Таке "повернення" об'єднання може бути здійснено за допомогою:

$ git revert -m 1 M Після того, як розробники бічної гілки виправлять свої помилки, історія може виглядати так:

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

де C і D повинні виправити те, що було порушено в A і B, і ви, можливо, вже матимете інші зміни на магістралі після W.

Якщо об’єднати оновлену бічну гілку (з D на її кінчику), жодна з змін, внесених в А або В, не призведе до результату, оскільки їх було повернено W. Саме це побачив Алан.

Лінус пояснює ситуацію:

Повернення звичайного зобов’язання просто ефективно скасовує те, що було зроблено, і є досить простим. Але повернення комісії злиття також скасовує дані про те, що змінилася комісія, але вона абсолютно нічого не впливає на історію, яка мала об'єднання. Таким чином, злиття все ще буде існувати, і воно все ще буде розглядатися як об'єднання двох гілок разом, і майбутні злиття побачать це злиття як останнє спільне стан - і повернення, яке повернуло введене злиття, не вплине на це зовсім. Тож "повернення" скасовує зміни даних, але це дуже не так"скасувати" в тому сенсі, що він не скасовує впливу комітету на історію сховища. Тож якщо ви думаєте про "повернення" як "скасування", то ви завжди будете пропускати цю частину реверсів. Так, це скасовує дані, але ні, це не скасовує історію. У такій ситуації вам слід спочатку повернути попереднє відновлення, завдяки чому історія виглядатиме так:

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

де Y - відновлення W. Таке "повернення відновлення" може бути здійснено за допомогою:

$ git revert W Ця історія (ігнорування можливих конфліктів між тим, що W і W..Y змінилися) було б еквівалентно тому, що взагалі немає W або Y в історії:

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

і знову злиття бічної гілки не матиме конфлікту, що виникне внаслідок попереднього відновлення та відновлення повернення.

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

Звичайно, зміни, внесені в C і D, все ще можуть суперечити тому, що було зроблено будь-яким із x, але це лише звичайний конфлікт злиття.


-2

Як згадував Райан, це git revertможе ускладнити злиття в дорозі, тому git revertне може бути тим, чого ви хочете. Я виявив, що використання git reset --hard <commit-hash-prior-to-merge>команди тут буде кориснішим.

Після того як ви виконали частину жорсткого скидання, ви можете примусити натиснути на віддалену гілку, тобто git push -f <remote-name> <remote-branch-name>там, де <remote-name>її часто називають origin. З цього моменту ви можете знову злитися, якщо хочете.


4
Все, що стосується силових натискань - погана ідея, якщо ви не єдиний, хто використовує репо, і ви точно знаєте, що робите. Повернення з поверненням до git, а потім, можливо, повернення до git повернення (якщо вам потрібно повернути речі) - набагато безпечніша альтернатива.
ойвінд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.