'git pull origin mybranch' оставляет локальный mybranch N коммитов раньше происхождения. Зачем? - PullRequest
91 голосов
/ 16 ноября 2009

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

В пятницу я работал в местном отделении. давайте назовем это mybranch. Перед тем как покинуть офис, я отправил его в исходное положение (это мой репозиторий 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 коммитов вперед, когда я даже не трогал их в выходные дни, а просто вытащил из источника? Итак, я запустил git diff origin/mybranch, и различия были в точности 6 изменений, которые я только что вытащил с пульта.

Я мог только "исправить" это, запустив 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?

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

Ответы [ 3 ]

113 голосов
/ 16 ноября 2009

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). Это означает, что локально он <em>выглядит , как будто вы опережаете удаленную ветвь, тогда как на самом деле вы в курсе этого.

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

3 голосов
/ 16 ноября 2009

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

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

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

$ git config branch.master.remote yourGitHubRepo.git

, затем git pull origin master, за которым следует git status, должно вернуть чистый статус (не впереди).
Зачем? потому что мастер происхождения get getch (включенный в мастер происхождения git pull) не просто обновит 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, создавая голое репо (которое может получать толчок из любого места)

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 упоминает мастер 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.

2 голосов
/ 16 ноября 2009

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

...