'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.