'git pull origin mybranch' оставляет локальные коммиты mybranch N перед origin.Почему?
-
20-09-2019 - |
Вопрос
Я только что заметил кое-что странное в git pull
, чего я не понимаю.
В пятницу я работал в местном филиале.давайте назовем это mybranch
.Прежде чем покинуть офис, я отправил его в origin (который является моим репозиторием на github).: git push origin mybranch
.
Вчера дома я pull
отредактировал mybranch на моем ноутбуке, сделал еще немного кодирования, а затем отправил мои изменения обратно на 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 коммитов вперед, когда я даже не прикасался к нему на выходных, А просто извлек из origin?Поэтому я запустил git diff origin/mybranch
и различия были именно теми 6 изменениями, которые я только что извлек из remote.
Я мог только "исправить" это, запустив git fetch origin
:
From git@github.com:me/project
af8be00..88b0738 mybranch -> origin/mybranch
По-видимому, в моем локальном репозитории отсутствовали некоторые ссылочные объекты, но как это может быть?Я имею в виду, что pull уже выполняет выборку, и я не работал ни над чем, кроме этой ветки, так что git fetch origin
и git fetch origin mybranch
должен ли быть тот же результат?
Должен ли я всегда использовать git pull origin
вместо того , чтобы git pull origin branchname
?
Я в замешательстве.
Решение
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
чтобы "поступать правильно".
Другие советы
Что делает git remote -v show
возвращается, когда дело доходит до происхождения?
Если источник указывает на github, статус должен быть актуальным, а не предшествовать какому-либо удаленному репозиторию.По крайней мере, с помощью Git1.6.5, который я использую для быстрого тестирования.
В любом случае, чтобы избежать этого, явно определите удаленное репозиторий главной ветви:
$ git config branch.master.remote yourGitHubRepo.git
затем a git pull origin master
, за которым следует git status
должен вернуть чистый статус (без опережений).
Почему?потому что get fetch origin master (включенный в git pull origin master) не будет просто обновляться 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
Я добавляю модификацию к своему рабочему репозиторию, которую отправляю в репозиторий 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.
Тщательно ли вы добавляете все свои удаленные (за исключением origin
который поставляется с вашим оригинальным клоном), используя git remote add NAME URL
?Я видел эту ошибку, когда они только что были добавлены в конфигурацию git.