Основная ветвь и «происхождение / мастер» разошлись, как «отклонить» ветки? - PullRequest
840 голосов
/ 16 марта 2010

Каким-то образом мой мастер и моя ветвь происхождения / мастера разошлись. Я на самом деле не хочу, чтобы они расходились. Как я могу просмотреть эти различия и объединить их?

Ответы [ 10 ]

911 голосов
/ 16 марта 2010

Вы можете просмотреть различия с:

git log HEAD..origin/master

до вытягивание (выборка + слияние) (см. Также «Как вы получаете git, всегда вытягивающий из определенной ветви?» )


Когда у вас есть сообщение вроде:

«Ваша ветка и« origin / master »разошлись, # и имеют 1 и 1 разные коммиты соответственно».

, проверьте, нужно ли обновить origin. Если origin обновлен, то некоторые коммиты были перенесены в origin из другого репо, пока вы делали свои коммиты локально.

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

Вы основали коммит C на коммите A, потому что это была последняя работа, которую вы получили из апстрима в то время.

Однако, прежде чем вы попытались вернуться к источнику, кто-то еще нажал коммит B.
История развития разошлась по отдельным путям.

Затем вы можете объединить или перебазировать. Подробнее см. Pro Git: Git Branching - Rebasing .

Слияние

Используйте команду git merge:

$ git merge origin/master

Это указывает Git интегрировать изменения из origin/master в вашу работу и создать коммит слияния.
Граф истории теперь выглядит так:

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

У нового слияния, commit M, есть два родителя, каждый из которых представляет один путь развития, который привел к содержанию, сохраненному в этом коммите.

Обратите внимание, что история M теперь нелинейна.

Rebase

Используйте команду git rebase:

$ git rebase origin/master

Это говорит Git, что нужно воспроизвести коммит C (ваша работа), как если бы вы основали его на коммите B вместо A.
Пользователи CVS и Subversion регулярно обновляют свои локальные изменения в верхней части исходной работы, когда они обновляются перед фиксацией.
Git просто добавляет явное разделение между шагами commit и rebase.

График истории теперь выглядит так:

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

Commit C '- это новый коммит, созданный командой git rebase.
Он отличается от C двумя способами:

  1. У него другая история: B вместо A.
  2. Его содержание учитывает изменения как в B, так и в C; это то же самое, что и M из примера слияния.

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

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

$ git pull --rebase

Это объединяет вышеупомянутые шаги извлечения и перебазирования в одну команду.

611 голосов
/ 12 декабря 2011

У меня было это, и я озадачен тем, что вызвало это, даже после прочтения вышеупомянутых ответов. Мое решение было сделать

git reset --hard origin/master

Тогда это просто сбрасывает мою (локальную) копию мастера (которая, как я предполагаю, облажалась) в правильную точку, как представлено (удаленным) источником / мастером.

ПРЕДУПРЕЖДЕНИЕ : Вы потеряете все изменения, которые еще не были переданы в origin/master.

44 голосов
/ 21 марта 2012
git pull --rebase origin/master 

- это одна команда, которая может помочь вам большую часть времени.

Редактировать: Извлекает коммиты из источника / мастера и применяет ваши изменения к недавно извлеченной истории ветвей.

28 голосов
/ 18 мая 2013

Я оказался в этой ситуации, когда попытался перебазировать ветвь, которая отслеживала удаленную ветку, и я пытался перебазировать ее на master. В этом сценарии, если вы попытаетесь выполнить перебазирование, вы, скорее всего, обнаружите, что ваша ветвь расходится , и это может создать беспорядок, не для мерзавцев!

Допустим, вы находитесь на ветке my_remote_tracking_branch, которая была разветвлена ​​от master

$ git status

# На ветке my_remote_tracking_branch

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

А теперь вы пытаетесь сделать ребаз из мастера как:

git rebase master

Остановись сейчас и избавь себя от неприятностей! Вместо этого используйте слияние как:

git merge master

Да, вы получите дополнительные коммиты в вашей ветке. Но если вы не хотите «не расходящихся» веток, это будет намного более плавный рабочий процесс, чем перебазирование. См. этот блог для более подробного объяснения.

С другой стороны, если ваша ветвь является только локальной ветвью (т.е. еще не отправлена ​​на какой-либо пульт), вам обязательно нужно выполнить ребазинг (и ваша ветвь не будет расходиться в данном случае).

Теперь, если вы читаете это, потому что вы уже находитесь в в «дивергентном» сценарии из-за такой перебазировки, вы можете вернуться к последнему коммиту от источника (т.е. в нерасходившемся состоянии) с помощью:

git reset --hard origin / my_remote_tracking_branch

20 голосов
/ 23 января 2013

В моем случае вот что я сделал, чтобы сообщение расходилось : я сделал git push, но затем git commit --amend добавил что-то к сообщению фиксации. Затем я также сделал еще один коммит.

Так что в моем случае это просто означало, что origin / master устарел. Поскольку я знал, что никто не касается источника / мастера, исправление было тривиальным: git push -f (где -f означает силу)

8 голосов
/ 27 июня 2016

В моем случае я поместил изменения в origin/master, а затем понял, что не должен был этого делать :-( Это было осложнено тем, что локальные изменения были в поддереве. Поэтому я вернулся к последнему правильному коммиту перед «плохими» локальными изменениями (используя SourceTree), а затем я получил «сообщение о расхождении».

После локального исправления ошибок (подробности здесь не важны) я захотел «отодвинуть назад» удаленную ветку origin/master, чтобы она снова синхронизировалась с локальной master. Решение в моем случае было:

git push origin master -f

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

Имейте в виду, что это потенциально разрушительная операция, поэтому выполняйте ее только в том случае, если вы на 100% уверены, что «откат» удаленного мастера во времени в порядке.

4 голосов
/ 22 сентября 2017

Я знаю, что здесь есть множество ответов, но я думаю, что git reset --soft HEAD~1 заслуживает некоторого внимания, потому что это позволяет вам сохранить изменения в последнем локальном (не выдвинутом) коммите при решении расхожденного состояния. Я думаю, что это более универсальное решение, чем pull с 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) , когда вы хотите отменить изменения в локальной фиксации. Также, когда вы хотите зафиксировать другую ветку, этот шаг следует выполнить после переключения на нужную.

4 голосов
/ 28 апреля 2017

Для просмотра различий:

git difftool --dir-diff master origin/master

Отобразятся изменения или различия между двумя ветвями.В araxis (Мой любимый) он отображает его в стиле diff папки.Отображение каждого из измененных файлов.Затем я могу щелкнуть файл, чтобы просмотреть подробную информацию об изменениях в файле.

3 голосов
/ 25 февраля 2015

В моем случае это было вызвано невыполнением моего разрешения конфликта.

Проблема была вызвана выполнением команды git pull. Изменения в происхождении привели к конфликтам с моим локальным репо, которые я решил. Однако я их не совершал. Решением на этом этапе является фиксация изменений (git commit разрешенный файл)

Если вы также изменили некоторые файлы после разрешения конфликта, команда git status покажет локальные изменения как локальные изменения без изменений, а разрешение слияния - как локальные изменения. Это может быть правильно решено путем фиксации изменений после слияния сначала с помощью git commit, а затем, как обычно, добавления и фиксации неотмеченных изменений (например, git commit -a).

0 голосов
/ 28 декабря 2017

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

...