'git pull origin mybranch' оставляет локальный mybranch N, фиксируется до начала. Зачем?

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

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

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

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

git pull origin mybranch

что вызвало ускоренное слияние, что хорошо. Затем я сделал a 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 [email protected]:me/project
af8be00..88b0738  mybranch -> origin/mybranch

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

Должен ли я всегда использовать git pull origin вместо git pull origin branchname?

Я смущен.

Ответ 1

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 на "правильную вещь".

Ответ 2

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

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

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

$ git config branch.master.remote yourGitHubRepo.git

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


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

Сначала создаю workrepo:

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

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

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 упоминает мастер-привязку впереди "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, но в любом случае a git config branch.master.remote yourGitHubRepo.git, явно заданный явно, должен быть в состоянии позаботиться об этом даже в ранних версиях Git.

Ответ 3

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