Насправді це не пов'язано з цією відповіддю, але я б відмовився git pull, який просто біжить git fetchза ним git merge. Ви виконуєте три злиття, які змусять ваш Git запустити три операції отримання, коли вам потрібно лише одне завантаження. Звідси:
git fetch origin # update all our origin/* remote-tracking branches
git checkout demo # if needed -- your example assumes you're on it
git merge origin/demo # if needed -- see below
git checkout master
git merge origin/master
git merge -X theirs demo # but see below
git push origin master # again, see below
Керування найскладнішим злиттям
Найцікавіша частина тут git merge -X theirs. Як зазначив root545 ,-X параметри передаються стратегії злиття, причому як recursiveстратегія за замовчуванням, так і альтернативна resolveстратегія приймають -X oursабо -X theirs(одну чи іншу, але не обидві). Однак, щоб зрозуміти, що вони роблять, вам потрібно знати, як Git знаходить та обробляє конфлікти та обробляє їх .
Конфлікт злиття може статися в якомусь файлі 1, коли базова версія відрізняється від поточної (також називається локальною, HEAD, або --ours) версії, так і від іншої (також званої віддаленою або --theirs) версії того самого файлу. Тобто злиття визначило три ревізії (три коміти): базову, нашу та їхню. Версія "base" - це основа злиття між нашим комітом та їхнім комітом, як це знайдено на графіку коміту (докладніше про це див. Інші публікації StackOverflow). Потім Git знайшов два набори змін: "що ми зробили" і "що вони зробили". Ці зміни (загалом) знаходяться у рядку за рядком, суто текстовіосновою. Git не має реального розуміння вмісту файлу; це просто порівняння кожного рядка тексту.
Ці зміни - це те, що ви бачите в git diff результатах, і, як завжди, вони також мають контекст . Можливо, речі, які ми змінили, знаходяться в різних рядках від речей, які вони змінили, так що зміни здаються такими, що вони не зіткнуться, але контекст також змінився (наприклад, через те, що наша зміна розташована близько до верхньої чи нижньої частини файлу, так що файл закінчується у нашій версії, але в їхній, вони також додали більше тексту вгорі або внизу).
Якщо зміни відбуваються на різних лініях, наприклад, ми змінюємо colorдо colourрядку 17 і вони змінюються fredв barneyна лінії 71-те немає ніякого конфлікту: Git просто приймає обидва зміни. Якщо зміни відбуваються в одних і тих же рядках, але є однаковими , Git бере одну копію зміни. Тільки якщо зміни знаходяться в одних рядках, але це різні зміни, або той особливий випадок, що заважає контексту, ви отримуєте конфлікт модифікації / модифікації.
Параметри -X oursand і -X theirsпідказують Git, як вирішити цей конфлікт, вибравши лише одну з двох змін: нашу чи їхню. Оскільки ви сказали, що об’єднуєте demo(їхнє) у master(наше) і хочете зміни від demo, ви хотіли б -X theirs.
-XОднак сліпе застосування небезпечно. Те, що наші зміни не суперечили окремо, не означає, що наші зміни насправді не суперечать! Один класичний приклад зустрічається в мовах із оголошеннями змінних. Базова версія може оголосити невикористовувану змінну:
int i;
У нашій версії ми видаляємо невикористовувану змінну, щоб зникло попередження компілятора - і у своїй версії вони додають цикл через кілька рядків пізніше, використовуючи iяк лічильник циклів. Якщо поєднати ці дві зміни, отриманий код більше не компілюється. -X варіант не допоможе, оскільки зміни входять до різних рядків .
Якщо у вас є автоматизований набір тестів, найголовніше - це запустити тести після об’єднання. Ви можете зробити це після фіксації та за потреби виправити ситуацію пізніше; або ви можете зробити це перед фіксацією, додавши --no-commitдо git mergeкоманди. Подробиці про все це ми залишимо для інших публікацій.
1 Ви також можете отримати конфлікти щодо "загальнофайлових" операцій, наприклад, можливо, ми виправляємо написання слова у файлі (щоб ми мали зміни), і вони видаляють весь файл (щоб вони мали видалити). Git не вирішить ці конфлікти самостійно, незалежно від -Xаргументів.
Роблячи менше злиттів та / або розумніші злиття та / або використовуючи перебазування
Існує три злиття в обох наших послідовностях команд. Перший - приєднати origin/demoдо локального demo(ваше використання, git pullяке, якщо ваш Git дуже старий, не зможе оновитись, origin/demoале дасть той самий кінцевий результат). Під - друге , щоб принести origin/masterв master.
Мені незрозуміло, хто оновлює demoта / або master. Якщо ви пишете свій власний код у своїй demoгілці, а інші пишуть код і штовхають його до demoгілки origin, тоді це перше крокове об’єднання може мати конфлікти або створити справжнє об’єднання. Найчастіше для поєднання роботи краще використовувати перебазування, а не об’єднання (правда, це питання смаку та думки). Якщо так, ви можете git rebaseзамість цього скористатися . З іншого боку, якщо ви ніколи не робите жодної власної комісії demo, ви навіть не робите : це перемотує вашу сторінку вперед, щоб вона відповідала оновленим потрібно в demoгалузі. Крім того, якщо ви хочете багато чого автоматизувати, але зможете ретельно перевірити, чи є коміти, зроблені вами та іншими, ви можете використовуватиgit merge --ff-only origin/demodemoorigin/demo якщо це можливо, і просто відмовити, якщо ні (тоді ви зможете перевірити два набори змін і вибрати реальне злиття або перебазування відповідно до ситуації).
Ця ж логіка застосовна і до master, хоча ви робите злиття на master , так що ви напевне потрібні master. Однак, навіть більше ймовірно, що ви хотіли б, щоб злиття не вдалося, якщо це неможливо зробити як швидке незлиття, тому це, мабуть, теж повинно бути git merge --ff-only origin/master.
Скажімо, ти ніколи не робиш власних зобов’язань demo. У цьому випадку ми можемо demoповністю відмовитись від назви :
git fetch origin # update origin/*
git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"
git merge -X theirs origin/demo || die "complex merge conflict"
git push origin master
Якщо будуть робити свої власні demoгілки фіксацій, це не корисно; Ви також можете зберегти існуюче злиття (але, можливо, додати, --ff-onlyзалежно від того, яку поведінку ви хочете), або переключити його на перебазування. Зверніть увагу, що всі три методи можуть зазнати збою: злиття може призвести до збою в результаті конфлікту, злиття з --ff-onlyне зможе перемотати вперед, а перебазування може призвести до збою в результаті конфлікту (перебазування працює, по суті, коммітування вибору вишні , яке використовує злиття машини, а отже, може виникнути конфлікт злиття).
git push -f origin master