Git - як змусити конфлікт злиття та об'єднання вручну для вибраного файлу


83

Ми підтримуємо веб-програму, яка має спільну головну гілку та безліч паралельних гілок, по одній для кожної інсталяції, кожна з яких має кілька конкретних змін. Вихідним кодом управляється в git, і це приголомшливий інструмент, коли нам потрібні функції передачі та виправлення помилок з майстер-гілки в паралельні. Але мало файлів, які є чутливими, і автоматичне злиття зазвичай дає погані результати. Тож об’єднання було б набагато простіше, якщо їх можна якось позначити, і кожне об’єднання призведе до конфлікту, що вимагає ручного об’єднання.

Я шукав відповідь:

  1. Я використовую параметри злиття --no-commit і --no-ff , але це не однаково.
  2. Тут і тут хтось задає те саме питання, але без рішення.
  3. Схоже на те, як запобігти об’єднанню файлів за допомогою .gitattributes, що містять: somefile.php merge = ours . Я спробував знайти якийсь варіант злиття, який би породив конфлікт або змусив об'єднати вручну, але поки що не знайшов жодного.
  4. .gitattributes, що містять: somefile.php -merge , ніколи не об'єднується автоматично, а отже, змушує об'єднувати вручну. Це 90% рішення, але я прагну спробувати автоматичне об’єднання та позначити його як конфліктне, незалежно від того, вдало це чи ні. Але це поки що найближче до рішення. (... дякую Чарльзу Бейлі за роз'яснення ...)
  5. Хтось пропонує запропонувати написати власний драйвер злиття ( 1 , 2 ), але як це зробити мені далеко не зрозуміло.

редагувати: варіант 4. опис


6
Це буде не точна відповідь, яку ви шукаєте, але з тієї ж причини, яку я роблю git fetchспочатку, а потім використовую git difftool <file> FETCH_HEAD, щоб я міг вручну застосувати зміну у віддаленій гілці до локальної.
MHC

MHC: це приємний трюк (особливо якщо він зберігається в сценарії для кожної паралельної гілки + у поєднанні з запобіганням автоматичному злиття файлів). Головний недолік полягає в тому, що в робочому процесі команди хтось забуває цей крок і замість цього робить звичайне злиття.
Степан

2
Налаштування -mergeне заважає вам об’єднувати файли, воно просто змушує робити це вручну, наприклад за допомогою mergetool. Хіба це не те, що вам потрібно?
CB Bailey

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

@Stepan Я потрапив у подібну ситуацію, тому хочу щось пояснити. Те, що ви говорите, що with -mergein .gitatttributes git mergeнічого не робить, і вся робота повинна бути закінчена за допомогою інструмента злиття? Тож немає <<<<< ===== >>>> для використання інструмента злиття, так? І рішення Дана це забезпечує?
Nero gris

Відповіді:


60

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

Спочатку створіть сценарій драйвера злиття з назвою merge-and-verify-driver. Зробіть його виконуваним та розмістіть у відповідному місці (можливо, ви захочете перевірити цей скрипт у репо, навіть, оскільки конфігураційний файл репо буде залежати від нього). Git збирається виконати цей сценарій оболонки, щоб виконати злиття конфіденційних файлів:

#!/bin/bash
git merge-file "${1}" "${2}" "${3}"
exit 1

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

Далі вам потрібно повідомити Git про існування власного драйвера злиття. Ви робите це у файлі конфігурації репо ( .git/config):

[merge "verify"]
        name = merge and verify driver
        driver = ./merge-and-verify-driver %A %O %B

У цьому прикладі я розмістив merge-and-verify-driverкаталог верхнього рівня репо ( ./). Вам потрібно буде вказати шлях до сценарію відповідно.

Тепер вам просто потрібно надати конфіденційним файлам належні атрибути, щоб користувацький драйвер злиття використовувався під час об’єднання цих файлів. Додайте це у свій .gitattributesфайл:

*.sensitive merge=verify

Тут я сказав Git, що будь-який файл з іменем, що відповідає шаблону, *.sensitiveповинен використовувати власний драйвер злиття. Очевидно, що вам потрібно використовувати шаблон, який відповідає вашим файлам.


Велике спасибі за цей детальний посібник!
Степан

13
Здається, драйвер злиття не називається "очевидними" рішеннями. Наприклад, якщо файл було змінено лише на одній гілці, і ви зробили злиття, "чутливий" файл буде перезаписаний, а драйвер злиття не буде викликаний. Чи є спосіб це виправити?
VitalyB

Чи справді це поводиться так, як пропонує @VitalyB? Дякую!
filippo

1
Це працює, але чи є спосіб зробити це глобальним варіантом для всіх сховищ на машині? Крім того, будь-який спосіб викликати його за допомогою командного рядка? Я хотів би, щоб був спосіб зробити це так просто, як зміна стратегії злиття в командному рядку.
user1748155

4
додавання до коментаря @VitalyB. Злиття також не відображається, якщо обидві гілки внесли однакові зміни у файл. Наприклад, обидві гілки збільшили версію на 1, а ви хотіли б збільшити на 2 при спробі об’єднати ... Дуже практична проблема, ще не вирішена. :(
VasiliNovikov

1

Ці дві команди, схоже, мають той самий ефект, що і користувальницький драйвер злиття:

git merge --no-commit your_target_branch
git checkout --conflict merge .   (do not forget the . and run it in the top dir of the repository)

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


Мені подобається ідея "одноразового" рішення (я щойно натрапив на такий випадок), однак це для мене не спрацювало. Git зробив FF, що призвело до поганого злиття (це було по суті і наше злиття).
Nero gris

@Nerogris Справді, це не буде працювати для швидкого злиття вперед. Ви завжди можете додати параметр --no-ff, але друга команда не призведе до конфлікту, оскільки в одній з двох гілок злиття немає змін від загального предка.
louisiuol

У моїй глобальній конфігурації для ff встановлено значення false. Коли я сказав, що це злиття FF, я маю на увазі, що якби я не сказав Git не робити цього, це було б.
Nero gris

0

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

git merge-fileможе використовуватися, наприклад, для ДЕКРИТУВАННЯ (та перешифрування) файлів перед злиттям (!)

У вашому випадку, закривши драйвер злиття зі статусом, що не дорівнює 0, переконайтеся, що злиття буде ручним.


2
Не могли б Ви детальніше розповісти про посилання "злиття драйвера для PO-файлів", оскільки це, здається, призводить до відмови у доступі для мене? Я сподіваюся , що це дасть відповідь на питання stackoverflow.com/questions/16214067 / ...
Мікко Rantalainen

@MikkoRantalainen заблокований на роботі, тому я спробую цього вечора вдома.
VonC

1
«Драйвер злиття для PO-файлів» у мене теж не працює :(

1
@sampablokuper Я погоджуюсь: стаття заблокована для "неавторизованого" читача. Я б не знав чому.
VonC

1
@sampablokuper Зараз у мене немає доступу до цього блогу. Я продовжуватиму шукати його зміст.
VonC
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.