„git pull origin mybranch” pozostawia lokalne zobowiązanie Mybranch N przed początkiem. Czemu?

92

Właśnie zauważyłem coś dziwnego git pull , czego nie rozumiem.

W piątek pracowałem w lokalnym oddziale. nazwijmy to mybranch. Przed opuszczeniem biura pchnąłem go do źródła (czyli mojego repozytorium na githubie):git push origin mybranch .

Wczoraj w domu, ja pull ściągnąłem moją gałąź do laptopa, trochę zakodowałem, a potem przeniosłem moje zmiany z powrotem na github (pochodzenie).

Teraz znowu jestem w pracy i próbowałem przenieść zmiany z wczoraj na mój komputer roboczy (w weekend nie zmieniłem niczego w lokalnym repozytorium mojego miejsca pracy):

git pull origin mybranch

co spowodowało szybkie scalanie do przodu, co jest w porządku. Wtedy zrobiłem git statusi powiedział:

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

Co? Jak to może być 6 zatwierdzeń do przodu, skoro nawet go nie dotykałem w weekend, a po prostu wyciągałem z początku? Więc uruchomiłemgit diff origin/mybranch i różnice były dokładnie tymi 6 zmianami, które właśnie wyciągnąłem z pilota.

Mogłem to „naprawić” tylko uruchamiając git fetch origin:

From [email protected]:me/project
af8be00..88b0738  mybranch -> origin/mybranch

Najwyraźniej w moim lokalnym repozytorium brakowało niektórych obiektów referencyjnych, ale jak to możliwe? Chodzi mi o to, że ciągnięcie już pobiera, a ja nie pracowałem na niczym oprócz tej gałęzi, więc a git fetch originigit fetch origin mybranch powinien mieć ten sam wynik?

Czy powinienem zawsze używać git pull originzamiast git pull origin branchname?

Jestem zmieszany.

Matthias
źródło
Też to zauważyłem; a git pushtakże wydaje się, że rozwiązuje ten problem (raportowanie „wszystkie aktualne”).
Ben James
4
git config --get-regexp br.*może ci powiedzieć, czy twoja konfiguracja ma lokalny oddział śledzi inny oddział
VonC
3
Czy możesz wpisać git config branch.master.remote yourGitHubRepo.gitswoje workRepo i sprawdzić (przy następnym git pull origin), czy status pozostaje z ostrzeżeniem „z wyprzedzeniem”?
VonC
nie jest ustawiony (puste wyjście). ale git remote show originpokazuje mi, że początek wskazuje na moje repozytorium GitHub, więc myślę, że powinno być w porządku?
Matthias
1
Sam git remote (pokazanie właściwego adresu dla repozytorium GitHub) nie wystarczy . Aby uniknąć Your branch is aheadkomunikatu ostrzegawczego „ ” po znaku git pull, musisz najpierw zdefiniować również zdalną nazwę dla gałęzi . Stąd moja sugestia: wpisz git config branch.master.remote yourGitHubRepo.git, a następnie spróbuj a git pulli a git statusi zobacz, czy problem nadal występuje.
VonC

Odpowiedzi:

115

git pullwywołuje git fetchz odpowiednimi parametrami przed scaleniem jawnie pobranych głowic (lub, jeśli nie ma, zdalnej gałęzi skonfigurowanej do scalania) do bieżącej gałęzi.

Składnia: git fetch <repository> <ref>gdzie <ref>to tylko nazwa gałęzi bez dwukropka to pobieranie „jednorazowe”, które nie wykonuje standardowego pobierania wszystkich śledzonych gałęzi określonego pilota, ale zamiast tego pobiera tylko nazwaną gałąź doFETCH_HEAD .

Aktualizacja: dla wersji Git od 1.8.4, jeśli istnieje zdalna gałąź śledzenia, która śledzi ref, który prosiłeś o pobranie, gałąź śledzenia zostanie teraz zaktualizowana przez fetch. Ta zmiana została wprowadzona specjalnie w celu uniknięcia zamieszania spowodowanego przez poprzednie zachowanie.

Kiedy wykonujesz git pull <repository> <ref>, FETCH_HEADjest aktualizowany jak powyżej, a następnie scalany z wyewidencjonowanym plikiem, HEADale żadna ze standardowych gałęzi śledzenia dla zdalnego repozytorium nie zostanie zaktualizowana (Git <1.8.4). Oznacza to, że lokalnie wygląda na to, że wyprzedzasz zdalną gałąź, podczas gdy w rzeczywistości jesteś z nią na bieżąco.

Osobiście zawsze robię to git fetch, git merge <remote>/<branch>ponieważ widzę ostrzeżenia o wymuszonych aktualizacjach przed scaleniem i mogę wyświetlić podgląd tego, co się scalam. Gdybym użył git pulltrochę więcej niż robię, zrobiłbym zwykły git pullbez parametrów czasu, polegając na branch.<branch>.remotei branch.<branch>.merge„postępując właściwie”.

CB Bailey
źródło
4
+1 To naprawdę dobre wyjaśnienie! Wiedziałem, że wyjaśnienie kryło się gdzieś w środku „git help fetch”, ale nie mogłem go wydostać ...
Stefan Näwe
1
+1. Dobry post, z podejściem podobnym do gitster.livejournal.com/28309.html
VonC
1
Czy git fetchpo git pull <repository> <ref>rozwiązaniu problemu, ponieważ pobieranie zaktualizowałoby standardowe gałęzie śledzenia? Również dzięki za tę odpowiedź, która zaczyna mieć sens :)
Bart Jędrocha
1
Natknąłem się też na ten problem i musisz to zrobić, git fetcha następnie git merge origin/master master.
user1027169
3

Co git remote -v showzwraca, jeśli chodzi o pochodzenie?

Jeśli źródło wskazuje na github, stan powinien być aktualny i nie wyprzedzać żadnego zdalnego repozytorium. Przynajmniej z Git1.6.5 używam do szybkiego testu.

W każdym razie, aby tego uniknąć, zdefiniuj jawnie zdalne repozytorium gałęzi głównej:

$ git config branch.master.remote yourGitHubRepo.git

następnie a git pull origin master, po którym następuje a, git statuspowinny zwrócić stan czysty (nie z wyprzedzeniem).
Czemu? ponieważ wzorzec pochodzenia pobierania pobierania (zawarty w wzorcu pochodzenia git pull) nie tylko aktualizowałby FETCH_HEAD(jak wyjaśnia w swojej odpowiedzi Charles Bailey ), ale także aktualizowałby „zdalną gałąź główną” w lokalnym repozytorium Git. W takim przypadku twój lokalny master nie wydaje się już być „przed” zdalnym masterem.


Mogę to przetestować za pomocą git1.6.5:

Najpierw tworzę 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"

Symuluję repozytorium GitHub, tworząc gołe repozytorium (takie, które może otrzymywać push z dowolnego miejsca)

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

Dodaję modyfikację do mojego działającego repozytorium, którą wciskam do repozytorium github (dodanego jako zdalne)

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

Tworzę repozytorium domowe, sklonowane z GitHuba, w którym dokonuję kilku modyfikacji, wypychanych do GitHuba:

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

Następnie klonuję workrepo do pierwszego eksperymentu

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(-)

W tym repozytorium status git wspomina o masteringu przed „ 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)

Ale to tylko originnie jest 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)

Ale jeśli powtórzę sekwencję w repozytorium, które ma początek w githubie (lub w ogóle nie ma źródła, zdefiniowano tylko zdalny „github”), status jest czysty:

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)

Gdybym tylko originwskazywał na github, statusbyłby czysty dla git1.6.5.
Może to być ostrzeżenie „z wyprzedzeniem” dla wcześniejszego gita, ale tak czy inaczej, git config branch.master.remote yourGitHubRepo.gitzdefiniowany wyraźnie powinien być w stanie się tym zająć, nawet we wczesnych wersjach Gita.

VonC
źródło
Dzięki za poświęcenie czasu na przyjrzenie się temu. Pilot źródłowy już wskazuje na moje repozytorium GitHub. Sklonowałem ten projekt z adresu URL GitHub, a moja lokalna gałąź główna śledzi źródło / wzorzec. Jeśli chodzi o gałąź mybranch, jestem prawie pewien, że utworzyłem ją z gałęzi origin / mybranch, która powinna śledzić ją automatycznie. Ale nadal, może to jest problem? Że lokalna moja gałąź faktycznie nie śledzi pochodzenia / mojej gałęzi? PS: Używam git 1.6.1 (przez MacPorts).
Matthias
Czy istnieje polecenie git, które pozwala mi sprawdzić, czy lokalny oddział śledzi inny oddział? Nie mogę znaleźć tego na stronach podręcznika.
Matthias
Możesz zobaczyć, które zdalne gałęzie są śledzone git remote show origin.
Ted Percival
2

Czy starasz się dodać cały pilot (z wyjątkiem tego, originktóry jest dostarczany z oryginalnym klonem) za pomocą git remote add NAME URL? Widziałem ten błąd, kiedy właśnie zostały dodane do konfiguracji git.

Pat Notz
źródło
Zrobiłem to podczas klonowania repozytorium. Jednak nie zrobiłem tego z każdą gałęzią. Na przykład moja gałąź najpierw pobierałabym z pochodzenia git checkout -b mybranch origin/mybranch. Zgodnie ze stroną podręcznika systemowego git-branch, origin / mybranch jest punktem początkowym, a ponadto podaje --track: "... Użyj tego, jeśli zawsze przeciągasz z tej samej gałęzi upstream do nowej gałęzi i jeśli nie chcesz jawnie używać polecenia „git pull <repository> <refspec>”. To zachowanie jest domyślne, gdy punktem początkowym jest zdalna gałąź. "
Matthias