'git pull origin mybranch' оставляет локальный mybranch N, опережающий origin. Зачем?

92

Я просто заметил что-то странное git pull, чего я не понимаю.

В пятницу я работал в местном филиале. давай назовем это mybranch. Перед тем как покинуть кабинет , я толкнул его происхождение (который является моим GitHub репо) git push origin mybranch.

Вчера дома я pullприкрепил свою ветку к ноутбуку, сделал еще немного кода, а затем отправил свои изменения обратно в github (origin).

Теперь я снова на работе и попытался перенести вчерашние изменения на свою рабочую машину (я ничего не менял в локальном репозитории моего рабочего места за выходные):

git pull origin mybranch

это вызвало быстрое слияние вперед, и это нормально. Затем я сделал git status, и он сказал:

# On branch mybranch
# Your branch is ahead of 'origin/mybranch' by 6 commits.
#
nothing to commit (working directory clean)

А? Как это может быть 6 коммитов вперед, если я даже не трогал их на выходных, а просто вытащил из источника? Итак, я запустил, git diff origin/mybranchи отличия были именно теми 6 изменениями, которые я только что извлек с пульта.

Я мог только "исправить" это, запустив git fetch origin:

From git@github.com:me/project
af8be00..88b0738  mybranch -> origin/mybranch

Судя по всему, в моем локальном репозитории отсутствовали некоторые ссылочные объекты, но как это могло быть? Я имею в виду, что pull уже выполняет выборку, и я не работал ни над чем, кроме этой ветки, поэтому a git fetch originи git fetch origin mybranchдолжны иметь тот же результат?

Всегда ли использовать git pull originвместо git pull origin branchname?

Я в замешательстве.

Матиас
источник
Я тоже это заметил; a git pushтакже, кажется, решает эту проблему (сообщение «все в актуальном состоянии»).
Бен Джеймс
4
git config --get-regexp br.*может сказать вам, есть ли в вашей конфигурации локальная ветка, отслеживающая другую ветку
VonC
3
Можете ли вы ввести git config branch.master.remote yourGitHubRepo.gitсвой workRepo и проверить (на следующемgit pull origin ), остается ли статус с предупреждением «впереди»?
VonC
он не установлен (пустой вывод). но git remote show originпоказывает мне, что происхождение указывает на мой репозиторий GitHub, так что, думаю, все в порядке?
Матиас
1
Одного только git remote (показывающего правильный адрес для репозитория GitHub) недостаточно . Чтобы избежать " Your branch is ahead" предупреждающего сообщения после "" git pull, вам нужно сначала также определить удаленное имя для ветви . Отсюда мое предложение: введите git config branch.master.remote yourGitHubRepo.git, затем попробуйте a git pullи a git statusи посмотрите, сохраняется ли проблема.
VonC

Ответы:

115

git pullвызывает git fetchс соответствующими параметрами перед объединением явно выбранных голов (или, если ни одна, удаленная ветвь, настроенная для слияния) в текущую ветвь.

Синтаксис: git fetch <repository> <ref>где <ref>просто имя ветки без двоеточия - это «одноразовая» выборка, которая не выполняет стандартную выборку всех отслеживаемых ветвей указанного пульта дистанционного управления, а вместо этого извлекает только названную ветвь FETCH_HEAD.

Обновление: для версий Git, начиная с 1.8.4, если есть ветка удаленного отслеживания, которая отслеживает ссылку, которую вы просили получить, теперь ветка отслеживания будет обновляться fetch. Это изменение было сделано специально, чтобы избежать путаницы, вызванной предыдущим поведением.

Когда вы выполняете git pull <repository> <ref> , FETCH_HEADобновляется, как указано выше, а затем объединяется с извлеченными, HEADно ни одна из стандартных ветвей отслеживания для удаленного репозитория не будет обновлена ​​(Git <1.8.4). Это означает, что локально похоже, что вы опережаете удаленную ветку, тогда как на самом деле вы в курсе последних событий.

Лично я всегда делаю это git fetch, git merge <remote>/<branch>потому что я вижу любые предупреждения о принудительных обновлениях перед слиянием, и я могу предварительно просмотреть то, что я сливаю. Если бы я использовал git pullнемного больше, чем я, я бы сделал простой git pullбез параметров большинство времени, опираясь на branch.<branch>.remoteи branch.<branch>.merge«делать правильные вещи».

CB Bailey
источник
4
+1 Это действительно хорошее объяснение! Я знал, что объяснение скрывалось где-то внутри «git help fetch», но не мог его достать ...
Стефан Наве
1
+1. Хороший пост, с подходом, похожим на gitster.livejournal.com/28309.html
VonC
1
Так будет ли git fetchпосле git pull <repository> <ref>устранения проблемы, поскольку выборка обновит стандартные ветки отслеживания? Кроме того, спасибо за этот ответ, начинающий
обретать
1
Я тоже столкнулся с этой проблемой, и вам нужно будет сделать, git fetchа затем git merge origin/master master.
user1027169 09
3

Что git remote -v showвозвращается, когда дело доходит до происхождения?

Если origin указывает на github, статус должен быть актуальным, а не перед удаленным репо. По крайней мере, с Git1.6.5 я использую для быстрого тестирования.

В любом случае, чтобы этого избежать, явно определите удаленное репо главной ветки:

$ git config branch.master.remote yourGitHubRepo.git

затем a git pull origin master, за которым git statusследует a, должен вернуть чистый статус (не впереди).
Зачем? потому что мастер источника получения извлечения (включенный в мастер источника извлечения git) не будет просто обновлять FETCH_HEAD(как объясняет Чарльз Бейли в своем ответе ), но он также обновит «удаленную главную ветку» в вашем локальном репозитории Git.
В этом случае ваш локальный мастер больше не будет «опережать» удаленного мастера.


Я могу проверить это с помощью git1.6.5:

Сначала я создаю рабочее репо:

PS D:\git\tests> cd pullahead
PS D:\git\tests\pullahead> git init workrepo
Initialized empty Git repository in D:/git/tests/pullahead/workrepo/.git/
PS D:\git\tests\pullahead> cd workrepo
PS D:\git\tests\pullahead\workrepo> echo firstContent > afile.txt
PS D:\git\tests\pullahead\workrepo> git add -A 
PS D:\git\tests\pullahead\workrepo> git commit -m "first commit"

Я имитирую репозиторий GitHub, создавая голое репо (которое может получать push отовсюду)

PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone --bare workrepo github

Я добавляю модификатор в свое рабочее репо, которое я нажимаю в репозиторий github (добавлен как удаленный)

PS D:\git\tests\pullahead> cd workrepo
PS D:\git\tests\pullahead\workrepo> echo aModif >> afile.txt
PS D:\git\tests\pullahead\workrepo> git ci -a -m "a modif to send to github"
PS D:\git\tests\pullahead\workrepo> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo> git push github

Я создаю домашнее репо, клонированное GitHub, в котором я вношу пару модификаций, помещенных в GitHub:

PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone github homerepo
PS D:\git\tests\pullahead> cd homerepo
PS D:\git\tests\pullahead\homerepo> type afile.txt
firstContent
aModif

PS D:\git\tests\pullahead\homerepo> echo aHomeModif1  >> afile.txt
PS D:\git\tests\pullahead\homerepo> git ci -a -m "a first home modif"
PS D:\git\tests\pullahead\homerepo> echo aHomeModif2  >> afile.txt
PS D:\git\tests\pullahead\homerepo> git ci -a -m "a second home modif"
PS D:\git\tests\pullahead\homerepo> git push github

Затем я клонирую workrepo для первого эксперимента

PS D:\git\tests\pullahead\workrepo4> cd ..
PS D:\git\tests\pullahead> git clone workrepo workrepo2
Initialized empty Git repository in D:/git/tests/pullahead/workrepo2/.git/
PS D:\git\tests\pullahead> cd workrepo2
PS D:\git\tests\pullahead\workrepo2> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo2> git pull github master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From d:/git/tests/pullahead/github
 * branch            master     -> FETCH_HEAD
Updating c2763f2..75ad279
Fast forward
 afile.txt |  Bin 46 -> 98 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)

В этом репо в git status упоминается master geing перед ' origin':

PS D:\git\tests\pullahead\workrepo5> git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
nothing to commit (working directory clean)

Но это только originне github:

PS D:\git\tests\pullahead\workrepo2> git remote -v show
github  d:/git/tests/pullahead/github (fetch)
github  d:/git/tests/pullahead/github (push)
origin  D:/git/tests/pullahead/workrepo (fetch)
origin  D:/git/tests/pullahead/workrepo (push)

Но если я повторю последовательность в репо, который имеет происхождение от github (или вообще не имеет происхождения, просто определен удаленный github), статус будет чистым:

PS D:\git\tests\pullahead\workrepo2> cd ..
PS D:\git\tests\pullahead> git clone workrepo workrepo4
PS D:\git\tests\pullahead> cd workrepo4
PS D:\git\tests\pullahead\workrepo4> git remote rm origin
PS D:\git\tests\pullahead\workrepo4> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo4> git pull github master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From d:/git/tests/pullahead/github
 * branch            master     -> FETCH_HEAD
Updating c2763f2..75ad279
Fast forward
 afile.txt |  Bin 46 -> 98 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)
PS D:\git\tests\pullahead\workrepo4> git status
# On branch master
nothing to commit (working directory clean)

Если бы я только originуказал github, statusбыло бы чисто для git1.6.5.
Это может быть с предупреждением «впереди» для более раннего git, но в любом случае, git config branch.master.remote yourGitHubRepo.gitявно определенный должен иметь возможность позаботиться об этом, даже с ранними версиями Git.

VonC
источник
Спасибо, что нашли время разобраться в этом. Исходный пульт уже указывает на мой репозиторий GitHub. Я клонировал этот проект с URL-адреса GitHub, и моя локальная главная ветвь отслеживает origin / master. Что касается mybranch, я почти уверен, что создал его из ветки origin / mybranch, которая должна отслеживать его автоматически. Но все же, может, в этом проблема? Что локальный mybranch на самом деле не отслеживает origin / mybranch? PS: я использую git 1.6.1 (через MacPorts).
Матиас
Есть ли команда git, которая позволяет мне увидеть, отслеживает ли локальная ветвь другую ветку? Я не могу найти его на страницах руководства.
Матиас
Вы можете видеть, какие удаленные ветки отслеживаются git remote show origin.
Тед Персиваль
2

Осторожно ли вы добавляете весь свой пульт (кроме того, originкоторый идет с вашим исходным клоном), используя git remote add NAME URL? Я видел эту ошибку, когда они только что добавлялись в конфигурацию git.

Пэт Нотц
источник
Я так делал при клонировании репо. Однако я не делал этого с каждой веткой. Например, для mybranch я сначала получу из origin git checkout -b mybranch origin/mybranch. Согласно странице руководства git-branch, origin / mybranch является начальной точкой, и, кроме того, в нем указано для --track: "... Используйте это, если вы всегда переходите из одной и той же восходящей ветки в новую ветвь, и если вы не хотите явно использовать «git pull <repository> <refspec>». Это поведение по умолчанию, когда начальная точка является удаленной ветвью ».
Matthias