Czy „git fetch --tags” obejmuje „git fetch”?

270

Ładne i proste pytanie - czy funkcja „git fetch” jest ścisłym podzbiorem git fetch --tags?

To git fetch --tagsznaczy, jeśli biegnę , czy kiedykolwiek jest jakiś powód, aby natychmiast biegać od git fetchrazu?

Co z git pulli git pull --tags? Ta sama sytuacja?

davidA
źródło
11
Począwszy od Git 1..9 / 2.0 (Q1 2014), odpowiedź będzie twierdząca . Zobacz moją odpowiedź poniżej
VonC
3
Do redaktora, który „poprawił mój tekst” edycją - niekoniecznie używa się wielkich liter po myślniku lub akronimie, więc twoja edycja była gramatycznie niepoprawna, dlatego ją odrzuciłem.
davidA

Odpowiedzi:

176

Uwaga: począwszy od git 1.9 / 2.0 (Q1 2014) , git fetch --tagspobiera tagi oprócz tego, co jest pobierane przez ten sam wiersz poleceń bez opcji.

Zobacz zatwierdzenie c5a84e9 przez Michael Haggerty (mhagger) :

Poprzednio --tagsopcja pobierania „ ” była uważana za równoważną z określeniem parametru refspec

refs/tags/*:refs/tags/*

w wierszu poleceń; w szczególności spowodowało remote.<name>.refspecto zignorowanie konfiguracji.

Ale to nie jest bardzo przydatna do pobierania tagów bez pobierania również inne odniesienia, podczas gdy to jest bardzo przydatne, aby móc pobrać tagów oprócz innych odniesień.
Więc zmień semantykę tej opcji, aby zrobić to drugie.

Jeśli użytkownik chce pobrać tylko tagi, nadal można określić jawny refspec:

git fetch <remote> 'refs/tags/*:refs/tags/*'

Należy pamiętać, że dokumentacja sprzed 1.8.0.3 była niejednoznaczna co do tego aspektu fetch --tagszachowania.
Zatwierdzenie f0cb2f1 ( 14.12.2012 ) fetch --tagsspowodowało, że dokumentacja jest zgodna ze starym zachowaniem.
To zatwierdzenie zmienia dokumentację w celu dopasowania do nowego zachowania (patrz Documentation/fetch-options.txt).

Zażądaj, aby wszystkie tagi były pobierane z pilota oprócz wszystkiego, co jest pobierane .


Ponieważ Git 2.5 (Q2 2015) git pull --tagsjest bardziej niezawodny:

Zob. Zatwierdzenie 19d122b przez Paula Tana ( pyokagan) , 13 maja 2015 r.
(Scalony przez Junio ​​C Hamano - gitster- w commit cc77b99 , 22 maja 2015 r.)

pull: usuń --tagsbłąd w przypadku braku scalania kandydatów

Ponieważ 441ed41 („ git pull --tags”: błąd z lepszym komunikatem., 2007-12-28, Git 1.5.4+), git pull --tagswydrukowałby inny komunikat o błędzie, gdyby git-fetchnie zwrócił żadnych kandydatów do scalenia:

It doesn't make sense to pull all tags; you probably meant:
       git fetch --tags

Wynika to z tego, że w tym czasie git-fetch --tagszastąpiłyby wszystkie skonfigurowane parametry referencyjne, a zatem nie byłoby kandydatów do scalenia. W ten sposób wprowadzono komunikat o błędzie, aby zapobiec pomyłkom.

Jednak ponieważ c5a84e9 ( fetch --tags: pobieraj tagi oprócz innych rzeczy, 2013-10-30, Git 1.9.0+), git fetch --tagspobierałby tagi oprócz wszelkich skonfigurowanych refspecs.
Stąd, jeśli nie wystąpi żadna sytuacja kandydatów do scalenia, to nie dlatego, że --tagszostała ustawiona. W związku z tym ten specjalny komunikat o błędzie jest teraz nieistotny.

Aby uniknąć pomyłek, usuń ten komunikat o błędzie.


Z Git 2.11+ (IV kwartał 2016) git fetchjest szybszy.

Zobacz commit 5827a03 (13 października 2016 r.) Autor: Jeff King ( peff) .
(Połączone przez Junio ​​C Hamano - gitster- w commit 9fcd144 , 26 paź 2016)

fetch: użyj „szybkiego” has_sha1_filedo śledzenia tagów

Podczas pobierania ze zdalnego, który ma wiele znaczników, które nie mają znaczenia dla gałęzi, które śledzimy, marnowaliśmy zbyt wiele cykli, sprawdzając, czy obiekt wskazany przez znacznik (którego nie zamierzamy pobrać!) Istnieje w naszym repozytorium zbyt ostrożnie.

Ta łatka uczy Fetch korzystania z HAS_SHA1_QUICK w celu poświęcenia dokładności dla szybkości, w przypadkach, gdy możemy być ryzykowni przy jednoczesnym przepakowaniu.

Oto wyniki z dołączonego skryptu perf, który konfiguruje sytuację podobną do opisanej powyżej:

Test            HEAD^               HEAD
----------------------------------------------------------
5550.4: fetch   11.21(10.42+0.78)   0.08(0.04+0.02) -99.3%

Dotyczy to tylko sytuacji, gdy:

  1. Po stronie klienta masz dużo pakietów, które mogą być reprepare_packed_git()drogie (najdroższą częścią jest znalezienie duplikatów na nieposortowanej liście, która jest obecnie kwadratowa).
  2. Potrzebujesz dużej liczby odnośników do tagów po stronie serwera, które są kandydatami do automatycznego śledzenia (tzn. Których klient nie ma). Każdy wyzwala ponowne odczytanie katalogu paczki.
  3. W normalnych okolicznościach klient automatycznie śledziłby te tagi i po jednym dużym pobraniu (2) przestałby być prawdziwy.
    Ale jeśli te znaczniki wskazują na historię, która jest odłączona od tego, co klient w inny sposób pobierałby, to nigdy nie będzie automatycznie śledzić, a ci kandydaci będą wpływać na nią przy każdym pobieraniu.

Wydaje się, że Git 2.21 (luty 2019 r.) Wprowadził regresję, gdy konfiguracja nieremote.origin.fetch jest domyślna ( '+refs/heads/*:refs/remotes/origin/*')

fatal: multiple updates for ref 'refs/tags/v1.0.0' not allowed

Git 2.24 (IV kwartał 2019 r.) Dodaje kolejną optymalizację.

Zobacz commit b7e2d8b (15 września 2019) autor: Masaya Suzuki ( draftcode) .
(Połączone przez Junio ​​C Hamano - gitster- w commit 1d8b0df , 07 paź 2019)

fetch: użyj, oidsetaby zachować pożądane identyfikatory OID w celu szybszego wyszukiwania

W git fetchtym czasie klient sprawdza, czy identyfikatory OID reklamowanych tagów są już w żądanym ustawieniu OID żądania pobierania.
Ta kontrola jest wykonywana w skanie liniowym.
W przypadku repozytorium, które ma wiele referencji, powtórzenie tego skanowania zajmuje ponad 15 minut.

Aby to przyspieszyć, utwórz oid_setOID dla innych referencji.

VonC
źródło
Wątek na git-list omawia możliwość zmiany zachowania git fetch <remote> <branch>automatycznego śledzenia znaczników (ponieważ już aktualizuje zdalne śledzenie PRZECIWKO oryginalnym intencjom): public-inbox.org/git/…
ankostis
@ankostis Interesujące: jak wspomniał Junio ​​w public-inbox.org/git/… , „powrót do starego zachowania może być jedną z opcji rozwiązania problemu omawianego w tym wątku”. (ale nie zrobią tego: public-inbox.org/git/… )
VonC
Czy Git mógłby narazić użytkownika końcowego na niepotrzebną złożoność, wymagając rozległych poleceń składniowych do tego stopnia, że ​​przypominałby włamania do wykonywania typowych operacji? Nie sądzę, aby wystarczająco dużo elementów wewnętrznych wymagała jeszcze wiedzy.
John Fantastico
1
@JohnFantastico Rozumiem ten punkt widzenia. Widziałem to wcześniej: news.ycombinator.com/item?id=16587496 . Lub hackernoon.com/… („Polecenia Gita są po prostu nieszczelną abstrakcją przechowywania danych.”)
VonC
1
@Vadorequest Dziękujemy. Zaktualizowałem odpowiedź i będę obserwował listę mailingową: public-inbox.org/git/?q=fetch
VonC
131

Uwaga: ta odpowiedź jest ważna tylko dla git v1.8 i starszych.

Większość tego powiedziano w innych odpowiedziach i komentarzach, ale oto zwięzłe wyjaśnienie:

  • git fetchpobiera wszystkie nagłówki gałęzi (lub wszystkie określone przez opcję konfiguracji remote.fetch), wszystkie niezbędne dla nich zatwierdzenia i wszystkie znaczniki, które są dostępne z tych gałęzi. W większości przypadków wszystkie tagi są osiągalne w ten sposób.
  • git fetch --tagspobiera wszystkie tagi, wszystkie niezbędne dla nich zmiany. To będzie nie aktualizować głowy oddział, nawet jeśli są one dostępne z tagami, które były naciągane.

Podsumowanie: Jeśli naprawdę chcesz być na bieżąco, używając tylko pobierania, musisz wykonać obie te czynności.

Nie jest też „dwa razy wolniejszy”, chyba że chodzi o pisanie w wierszu poleceń, w którym to przypadku aliasy rozwiązują problem. Składanie dwóch próśb zasadniczo nie wiąże się z narzutami, ponieważ proszą one o inne informacje.

Cascabel
źródło
2
Dzięki za komentarz. Używam gita w Cygwin przez sieć o dużych opóźnieniach - jest dwa razy wolniejsza, gdy nie ma nic do pobrania (około 5 sekund).
davidA
Och, wow. Czy git-remote działa lepiej? Patrząc krótko na źródło, myślę, że może on wykonać tylko jedno połączenie - ale nie jestem całkowicie pewien, czy przejmie tagi niezwiązane z oddziałem. Szczerze mówiąc nie wiem, czy kiedykolwiek widziałem jakieś tagi poza gałęzią. Z rzeczami, z których czerpię, jedynym sposobem, który miałby miejsce, gdybym czekał tak długo, że przegapiłem wydanie serwisowe, wydanie funkcji i zaprzestanie konserwacji starego wydania.
Cascabel
Myślę, że problem polega na tym, że „git fetch” pobiera tylko tagi na śledzonych gałęziach. Mamy skrypt, który pozwala użytkownikom wybrać działającą gałąź, więc domyślnie istnieje wiele gałęzi, które obecnie nie są śledzone przez osobę fizyczną.
davidA
Nie próbowałem jeszcze git-remote, ale jest to na mojej stale rosnącej liście rzeczy do zrobienia :)
davidA
7
Zauważ, że git remote updatetak naprawdę nie zastępuje git fetchi git fetch --tags. git remote updatenie zaktualizuje istniejących tagów, które uległy zmianie, chociaż wprowadzi nowe tagi. git fetch --tagsAktualizuje tylko istniejące już tagi.
larsks
48

Sam odpowiem na to pytanie.

Ustaliłem, że jest różnica. „git fetch --tags” może przynieść wszystkie tagi, ale nie wprowadza żadnych nowych zatwierdzeń!

Okazuje się, że trzeba to zrobić, aby być całkowicie „aktualnym”, tj. Powielić „ściągnięcie git” bez scalenia:

$ git fetch --tags
$ git fetch

Szkoda, bo dwa razy wolniej. Gdyby tylko „git fetch” miał opcję robienia tego, co zwykle, i wprowadzania wszystkich tagów.

davidA
źródło
Interesujące, że tego nie doświadczyłem (prawdopodobnie dlatego, że moje repozytorium było aktualne w momencie mojego testu.) +1
VonC
1
Co powiesz na „ git remote update myRemoteRepo”: czy pobrałoby to zdalną treść i tagi?
VonC
1
Robię to git fetchcały czas i konsekwentnie niszczy wszelkie nowe zmiany i nowe tagi. Jaką wersję Git używasz?
Tim Visher
4
FTR, „git zdalna aktualizacja myRemoteRepo” nie działa dobrze - wydaje się, że nie robi tego, co robi „git fetch && git fetch --tags”, zwłaszcza że kolejne scalanie nie ma żadnego efektu.
davidA,
1
@TimVisher git fetchnie pobierze tagów, które nie znajdują się w dzienniku zatwierdzeń oddziału. Interfejs jQuery robi to na przykład w tagu wydania. Robimy git checkout -b temp-branch, robimy nasze wydanie, dodajemy pliki potrzebne do wydania, aktualizujemy wersję itp., A git commit -m "1.10.x" ; git tag 1.10.x; git push --tagsnastępnie usuwamy nasz lokalny oddział tymczasowy. Żadna zdalna gałąź nie osiągnie tego znacznika i git fetchnigdy go nie pobierze.
krasnolud
31

Ogólny problem polega na tym git fetch, że zostanie pobrany +refs/heads/*:refs/remotes/$remote/*. Jeśli którykolwiek z tych zatwierdzeń ma tagi, te tagi również zostaną pobrane. Jeśli jednak tagi nie są dostępne dla żadnego oddziału na pilocie, nie zostaną pobrane.

--tagsOpcja przełącza refspec do +refs/tags/*:refs/tags/*. Państwo mogłoby zapytać git fetchchwycić obie. Jestem prawie pewien, że po prostu git fetch && git fetch -tużyję następującego polecenia:

git fetch origin "+refs/heads/*:refs/remotes/origin/*" "+refs/tags/*:refs/tags/*"

A jeśli chcesz ustawić to jako domyślne dla tego repozytorium, możesz dodać drugi refspec do domyślnego pobierania:

git config --local --add remote.origin.fetch "+refs/tags/*:refs/tags/*"

Spowoduje to dodanie drugiej fetch =linii .git/configdo tego pilota.


Spędziłem trochę czasu, szukając sposobu, aby sobie z tym poradzić w projekcie. Właśnie to wymyśliłem.

git fetch -fup origin "+refs/*:refs/*"

W moim przypadku chciałem te funkcje

  • Chwyć wszystkie głowy i tagi z pilota, więc użyj refspec refs/*:refs/*
  • Zastąp lokalne oddziały i tagi szybkim przewijaniem do przodu +przed refspec
  • W razie potrzeby nadpisuj aktualnie wyewidencjonowany oddział -u
  • Usuń gałęzie i tagi, których nie ma na pilocie -p
  • I siłą być pewnym -f
gnarf
źródło
To powinna być odpowiedź.
redolent
+1 dla „ --tagsOpcja przełącza refspec na +refs/tags/*:refs/tags/*”. Chociaż man git-fetchwydaje się, że określa to refspec bez wiodącego +( refs/tags/*:refs/tags/*).
Dmitrij Minkowski
remote.origin.fetchdomyślnie +refs/heads/*:refs/remotes/origin/*, tj. +wersja, prawda? (Oznacza to, że pochodzenie / oddział zostanie nadpisane, bez względu na to, gdzie pochodzenie / oddział znajduje się teraz lokalnie.)
Robert Siemer
... a w chwili pisania tego artykułu, oprócz wszystkiego innego , git --tagspobierałem tagi . Zobacz odpowiedź @VonC.
Robert Siemer,
10

W większości sytuacji git fetchnależy zrobić, co chcesz, czyli „pobrać wszystko ze zdalnego repozytorium i umieścić w lokalnej kopii bez łączenia się z lokalnymi oddziałami”. git fetch --tagsrobi dokładnie to, poza tym, że nie otrzymuje niczego oprócz nowych tagów.

W tym sensie nie git fetch --tagsjest w żaden sposób nadzbiorem git fetch. W rzeczywistości jest dokładnie odwrotnie.

git pull, oczywiście, jest tylko opakowaniem dla git fetch <thisrefspec>; git merge. Zaleca się, aby przyzwyczaić się do prowadzenia ręcznego git fetching i git mergeing przed dokonaniem skok git pullpo prostu dlatego, że pomaga zrozumieć, co git pullrobi w pierwszej kolejności.

Biorąc to pod uwagę, związek jest dokładnie taki sam jak z git fetch. git pulljest nadzbiorem git pull --tags.

Tim Visher
źródło
1
„git pull jest nadzbiorem git pull - tagi” - ale… „git fetch” nie jest nadzbiorem „git fetch - tagi”, więc relacja nie jest dokładnie taka sama…?
davidA
9
Wystarczy znaleźć na to pytanie ... no, wydaje mi się, że git pullma nie dostać wszystkie znaczniki, ale tylko tych, osiągalny z obecnych szefów oddziałów. Jednak git pull --tagspobiera wszystkie znaczniki i jest pozornie równoważne git fetch --tags.
Archimedix
2
git fetch upstream --tags

działa dobrze, otrzyma tylko nowe tagi i nie otrzyma żadnej innej bazy kodu.

Ojczyzna
źródło
1
upstreamjest zwykle nazywany origin. Myślę, że upstreamto nazwa używana przez GitHub. W każdym razie należy użyć nazwy wyświetlanej przez git remote.
Fabio mówi Przywróć Monikę