Випуск Git злиття


183

Візьміть такий випадок:

У мене є робота в тематичній галузі, і тепер я готовий знову об'єднатись до майстра:

* eb3b733 3     [master] [origin/master]
| * b62cae6 2   [topic]
|/  
* 38abeae 1

Я виконую злиття від майстра, вирішую конфлікти і тепер маю:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | eb3b733 3                     [origin/master]
|/  
* 38abeae 1

Тепер, злиття зайняло у мене деякий час, тож я роблю ще один збір і помічаю, що віддалене відділення головного виконавця має нові зміни:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
| | * e7affba 4                   [origin/master]
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

Якщо я спробую 'git rebase origin / master' від master, я змушений знову вирішити всі конфлікти, а також втрачую прив'язку:

* d4de423 2       [master]
* e7affba 4       [origin/master]
* eb3b733 3
| * b62cae6 2     [topic]
|/  
* 38abeae 1

Чи є чистий спосіб перезавантажити об'єкт злиття, щоб я закінчив історію, подібну до тієї, яку я показую нижче?

*   51984c7 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | e7affba 4                     [origin/master]
* | eb3b733 3
|/  
* 38abeae 1

74
TL; DR:git rebase --preserve-merges origin/master
Ilia K.

6
Що стосується необхідності повторного вирішення конфліктів, ви можете поглянути на git rerere .
Паркер Коутс

git config --global pull.rebase preserve завжди зберігати злиття, здійснені під час
ребазування

4
Попередження: починаючи з Git 2.18 (Q2 2018, 5 років пізніше), git --rebase-mergesврешті-решт замінить старе git --preserve-merges. Подивіться, що саме робить " rebase --preserve-merges" (і чому?)
Гіта

1
--preserve-mergesзастаріло. Використанняgit rebase --rebase-merges origin/master
Арджун

Відповіді:


127

Тут є два варіанти.

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

Інша полягає у використанні --rebase-mergesопції « Увімкнути» git rebase, яка описана у посібнику: «За замовчуванням ребаза просто випаде з об'єднаних комітетів зі списку todo, а перезавантажені комісії - в єдину лінійну гілку. З --rebase- злиття, замість цього база даних намагатиметься зберегти структуру розгалуження в межах комітетів, які підлягають відновленню, шляхом відтворення об'єднаних комісій. Будь-які вирішені конфлікти злиття або поправки вручну в цих комісіях об'єднання доведеться вирішувати / повторно застосовувати вручну. "


16
Я спробував параметр -p, і він дійсно залишає історію фіксації так, як я хотів, але це змушує мене знову вирішувати конфлікти, навіть у файлах, які не були відредаговані в початковому / ведучому. Що стосується Вашої першої пропозиції, якою буде точна послідовність команд?
jipumarino

2
@jipumarino: git rebase -i (скажіть йому, щоб відредагувати комісію злиття), коли вона дістається до комісії злиття, git reset - тверда голова ^, git merge, виправлення конфліктів, git commit, git rebase --continue. Ви також можете поглянути на git rerere, який повинен допомогти у подібних речах (але я ніколи не користувався, тому не можу запропонувати жодних порад чи допомоги).
siride

2
Дякую. Я ввімкнув rerere і спробував з rebase -p, і він працює як слід.
jipumarino

3
Ось чудовий пост у блозі, що описує таку точну ситуацію: звільнення об'єднань у Git
kynan,

1
rere - це не рішення, тому що вам доведеться вирішувати злиття вперше вручну.
Flimm

29

Гаразд, це давнє запитання, і на нього вже прийняли відповідь @siride, але в моєму випадку ця відповідь виявилася недостатньою, оскільки --preserve-mergesзмушує вас вирішити всі конфлікти вдруге. Моє рішення засноване на ідеї, @Tobi Bале з точними покроковими командами

Тож ми почнемо з такого стану, грунтуючись на прикладі запитання:

*   8101fe3 Merge branch 'topic'  [HEAD -> master]
|\  
| * b62cae6 2                     [topic]
| |
| | * f5a7ca8 5                   [origin/master]
| | * e7affba 4
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

Зауважте, що у нас на 2 майстри попереду майстер, тому вишня вибору не буде працювати.

  1. Перш за все, давайте створимо правильну історію, яку ми хочемо:

    git checkout -b correct-history # create new branch to save master for future
    git rebase --strategy=ours --preserve-merges origin/master
    

    Ми використовуємо --preserve-mergesдля збереження в історії об'єднання. Ми --strategy=oursігноруємо всі конфлікти злиття, оскільки нам не байдуже, який вміст буде в цьому об'єкті злиття, нам потрібна лише приємна історія.

    Історія виглядатиме так (ігноруючи майстра):

    *   51984c7 Merge branch 'topic'  [HEAD -> correct-history]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
  2. Давайте тепер отримаємо правильний індекс.

    git checkout master # return to our master branch
    git merge origin/master # merge origin/master on top of our master
    

    Ми можемо отримати деякі додаткові злиття конфліктів тут, але це буде тільки конфлікти з файлів змінилися між 8101fe3і f5a7ca8, але не включає в себе вже вирішені конфлікти зtopic

    Історія виглядатиме так (ігноруючи коректну історію):

    *   94f1484 Merge branch 'origin/master'  [HEAD -> master]
    |\  
    * | f5a7ca8 5                   [origin/master]
    * | e7affba 4
    | *   8101fe3 Merge branch 'topic'
    | |\  
    | | * b62cae6 2                     [topic]
    |/ /
    * / eb3b733 3
    |/  
    * 38abeae 1
    
  3. Останнім етапом є поєднання нашої гілки з правильною історією та відділення з правильним індексом

    git reset --soft correct-history
    git commit --amend
    

    Ми використовуємо reset --softдля скидання нашої гілки (та історії) на корекційну історію, але залишаємо індекс і робоче дерево таким, яким є. Тоді ми використовуємо commit --amendдля того, щоб переписати нашу команду злиття, яка раніше мала неправильний індекс, з нашим добрим індексом від головного.

    Зрештою, у нас буде такий стан (відзначте ще один ідентифікатор верхньої комісії):

    *   13e6d03 Merge branch 'topic'  [HEAD -> master]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    

Це приголомшливо і дуже допомогло! Але я не зрозумів хитрість у команді -мен: ви могли б додати більше інформації про це? Що саме відбувається після запуску - я помітив, що SHA прихильності змінився - але чому? Або що станеться, якщо ви цього не запустите?
ZenJ

1
@ZenJ git commit --amendдодає зміни до останнього комітету (HEAD, у цьому випадку - об'єднання). Оскільки вміст фіксації змінюється, хеш оновлюється.
Dries Staelens

1
Для людей, які не ввімкнули "повторно" до виправлення конфліктів, це рішення чудово, оскільки позбавить вас від необхідності виправляти конфлікти знову. Дякую!
Шеклфорд

6

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

У нас є велика база коду, і нам доводиться мати справу з 2-ма гілками, які сильно змінюються одночасно. Є головна гілка та вторинна гілка, якщо ти яка.

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

Тому мені потрібно "переобладнати" моє "об'єднання".

Ось як ми нарешті це зробили:

1) зробити помітку SHA. напр .: c4a924d458ea0629c0d694f1b9e9576a3ecf506b

git log -1

2) Створіть належну історію, але це порушить злиття.

git rebase -s ours --preserve-merges origin/master

3) зробити помітку SHA. напр .: 29dd8101d78

git log -1

4) Тепер скиньте туди, де ви були раніше

git reset c4a924d458ea0629c0d694f1b9e9576a3ecf506b --hard

5) Тепер об'єднайте поточного майстра у свою робочу гілку

git merge origin/master
git mergetool
git commit -m"correct files

6) Тепер, коли у вас є правильні файли, але неправильна історія, отримайте потрібну історію поверх змін:

git reset 29dd8101d78 --soft

7) А потім --зменшіть результати в початковому документі злиття

git commit --amend

Вуаля!


1

Схоже, що ви хочете зробити, це зняти перше злиття. Ви можете дотримуватися наступної процедури:

git checkout master      # Let's make sure we are on master branch
git reset --hard master~ # Let's get back to master before the merge
git pull                 # or git merge remote/master
git merge topic

Це дасть вам те, що ви хочете.


4
Якщо ввімкнено повторне оновлення, це, здається, дає такий же результат, як і рішення rebase -p, подане вище Siride.
jipumarino

0
  • Від вашої злиття
  • Вишні виберіть нову зміну, яка повинна бути легкою
  • скопіюйте свої речі
  • повторити злиття та вирішити конфлікти, просто скопіювавши файли з локальної копії;)

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