TL; DR
(Помните, что здесь задействованы два Gits. Вы вызываете одного A . С аппарата A вы можете подключиться по ssh к машине B , поэтому на машине A в хранилище вы используете удаленное имя B
, чтобы говорить о "другом Git". Между тем на машине B Вы используете удаленное имя A
, чтобы говорить о «другом Git».)
Используйте git push B master:refs/remotes/A/master
, чтобы создать или обновить фактическое имя удаленного отслеживания на A
.Используйте git push B +master:refs/remotes/A/master
, чтобы принудительно перезаписать имя удаленного отслеживания на A
(или то же самое с --force
и без знака плюс).
Вы можете использовать git push B master:A/master
для создания или обновления обычного(локальный филиал, а не имя для удаленного отслеживания) A/master
on A
.Как и прежде, вы можете добавить --force
или знак плюс к этой refspec для перезаписи.
Если вы используете remotes/A/master
, без части refs/
, это создает ветку local с именемremotes/A/master
, что я считаю плохой идеей.На компьютере A
запустите git branch
и git branch -r
, чтобы увидеть различие между именами ветвей и именами удаленного отслеживания;или используйте git for-each-ref
, чтобы выгрузить их все в полных именах.
Long
Сначала отметим, что git push
не объединяет .Как и git fetch
.Сообщение об отказе в обновлении не имеет никакого отношения к слияниям!Ваш диагноз здесь по крайней мере частично верен (в зависимости от того, что вы подразумеваете под расходятся - вы не сказали от того, что ):
... не удаетсяпотому что это приведет к расхождению рабочего дерева и индекса
Фактически, индекс и рабочее дерево останутся неизменными , и в этом проблема.
Все, что вам нужноздесь нужно сделать git push
с каким-то именем, которое не с текущим проверенным именем ветви.
Когда вы запускаете git push
, вы даете команду своему Git вызвать другой Gitобычно через https (порт 443) или ssh (порт 22) на какой-то IP-адрес.Этот другой Git является хранилищем со своими собственными ветвями.Если это репозиторий --bare
, у него есть нет рабочего дерева, и никто не может выполнять какую-либо работу в нем, поэтому он обычно принимает толчки.Если не , у него есть рабочее дерево, проиндексированное по его индексу, и кто-то может выполнять работу в нем.
Посмотрите, что за коммит равен .Каждый коммит имеет уникальный хеш-идентификатор, который в действительности соответствует настоящему, настоящему имени коммита.Каждый коммит хранит снимок всех файлов, а каждый коммит хранит метаданные о этого снимка: кто его сделал (имя и адрес электронной почты), когда (отметка времени) и почему (сообщение в журнале).Он также хранит идентификатор хеша - истинное имя - своего непосредственного родительского коммита, или, для коммитов слияния, все его родительские коммиты.
Имена ветвей в репозитории Git служат для поиска last commit в цепочке коммитов:
... <-F <-G <-H <--branch
В имени ветки хранится хеш-идентификатор commit H
.H
сам хранит хэш-идентификатор своего предшественника G
, в котором хранится другой идентификатор F
и т. Д. В истории.
Когда вы запускаете git push
, ваш Git вызывает какой-то другой Git,Затем ваш Git предлагает своим Git некоторые хеш-идентификаторы коммитов.Они либо делают имеют этот коммит - хэш-идентификаторы универсальны для всех Gits, с помощью магии криптографических контрольных сумм, либо нет.Если у них нет коммита, им нужен он (и все его файлы) и, возможно, его родительский коммит (и все файлы , которые commit) и, возможно, родительский коммит и так далее.По сути, им нужны любые коммиты, которые у вас есть, которых у них нет.Так что ваш Git предлагает им коммиты, пока их Git не скажет: «Хорошо, у меня есть этот и все предыдущие, вы можете остановиться сейчас».
Тогдаваш Git отправляет эти коммиты (и их файлы). Вот где вы видите подсчет, сжатие и запись объектов сообщений. В конце концов ваш мерзавец отправил им все, что им нужно. Если они уже имели коммиты, эта фаза вообще не отправляет данные, но независимо от того, что, в конце концов, они имеют коммиты.
Теперь ваш Git выполняет последнюю часть git push
: он вежливо просит (push без --force
) или команды (git push --force
), чтобы другой Git установил часть своей ветви имена для запоминания коммитов, которые вы только что отправили или не отправили, если они уже были.
Допустим, вы отправили им новый коммит I
, чей родитель H
:
...--F--G--H <-- branch
\
I
У них теперь есть I
, но теперь вы спрашиваете их: Установите ваше имя branch
, чтобы запомнить коммит I
вместо H
, хорошо?
Это не ОК, потому что у кого-то branch
проверено! Всем своим Git знает, что кто-то занят редактированием файлов и переключением с индексом и / или рабочим деревом и планирует сделать свой коммит J
в наносекунду или две:
...--F--G--H--J <-- branch
\
I
, который оставил бы I
все странными, или:
...--F--G--H--I--J <-- branch
, который, поскольку git push
не не выполняет слияние, делает коммит J
эффективным отмена коммит I
.
Так что их Git (который на самом деле ваш, вы просто стоите не на той стороне Интернета, пока делаете это) говорит: Нет, вы не можете сделать моим именем branch
запомни коммит J
, он занят запоминанием коммита H
пока мой пользователь работает!
Но вы можете попросить их установить, скажем, merge-me-into-branch
, имя, которого сейчас не существует. Для их Git это новое имя:
...--F--G--H <-- branch
\
I <-- merge-me-into-branch
Так что все, что вам нужно сделать, это запустить:
git push <remote-or-URL> branch:merge-me-into-branch
для создания нового имени merge-me-into-branch
в "их" Git для запоминания нового коммита I
.