Питання Як вирішити конфлікти злиття в Git


Чи є хороший спосіб пояснити, як вирішити конфлікти злиття в Git?


4134
2017-10-02 11:31


походження


Наступна публікація в блозі, здається, дає дуже хороший приклад того, як вирішити конфлікт з'єднання з Gіt, який повинен змусити вас йти в правильному напрямку. Обробка та уникнення конфліктів в Git - mwilliams
Ви можете налаштувати інструмент злиття (kdiff3 jebaird.com/2013/07/08/...), а потім використовуйте git mergetool. Коли ви працюєте у великих командах розробників, ви завжди стикаєтеся з конфліктами злиття. - Grady G Cooper
Не забувайте, що ви можете пом'якшити більшість конфліктів злиття шляхом регулярного злиття вниз по течії! - Ant P
Також див git-tower.com/learn/git/ebook/command-line/tools-services/... - Pacerier
Це, здається, детальний підручник - githubtraining.com/fix-merge-conflict-git-using-sourcetree - Rajavanya Subramaniyan


Відповіді:


Спробуйте: git mergetool

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

Як за @JoshGlover коментар:

Ця команда не обов'язково відкриває графічний інтерфейс, якщо ви не встановите його. Біг git mergetool для мене це призвело vimdiff використовується Замість цього ви можете встановити один із наведених нижче інструментів: meld, opendiff, kdiff3, tkdiff, xxdiff, tortoisemerge, gvimdiff, diffuse, ecmerge, p4merge, araxis, vimdiff, emerge.

Нижче наведено процедуру вибірки для використання vimdiff для вирішення конфліктів злиття. На підставі це посилання

Крок 1: Виконайте наступні команди на вашому терміналі

git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false

Це встановить vimdiff як інструмент злиття за замовчуванням.

Крок 2: Запустіть наступну команду в терміналі

git mergetool

Крок 3: Ви побачите дисплей vimdiff у наступному форматі

  +----------------------+
  |       |      |       |
  |LOCAL  |BASE  |REMOTE |
  |       |      |       |
  +----------------------+
  |      MERGED          |
  |                      |
  +----------------------+

Ці 4 перегляду є

LOCAL - це файл з поточної гілки

BASE - загальний предок, як виглядав файл перед обома змінами

REMOTE - файл, який ви об'єднуєте у свою гілку

MERGED - результат злиття, це те, що зберігається в репо

Ви можете переходити між цими переглядами за допомогою ctrl+w. Ви можете безпосередньо отримати доступ до MERGED, використовуючи ctrl+w слідує j.

Докладніше про навігацію vimdiff тут і тут

Крок 4. Ви можете редагувати представлення MERGED наступним чином

Якщо ви хочете отримати зміни з REMOTE

:diffg RE  

Якщо ви хочете отримати зміни з BASE

:diffg BA  

Якщо ви хочете отримати зміни від LOCAL

:diffg LO 

Крок 5. Зберегти, Вийти, Прийняти та очистити

:wqa зберегти і вийти з VI

git commit -m "message"

git clean Видаліть додаткові файли (наприклад, * .orig), створені інструментом diff.


2425
2017-10-02 17:50



Ви можете використовувати FYI git mergetool -y щоб зберегти декілька натискань клавіш, якщо ви об'єднуєте багато файлів одночасно. - davr
Ну, це не обов'язково відкрити графічний інтерфейс, якщо ви не встановите його. Біг git mergetool для мене це призвело vimdiff використовується Замість цього ви можете встановити один із наведених нижче інструментів: meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse ecmerge p4merge araxis vimdiff emerge. - Josh Glover
Хороший пункт Джош. У Ubuntu я мав найкращу долю з meld, його триразове злиття дисплея не погано. На GIT OSX вибрано хороший стандартний параметр. - Peter Burns
Це відкрило KDiff3. Котрий я зовсім ніяка clue як використати. - David Murdoch
Я не розумію, чому ця відповідь отримала стільки зворотного зв'язку, це не дуже корисно, оскільки воно містить лише одну команду і абсолютно не пояснює, як його використовувати. Як інші сказали, він відкрив vimdiff, і навіть якщо я знаю, як використовувати vim (перемикаю вікна принаймні або закриваю їх), я навіть не знаю, що в кожному вікні не відображається, як порівнювати чи приймати зміни. Приємно знати, є така команда, але без пояснення того, як її використовувати або інсталювати інші 3-х інструментів, це даремна відповідь - Petr


Ось ймовірний варіант використання, зверху:

Ви збираєтеся внести деякі зміни, але, ой, ви не в курсі.

git fetch origin
git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Updating a030c3a..ee25213
error: Entry 'filename.c' not uptodate. Cannot merge.

Таким чином, ви отримуєте актуальні дані та повторіть спробу, але виникне конфлікт:

git add filename.c
git commit -m "made some wild and crazy changes"
git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Auto-merging filename.c
CONFLICT (content): Merge conflict in filename.c
Automatic merge failed; fix conflicts and then commit the result.

Тому ви вирішите поглянути на зміни:

git mergetool

О, мене, о мій, вгору, змінив деякі речі, але просто використовувати мої зміни ... ні ... їх зміни ...

git checkout --ours filename.c
git checkout --theirs filename.c
git add filename.c
git commit -m "using theirs"

І тоді ми спробуємо остаточний час

git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Already up-to-date.

Та-да!


1610
2017-08-04 17:04



Це було надзвичайно корисним, тому що я мав багато помилок злиття з двоичними файлами (арт-активами), і зливання їх, здається, завжди збігається, тому мені потрібно перезаписати його новим файлом завжди, а не "зливати" - petrocket
Обережно! Значення --ours і --their змінюється. - наша == пульт дистанційного керування. --сфери == місцеві. Побачити git merge --help - mmell
У моєму випадку я підтверджую, що --theirs = віддалений сховище, --ours = мій власний локальний репозиторій. Це протилежне коментарі @mmell. - Aryo
@ммейл Тільки на ребазі, мабуть. Побачити this question - Navin
Хлопці, "наші" та "їхні" відносяться до того, чи ви об'єднуєтесь чи переробляєте. Якщо ти злиття, тоді "наша" означає галузь, з якою ви об'єднуєтеся, а "їх" це галузь, з якою ви об'єднуєтеся. Коли ви переробка, тоді "наша" означає, що ви зобов'язуєтесь перезавантажувати свій ресурс, а "їх" - це зобов'язання, які ви хочете переробити.


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

Ось декілька порад:

Порада перша

Найкраще, що я знайшов, - використовувати стиль конфлікту "diff3":

git config merge.conflictstyle diff3

Це дає такі маркери конфліктів:

<<<<<<<
Changes made on the branch that is being merged into. In most cases,
this is the branch that I have currently checked out (i.e. HEAD).
|||||||
The common ancestor version.
=======
Changes made on the branch that is being merged in. This is often a 
feature/topic branch.
>>>>>>>

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

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

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

Потім я можу запустити наступні команди, щоб побачити дві розбіжності, що викликали конфлікт:

diff common mine
diff common theirs

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

Підказка Два

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

git log --merge -p <name of file>

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

Третя порада

Підтвердьте свої зміни за допомогою автоматизованих інструментів.

Якщо у вас є автоматизовані тести, запустіть їх. Якщо у вас є лин, запустіть це. Якщо це проект, який можна побудувати, тоді створити його перед тим, як ви вчините, і т. Д. У будь-якому випадку вам потрібно трохи тестувати, щоб переконатися, що ваші зміни нічого не порушили. (Хек, навіть злиття без конфліктів може зламати робочий код.)

Підказка Четверта

Планувати заздалегідь; спілкуватися з колегами.

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

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

Для великих рефакторингів, які перетинають велику кількість кодів, ви повинні сильно вважати роботу серійним: кожен перестає працювати над тією ділянкою коду, поки одна особа виконує повне рефакторинг.

Якщо ви не можете працювати серійно (через тиск часу, може бути), тоді спілкування про очікувані конфлікти злиття принаймні допоможе вам вирішити проблеми швидше, поки деталі все ще свіжі на увазі. Наприклад, якщо співбесідник проводить порушну серію зобов'язань протягом одного тижня, ви можете вирішити об'єднати / переробляти цю філію співробітників один або два рази на день протягом цього тижня. Таким чином, якщо ви знайдете конфлікти злиття / перебазування, ви можете вирішити їх швидше, ніж якщо ви будете чекати кілька тижнів, щоб об'єднати все разом в один великий кусок.

Порада п'ять

Якщо ви не впевнені в злитті, не примушуйте це.

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

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


685
2017-09-28 21:08



Параметр diff3 є прекрасною функцією для злиття. Єдиний графічний інтерфейс, який я натрапив на це, показує, що це Perforce p4merge, який можна встановити та використовувати окремо від інших інструментів Perforce (які я не використовував, але почув скарги). - alxndr
Це найкращий підручник, який я знайшов в Інтернеті стосовно "як виправити конфлікти злиття"! - Venkat Sudheer Reddy Aedama
Ця відповідь така, що заслуговує на голосування; а не два вищезазначені, які затоплені голосами; - DJphy
Після спроби rebase, що призвело до конфлікту злиття: вихідний файл $ git log --merge -p build.xml: фатальний: - зависати без MERGE_HEAD? - Ed Randall
Що робити, якщо я змінив у одному файлі з branch1 і видалити цей файл у branch2. Як я можу вирішити цей конфлікт злиття? Чи є який-небудь спосіб використовувати git, де я можу об'єднати їх, зберігаючи зміни однієї гілки? - Honey


  1. Визначте, які файли конфліктують (Git має сказати вам це).

  2. Відкрийте кожен файл і перевірте розбіжності; Гіт демаркацію їх. Сподіваємось, буде очевидно, яка версія кожного блоку зберегти. Вам може знадобитися обговорити це з колегами-розробниками, які здійснили цей код.

  3. Після того як ви вирішите конфлікт у файлі git add the_file.

  4. Як тільки ви вирішите все конфлікти, роби git rebase --continue або будь-яка команда Гіт сказав, що робити, коли ти закінчиш.


321
2017-10-02 12:41



@Justin Подумайте про Git як стеження зміст а не відстеження файлів. Потім легко побачити вміст, який ви оновили це не так в сховище і його потрібно додати. Такий спосіб мислення також пояснює, чому Git не відстежує порожні папки: хоча вони є технічно файлами, для відстеження немає будь-якого вмісту. - Gareth
контент там, конфлікт виникає тому, що там 2 версії контенту. Тому "git add" не звучить правильно. І це не спрацює (git add, git commit), якщо ви хочете здійснити лише те, що один файл після конфлікту був вирішено ("фатальний: неможливо виконати часткове виконання під час злиття"). - Dainius
Так, технічно, це відповідає на питання, яке, як поставили запитання, але не є корисною відповіддю, на мій погляд, вибачте. Що таке? точка зробити одну галузь такою ж, як іншу? Звичайно, злиття буде мати конфлікти .. - Thufir
Тулфір: хто сказав щось про те, щоб зробити одну гілку такою ж, як іншу? Існують різні сценарії, в яких потрібно об'єднатись, без "створення однієї гілки тієї ж, як інша". Один з них - це коли ви закінчите галузь розвитку та бажаєте включити свої зміни в головний сектор; після цього галузь розвитку може бути вилучена. Інший варіант полягає в тому, що ви хочете переробити свою гілку розвитку, щоб полегшити остаточне злиття майстра. - Teemu Leisti
@ JustinGrant git add етапи файлів в індексі; це робить ні додайте щось до сховища. git commit додає речі до сховища. Це використання має сенс для злиття - об'єднання автоматично ставить всі зміни, які можна об'єднати автоматично; ви зобов'язані об'єднати решту змін і додати їх до індексу, коли ви закінчите. - Mark E. Haase


Ознайомтеся з відповідями у записі переповнення стека Переривання злиття в Git, особливо Відповідь Чарлза Бейлі який показує, як переглядати різні версії файлу з проблемами, наприклад,

# Common base version of the file.
git show :1:some_file.cpp

# 'Ours' version of the file.
git show :2:some_file.cpp

# 'Theirs' version of the file.
git show :3:some_file.cpp

97
2017-10-03 15:15



Також перевірте параметр "-m" на "git checkout -m" - це дозволяє витягнути різні мухи назад у робочу область - qneill
Це врятувало мене. Дивлячись на кожен файл окремо дозволив мені запам'ятати те, що я збираюся в кожній гілці. Потім я міг прийняти рішення вибрати. - Rohmer


Злиття конфліктів відбувається, коли одночасно внесено зміни до файлу. Ось як це вирішити.

git CLI

Ось прості кроки, що робити, коли ви потрапляєте в конфліктне стан:

  1. Зверніть увагу на список конфліктуючих файлів за допомогою: git status (під Unmerged paths розділ)
  2. Вирішуйте конфлікти окремо для кожного файлу за допомогою одного з наступних підходів:

    • Використовувати графічний інтерфейс для вирішення конфліктів: git mergetool (найпростіший спосіб).

    • Щоб прийняти віддалену / іншу версію, скористайтеся: git checkout --theirs path/file. Це відхилить всі локальні зміни, внесені вами для цього файлу.

    • Щоб прийняти місцеву / нашу версію, скористайтеся: git checkout --ours path/file

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

      Пов'язані: Який точний сенс "наших" та "їх" у гіт?

    • Редагувати конфліктуючі файли вручну і шукати кодовий блок між <<<<</>>>>> потім виберіть версію, зверху або знизу =====. Побачити: Як виникають конфлікти.

    • Конфлікт шляху та імені файлу може бути вирішено шляхом git add/git rm.

  3. Нарешті, перегляньте файли, готові для здійснення: git status.

    Якщо у вас ще є файли Unmerged paths, і ви вирішили конфлікт вручну, а потім дозвольте Гіт знати, що ви вирішили це за допомогою: git add path/file.

  4. Якщо всі конфлікти були вирішені успішно, внесіть зміни за: git commit -a і натискай на віддалений, як завжди.

Дивись також: Вирішення конфлікту злиття з командного рядка в GitHub

DiffMerge

Я успішно використовую DiffMerge який може візуально порівнювати та об'єднувати файли у Windows, MacOS та Linux / Unix.

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

DiffMerge

Джерело зображення: DiffMerge (Знімок екрана Linux)

Просто завантажте його та запустіть у репо:

git mergetool -t diffmerge .

macOS

У macOS ви можете встановити через:

brew install caskroom/cask/brew-cask
brew cask install diffmerge

І, ймовірно (якщо не надано), вам потрібна додаткова простий обгортка, поміщена у ваш PATH (наприклад, /usr/bin):

#!/bin/sh
DIFFMERGE_PATH=/Applications/DiffMerge.app
DIFFMERGE_EXE=${DIFFMERGE_PATH}/Contents/MacOS/DiffMerge
exec ${DIFFMERGE_EXE} --nosplash "$@"

Потім ви можете використовувати наступні комбінації клавіш:

  • -Альт-Вгору/Вниз щоб перейти до попередніх / наступних змін.
  • -Альт-Ліворуч/Правильно прийняти зміни зліва або справа

Ви також можете використовувати opendiff (частина Xcode Tools), яка дозволяє об'єднати два файли або каталоги разом для створення третього файлу або каталогу.


88
2017-08-05 14:29





Якщо ви часто робите невеликі копії, тоді спочатку дивіться на коментар щодо коментарів git log --merge. Потім git diff покаже вам конфлікти.

Для конфліктів, що містять більше кількох рядків, легше з'ясувати, що відбувається у зовнішньому інструменті графічного інтерфейсу. Мені подобається opendiff - Gіt також підтримує vimdiff, gvimdiff, kdiff3, tkdiff, meld, xxdiff, виходять з коробки, і ви можете встановити інші: git config merge.tool "your.tool" буде встановити ваш вибраний інструмент, а потім git mergetool після невдалого злиття ви побачите різницю в контексті.

Щоразу, коли ви редагуєте файл, щоб вирішити конфлікт, git add filename буде оновлювати індекс, і ваш розбіжність більше не відображатиметься. Коли всі конфлікти обробляються і їх файли були git add-все git commit завершить ваше злиття.


73
2017-10-02 16:11



Використання "git add" - справжній трюк тут. Можливо, ви навіть не захочете робити (може, ви хочете приховати), але вам доведеться зробити "git add" для завершення об'єднання. Я думаю, що mergetool робить для вас доповнення (хоча це не на сторінці), але якщо ви здійснюєте злиття вручну, для його завершення вам слід скористатися git add (навіть якщо ви не бажаєте робити це). - nobar