Основная ветвь и "происхождение / мастер" разошлись, как "отклонить" ветки?
Каким-то образом мой мастер и моя ветвь происхождения / мастера разошлись. Я на самом деле не хочу, чтобы они расходились. Как я могу просмотреть эти различия и "объединить" их?
20 ответов
Вы можете просмотреть различия с:
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 двумя способами:
- У него другая история: B вместо A.
- Его содержание учитывает изменения как в B, так и в C; это то же самое, что и M из примера слияния.
Обратите внимание, что история C'все еще линейна.
Мы решили (на данный момент) разрешить только линейную историю в cmake.org/cmake.git
,
Этот подход сохраняет рабочий процесс на основе CVS, использованный ранее, и может облегчить переход.
Попытка вставить C'в наш репозиторий сработает (при условии, что у вас есть разрешения, и никто не выдвигал их во время перебазировки).
Команда git pull обеспечивает сокращенный способ извлечения из источника и перебазирования локальной работы над ним:
$ git pull --rebase
Это объединяет вышеупомянутые шаги извлечения и перебазирования в одну команду.
У меня было это, и я не уверен, что вызвало это, даже после прочтения вышеупомянутых ответов. Мое решение было сделать
git reset --hard origin/master
Затем это просто сбрасывает мою (локальную) копию мастера (которая, как я полагаю, облажалась) в правильную точку, представленную (удаленным) источником / мастером.
ВНИМАНИЕ: Вы потеряете все изменения, которые еще не были переданы
origin/master
,
git pull --rebase origin/master
это одна команда, которая может помочь вам большую часть времени.
Редактировать: извлекает коммиты из источника / мастера и применяет ваши изменения к недавно извлеченной истории веток.
Я считаю, что это должно было мне помочь:
git reset --hard origin/master
Но этого не произошло, как-то я получал то же сообщение, и как только я извлекал изменения из удаленной ветки, возникали конфликты. Поскольку я был уверен, что мне вообще не нужна моя существующая локальная ветка, и мне просто нужна точная копия
master
ветка с удаленного, поэтому я придумал это решение:
- Касса в новом филиале, например
git checkout -b placeholder-branch
. Примечание: эту ветку можно будет удалить позже. -
git branch -D master
, Я сделал это, так как был уверен, что моя локальная ветка облажалась, и мне это действительно не нужно, мне просто нужна новая копия с удаленного экземпляра. -
git checkout --track origin/master
и все готово, теперь вы можете удалитьplaceholder-branch
с использованиемgit branch -D
Я оказался в этой ситуации, когда попытался перебазировать ветку, которая отслеживала удаленную ветку, и пытался перебазировать ее на master. В этом сценарии, если вы попытаетесь перебазировать, вы, скорее всего, обнаружите, что ваша ветвь разошлась, и это может создать беспорядок, который не для git nubees!
Допустим, вы находитесь на ветке my_remote_tracking_branch, которая была разветвлена от master
$ git status
# На ветке my_remote_tracking_branch
нечего коммитить (рабочий каталог чистый)
И теперь вы пытаетесь сделать ребаз из мастера как:
мастер git rebase
Остановись сейчас и избавь себя от неприятностей! Вместо этого используйте слияние как:
Git Merge Master
Да, вы получите дополнительные коммиты в своей ветке. Но если вы не готовы к "не расходящимся" ветвям, это будет гораздо более плавный рабочий процесс, чем перебазирование. Смотрите этот блог для более подробного объяснения.
С другой стороны, если ваша ветвь является только локальной ветвью (то есть еще не передана на какой-либо удаленный узел), вам определенно следует выполнить ребазинг (и ваша ветвь в этом случае не будет расходиться).
Теперь, если вы читаете это, потому что вы уже находитесь в "дивергентном" сценарии из-за такой перебазировки, вы можете вернуться к последнему коммиту из источника (то есть в нерасходившемся состоянии), используя:
git reset --hard origin / my_remote_tracking_branch
В моем случае вот что я сделал, чтобы вызвать разошедшиеся сообщения: я сделал git push
но потом сделал git commit --amend
добавить что-то к сообщению фиксации. Затем я также сделал еще один коммит.
Так что в моем случае это просто означало, что origin / master устарел. Поскольку я знал, что никто не трогал происхождение / мастера, исправить это было тривиально: git push -f
(где -f
значит сила)
В моем случае я внес изменения в origin/master
и затем понял, что я не должен был делать это:-(Это было осложнено тем фактом, что локальные изменения были в поддереве. Поэтому я вернулся к последнему хорошему коммиту перед "плохими" локальными изменениями (используя SourceTree), а затем я получил "сообщение о расхождении".
После локального исправления ошибок (подробности здесь не важны) я захотел "перенести время назад" на пульт origin/master
ветвь, чтобы она была синхронизирована с местным master
снова. Решение в моем случае было:
git push origin master -f
Обратите внимание -f
(силовой) переключатель. Это удалило "плохие изменения", которые были origin/master
по ошибке и теперь локальные и удаленные филиалы синхронизированы.
Помните, что это потенциально разрушительная операция, поэтому выполняйте ее только в том случае, если вы на 100% уверены, что "возвращение" удаленного мастера во времени в порядке.
Я знаю, что здесь есть много ответов, но я думаю, 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), когда вы хотите отменить изменения в локальной фиксации. Также, когда вы хотите зафиксировать другую ветку, этот шаг следует выполнить после переключения на нужную.
Я исправил это, перейдя к commit_sha, последний привязан к origin/master.
git reset --hard commit_sha
ВНИМАНИЕ: вы потеряете все, что зафиксировано после коммита 'commit_sha'.
Чтобы увидеть различия:
git difftool --dir-diff master origin/master
Это покажет изменения или различия между двумя ветвями. В araxis (Мой любимый) он отображает его в стиле diff папки. Отображение каждого из измененных файлов. Затем я могу щелкнуть файл, чтобы просмотреть подробную информацию об изменениях в файле.
Замените 123 количеством коммитов, которые ваша ветка отклонилась от источника.
git reset HEAD~123 && git reset && git checkout . && git clean -fd && git pull
В моем случае это было вызвано невыполнением моего разрешения конфликта.
Проблема была вызвана запуском git pull
команда. Изменения в происхождении привели к конфликтам с моим локальным репо, которые я решил. Однако я их не совершал. Решение на этом этапе заключается в фиксации изменений (git commit
разрешенный файл)
Если вы также изменили некоторые файлы после разрешения конфликта, git status
Команда покажет локальные изменения как локальные изменения без этапов и разрешение слияния как локальные изменения. Это может быть правильно решено путем внесения изменений из слияния сначала git commit
затем добавление и фиксация неустановленных изменений как обычно (например, git commit -a
).
git reset --soft origin/my_remote_tracking_branch
This way you will not loose your local changes
Чтобы более прямо ответить на исходный вопрос, вы можете проверить фактические конфликтующие различия с помощью:
git diff HEAD..origin/master
и используйте эту информацию, чтобы решить, вносить ли изменения источника в локальное репо или отправлять локальные изменения в источник.
Я предпочитаю делать это более удобным и безопасным способом.
# copying your commit(s) to separate branch
git checkout <last_sync_commit>
git checkout -b temp
git cherry-pick <last_local_commit>
git checkout master
git reset --soft HEAD~1 # or how many commits you have only on local machine
git stash # safer, can be avoided using hard resetting on the above line
git pull
git cherry-pick <last_local_commit>
# deleting temporary branch
git branch -D temp
Вы можете столкнуться с этой ситуацией, только вытащите 1 историю с удаленного компьютера:
$ git pull --depth=1
fatal: refusing to merge unrelated histories
$ git status
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
Согласно приведенным выше ответам, это приведет к тому, что две ветви будут расходиться на разные «линии», поэтому Git думает, что это несвязанные истории.
---a---b---main
\ \
x x x x diverged, cannot be merged anymore
\ \
---?---?---?---c(origin/main)
И, наконец, простое решение:git reset --hard origin/main
, если вас не волнуют локальные изменения, иначе вы потеряете всю свою работу.
Или попробуйтеgit pull --depth=2
.
Я столкнулся с этой проблемой, когда создал ветку на основе ветки A от
git checkout -ba
а затем я установил восходящий поток из ветки a в исходную ветвь B с помощью
git branch -u origin/B
Затем я получил сообщение об ошибке выше.
Один из способов решить эту проблему для меня был:
- Удалить ветку a
- Создайте новую ветку b с помощью
git checkout -b b origin/B
У меня было то же самое сообщение, когда я пытался редактировать последнее сообщение о коммите, уже переданного коммита, используя git commit --amend -m "New message"
Когда я нажал на изменения, используя git push --force-with-lease repo_name branch_name
не было никаких проблем.
В моем случае я получил это сообщение, когда я переместил фиксацию X ver.1 из ветки B в ее ветку удаленного отслеживания remote_B. Затем в своем локальном репозитории я внес изменения и изменил его на ту же фиксацию, т.е. Х версия 2 .
Теперь у нас есть коммит X ver1 в удаленном репо и коммит X ver.2 в локальном. Затем git покажет вам предупреждение о том, что
Ваша локальная ветка и remote_ имеют 1 и 1 разные коммиты соответственно
чтобы решить эту проблему, у вас есть два варианта:
1. потяните изменения из ветки удаленного отслеживания.
git reset --hard HEAD
git checkout --track remoteRepoName/branch_name
2. принудительно отправьте измененную фиксацию в удаленное репо. ( Рекомендуется только в том случае, если удаленное репо никем не вытащено после нажатия фиксации X ver1 )
git push -f remote_repo_name remote_branch_name
Абсолютное решение этой проблемы:
git push -f
Эта команда отправит все ваши изменения в источник/вашу ветку. Не нужно беспокоиться, потому что все ваши коммиты, относящиеся к источнику, хранятся в вашей локальной ветке.
Отблагодаришь позже...