Насправді це не пов'язано з цією відповіддю, але я б відмовився 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 ours
and і -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/demo
demo
origin/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