головна гілка та "походження / господар" розходяться, як "розлучити" гілки "?


964

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

Як я можу переглянути ці відмінності та "об'єднати" їх?


2
що ви маєте на увазі під розбіжністю? ви переставляєте майстра після натискання на нього?
hasen

13
Я отримую повідомлення про те, що "Ваша філія та" походження / майстер "розійшлися, # і мають 1 і 1 різні комісії (і) відповідно."
Френк

Я оновив свою відповідь, щоб відобразити це "розбіжне" попереджувальне повідомлення.
VonC

Прийнята відповідь на інше питання також може бути корисною для вирішення певних випадків, коли це може зігратись (наприклад, ви намагаєтеся перемістити свого господаря, але це вже було натиснуто): stackoverflow.com/questions/2862590/…
lindes

8
Пояснення в цьому блозі допомогло мені нескінченно більше, ніж будь-яка відповідь нижче: sebgoo.blogspot.com/2012/02/…

Відповіді:


1013

Ви можете переглянути відмінності за допомогою:

git log HEAD..origin/master

перед тим, як витягнути його (витяг + злиття) (див. також "Як отримати git, щоб завжди тягнути з певної гілки?" )


Коли у вас є повідомлення типу:

"Ваша філія та" походження / головний "розійшлися, # і мають 1 і 1 різних комітів (и) відповідно."

, перевірте, чи потрібно оновитиorigin . Якщо originоновлення оновлено, то деякі комісії були перенесені originз іншої репо, тоді як ви робили власні зобов’язання на місцевому рівні.

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \
                    C  master (your work)

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

Однак, перш ніж спробувати відштовхуватися від походження, хтось інший підштовхнув скоєння Б.
Історія розвитку розбіглася на окремі шляхи.

Потім ви можете об'єднати або відновити. Див. Розділ Pro Git: Git Branching - оприлюднення для деталей.

Злиття

Використовуйте команду git merge:

$ git merge origin/master

Це підказує Git інтегрувати зміни origin/masterу свою роботу та створити об'єднання.
Графік історії тепер виглядає так:

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \      \
                    C ---- M  master (your work)

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

Зауважимо, що історія за М тепер нелінійна.

База даних

Використовуйте команду git rebase:

$ git rebase origin/master

Це дозволяє Git відтворювати команду C (свою роботу) так, як ніби ви базували її на команді B замість А.
Користувачі CVS та Subversion регулярно переосмислюють свої локальні зміни поверх роботи вище за течією, коли вони оновлюються перед фіксацією.
Git просто додає чіткий поділ між кроками фіксації та перезавантаження.

Графік історії тепер виглядає так:

... o ---- o ---- A ---- B  origin/master (upstream work)
                          \
                           C'  master (your work)

Коміт С '- це новий коміт, створений командою gbase rebase.
Він відрізняється від C двома способами:

  1. У нього інша історія: Б замість А.
  2. Його зміст пояснює зміни як B, так і C; це те саме, що і M з прикладу злиття.

Зауважте, що історія, що стоїть за C ', все ще лінійна.
Ми вирішили (поки що) допускати лише лінійну історію в cmake.org/cmake.git.
Цей підхід забезпечує збереження робочого процесу на основі CVS, який використовувався раніше, і може полегшити перехід.
Спроба підштовхнути C 'до нашого сховища спрацює (за умови, що у вас є дозволи та ніхто не натискав, поки ви перезавантажували).

Команда git pull надає скорочений спосіб отримання з початку та відновлення локальної роботи над ним:

$ git pull --rebase

Це поєднує вищезазначені етапи отримання та перезавантаження в одну команду.


5
Я виявив це, шукаючи ту саму проблему, чи можете ви пояснити, чому "git reset --hard HEAD" не усунув проблему?
Neth

12
@Neth: тому що йдеться не про поетапні модифікації (тобто модифікації, наявні в індексі, але ще не здійснені), а про локальні коміти (що відрізняється від комітетів, присутніх на пульті). git reset --hard HEADбуде видалено лише будь-яку локальну індексовану незавершену модифікацію, і нічого не зробить для усунення відмінностей між локальними та віддаленими комісіями . Лише злиття або повторна база об'єднає два набори комітетів (локальний і віддалений) разом.
VonC

4
Нічого, дякую за цю дивовижну відповідь. Ми випадково зробили "git pull" без "--rebase", а "git rebase origin / master" - лише виправлення!
mrooney

3
Як щодо - я просто хочу ігнорувати / скидати мої локальні зміни та бути у своєму місцевому відділенні, де віддалений? Іншими словами, я хочу masterвказати Bна ваш приклад.
CygnusX1

23
@ CygnusX1 , що буде , git reset --hard origin/masterяк зазначено у відповіді трохи нижче: stackoverflow.com/a/8476004/6309
VonC

725

У мене це було і я вражений тим, що це спричинило, навіть після прочитання вищезазначених відповідей. Моє рішення було зробити

git reset --hard origin/master

Потім це просто скидає мою (локальну) копію майстра (яка, я вважаю, накручена) до правильної точки, як це представлено (віддаленим) походженням / майстром.

ПОПЕРЕДЖЕННЯ : Ви втратите всі зміни, на які ще не натиснуті origin/master.


21
так, це трохи схоже на варіант манекенів, але якщо немає реальної небезпеки, і ви тут для швидкого виправлення - це працює (для мене все одно)
PandaWood

7
Для цього потрібно бути на головній гілці раніше ("master gout checkout master").
синюватий

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

96
Ви, мабуть, повинні попередити користувачів, що це змусить їх втратити всі зміни, які ще не підштовхнулися до походження
Pedro Loureiro

6
@PedroLoureiro Комітети справді втрачені, ви все ще можете знайти ці записи git reflogабо побачити їх у gitk --all. Але все ж, звичайно, жорстке скидання - це інша річ, ніж перезавантаження.
sebkraemer

52
git pull --rebase origin/master 

це єдина команда, яка може допомогти вам більшу частину часу.

Редагувати: витягує комісії з початкового / головного та застосовує ваші зміни до нещодавно витягнутої філії історії.


89
будь ласка, згадайте, що робить команда, інакше люди можуть її виконати і в кінцевому підсумку
перекрутити

1
Якщо немає проблем, вам слід закінчити свого майстра, що містить усі зміни origin / master плюс всі ваші локальні комісії будуть відтворені поверх нього. Здається мені добре.
Філіп Класен

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

Це призводить до помилки: помилка: не вдалося об'єднати зміни. Виправлення не вдалося о 0024 Моделі запитів та відповідей
ІгорГанапольський

32

Я опинився в цій ситуації, коли я намагався відновити повторно гілку, яка відстежувала віддалену гілку, і я намагався відновити її на master. У цьому випадку, якщо ви спробуєте зробити перезавантаження, ви, швидше за все, виявите, що ваша філія розбіжна, і це може створити безлад, який не стосується git nubees!

Скажімо, ви перебуваєте на гілці my_remote_tracking_branch, яка була розгалужена від головного

$ git status

# На гілці my_remote_tracking_branch

нічого не робити (чистий робочий каталог)

А тепер ви намагаєтеся перезавантажити майстер як:

git rebase master

СТОПУЙТЕ ЗАРАЗ і вбережіть собі неприємності! Замість цього використовуйте об'єднання як:

git merge master

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

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

Тепер, якщо ви читаєте це, тому що ви вже знаходитесь в "розбіжному" сценарії через таке перезавантаження, ви можете повернутися до останнього комітету з початку (тобто в нерозбіжному стані), використовуючи:

git reset - жорстке походження / my_remote_tracking_branch


5
Основне правило - це використання, rebaseякщо гілка, яку ви поновлюєте, не була опублікована (і використовується іншими людьми). В іншому випадку використовуйте merge. Якщо ви перезавантажуєте вже опубліковані (і використовувані) гілки, вам потрібно узгодити змову, щоб переписати історію для кожного розробника, який використовував вашу гілку.
Мікко Ранталайнен

1
На жаль, я не прочитав це повідомлення, перш ніж робити git rebase master...
Віталій Ісаєв

Якщо я виконую git rebase master, перебуваючи на гілці 'foobar', то технічно foobar відхиляється від походження / foobar, поки я не виконую git push -f, правда?
реліп


1
git reset --hard origin/my_remote_tracking_branchце те, що справді працювало
roothahn

24

У моєму випадку ось що я зробив, щоб викликати розбіжне повідомлення: я це зробив, git pushале потім зробив, git commit --amendщоб додати щось до повідомлення про фіксацію. Тоді я теж зробив ще один вчинок.

Тож у моєму випадку це просто означало походження / майстер застаріло. Оскільки я знав, що ніхто більше не торкається походження / господаря, виправлення було тривіальним: git push -f (де -fозначає силу)


8
+1 для того, git push -fщоб перезаписати зміни, які раніше були здійснені та натиснуті на початкове. Я також впевнений, що ніхто не торкнувся сховища.
зачардл

4
Дуже ризикована команда. Будь ласка, напишіть коротку інформацію про коефіцієнт ризику команди.
J4cK

1
@Trickster: Я вже описував ризик: "як я знав, ніхто більше не торкається походження / господаря". Я вважаю, що в цьому випадку це не ризикована команда.
Даррен Кук

1
Якщо хтось бере на себе майстер, а потім одна людина виконує команду git push -f, це команда з високим ризиком
J4cK

11

У моєму випадку я підштовхнув зміни, origin/masterа потім зрозумів, що не повинен був цього робити :-( Це ускладнювалося тим, що локальні зміни були в нижньому дереві. Тому я повернувся до останнього доброго завдання перед "поганим" місцевим зміни (використовуючи SourceTree), і тоді я отримав "повідомлення про розбіжність".

Після виправлення мого безладу локально (деталі тут не важливі) я хотів "перенести назад у часі" віддалену origin/masterгілку, щоб вона знову синхронізувалася з локальною master. У моєму випадку рішення було:

git push origin master -f

Зверніть увагу на -f(силовий) вимикач. Це видалило «погані зміни», які були підштовхнуті origin/masterпомилково, і тепер локальні та віддалені гілки синхронізуються.

Будь ласка, майте на увазі, що це потенційно руйнівна операція, тому виконайте її лише в тому випадку, якщо ви на 100% впевнені в тому, що вчасно повернути віддаленого майстра.


Завжди корисний, але точно не відповідає на питання.
Тібо Д.

1
@ThibaultD. навіть якщо цього не сталося, саме це я шукав.
Ніл Чоуддурі

Я отримую You are not allowed to force push code to a protected branch on this project.. Я намагаюся натиснути на вилку.
BanAnanas

Я повинен був зняти захист на gitlab репо stackoverflow.com/questions/32246503 / ...
BanAnanas

5

Я знаю, що тут є багато відповідей, але я думаю git reset --soft HEAD~1, що це заслуговує на певну увагу, тому що це дозволяє вам зберігати зміни в останньому локальному (не підштовхуваному) введенні під час вирішення розбіжного стану. Я думаю, що це є більш універсальним рішенням, ніж "тягнути" rebase, тому що місцевий комітет можна переглянути і навіть перенести в іншу галузь.

Ключ використовується --soft, замість різкого --hard. Якщо є більше 1 коміти, варіація HEAD~xповинна працювати. Ось ось усі кроки, які вирішили мою ситуацію (у мене було 1 місцеве зобов’язання і 8 віддалених передач):

1) git reset --soft HEAD~1 скасувати локальну комісію. Для наступних кроків я використовував інтерфейс у SourceTree, але, думаю, наступні команди також повинні працювати:

2) git stash приховувати зміни з 1). Тепер усі зміни безпечні і розбіжностей вже немає.

3) git pull отримати віддалені зміни.

4) git stash pop або git stash applyзастосувати останні заховані зміни з подальшим новим зобов’язанням, якщо потрібно. Цей крок є необов’язковим, поряд із 2) , коли потрібно змінити зміни в локальній комісії. Крім того, коли потрібно скористатися іншою гілкою, цей крок слід зробити після переходу на потрібну.


Насправді, в ці дні, pull --rebaseвсе одно автоматично буде сховатися. stackoverflow.com/a/30209750/6309
VonC

4

Щоб переглянути відмінності:

git difftool --dir-diff master origin/master

Це відобразить зміни або відмінності між двома гілками. У програмі araxis (Мій улюблений) він відображає його у стилі різної папки. Показ кожного із змінених файлів. Потім я можу натиснути на файл, щоб переглянути деталі змін у файлі.


1
Цікаве використання git-dir: +1
VonC

3

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

Проблема була викликана запуском git pullкоманди. Зміни в походженні призвели до конфліктів з моїм місцевим репо, яке я вирішив. Однак я їх не вчиняв. На даний момент рішенням є внесення змін ( git commitвирішений файл)

Якщо ви також змінили деякі файли з моменту вирішення конфлікту, git statusкоманда покаже локальні модифікації як нестандартні локальні модифікації, а дозвіл злиття - як поетапні локальні модифікації. Це можна правильно вирішити, спершу git commitвнісши зміни в об'єднанні , а потім додавши та здійснивши нестандартні зміни, як зазвичай (наприклад, від git commit -a).


0

У мене було те саме повідомлення, коли я намагався редагувати останнє повідомлення про фіксацію, про вже натиснуте фіксування, використовуючи: git commit --amend -m "New message" Коли я натискав зміни, використовуючи, проблем git push --force-with-lease repo_name branch_name не було.


0

З цією проблемою зіткнувся, коли створив філію на основі гілки A by

git checkout -b a

а потім я встановив потік вгору гілки a до початкової гілки B

git branch -u origin/B

Тоді я отримав повідомлення про помилку вище.

Одним із способів вирішити цю проблему для мене було:

  • Видаліть гілку a
  • Створіть нову гілку b by
git checkout -b b origin/B
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.