Git-Checkout znacznik zdalny, gdy dwa piloty mają tę samą nazwę znacznika

Miałem nadzieję, że to zadziała:

git checkout remote/tag_name

Ale tak nie jest. to tak:

git checkout tags/tag_name

Ale robię coś dziwnego, gdzie mam dużo pilotów, i martwię się o to, co się stanie, jeśli dwa piloty mają ten sam znacznik. Czy istnieje sposób na określenie pilota podczas sprawdzania tagu?

4 answers

Streszczenie: to, co chcesz osiągnąć, jest możliwe, ale najpierw musisz wymyślić zdalne tagi.

Robisz to za pomocą serii refspeców, po jednym dla każdego pilota. Reszta dotyczy tego, czym one są, jak działają i tak dalej.


Twoje pytanie pyta o sprawdzenie "zdalnego tagu", ale Git nie ma ma zdalnych tagów, a to:

Ale robię coś dziwnego, gdzie mam dużo pilotów i martwię się o to, co dzieje się, jeśli dwa piloty mają ten sam znacznik. Czy istnieje sposób na określenie pilota podczas sprawdzania tagu?

Ujawnia (myślę) źródło twojego zamieszania.

Cofnijmy się na chwilę i po prostu porozmawiajmy o tym, co Git ma w ogólnym sensie, które są "odniesieniami". Aby wesprzeć ten pomysł, konkretne formularze odniesień obejmują nazwy lokalnych oddziałów (master, devel, feature, i tak dalej), "nazwy gałęzi zdalnych" jak origin/master i stuff_from_bobs_computer/master oraz nazwy znaczników. Rzeczy podobnie jak "stash" Gita również używa odniesień, a nawet HEAD jest odniesieniem, choć jest to bardzo specjalne i zazwyczaj "symboliczne" odniesienie. Chodzi o to, że Git ma wiele form odniesień i wszystkie one naprawdę działają w ten sam sposób w końcu: nazwa odniesienia rozwiązuje, w końcu, jedną z tych dużych wartości SHA-1, 676699a0e0cdfd97521f3524c763222f1c30a094 lub cokolwiek innego.

Większość referencji-wyjątkami są rzeczy takie jak HEAD, ORIG_HEAD, MERGE_HEAD, i kilka innych wzdłuż tych linii-są faktycznie pisane nazwami, które zacznij od refs/. Są one przechowywane w strukturze przypominającej katalog lub folder,1 z podkatalogami: refs/tags/ zawiera Twoje tagi,2refs/heads/ zawiera wszystkie gałęzie, a refs/remotes/ zawiera wszystkie gałęzie zdalne.

Zdalne gałęzie są dalej podzielone przez nazwę zdalnego: refs/remotes/origin/ zawiera wszystkie origin zdalne gałęzie, podczas gdy refs/remotes/stuff_from_bobs_computer/ zawiera wszystkie stuff_from_bobs_computer zdalne gałęzie. Jeśli masz dużo pilotów, masz wiele podkatalogów wewnątrz refs/remotes/.

Właśnie wspomniałem, że Twoje tagi są w refs/tags/. A co z tagami pilotów, wszystkimi tagami na różnych pilotach? Cóż, ponownie, git nie ma "zdalnych tagów". Git ma "zdalne gałęzie" , ale w rzeczywistości wszystkie są lokalne. Są one przechowywane w Twoim repozytorium, pod nagłówkiem refs/remotes/.

Kiedy Twój Git kontaktuje się z "zdalnym" - zwykle przez git fetch remote, ale także przez push (i początkowy clone krok, o to chodzi), Twój Git pyta zdalnego Git3 pytanie: "Jakie lokalne oddziały masz? Jakie są ich wartości SHA-1?"Tak właśnie działa fetch: jako uproszczony opis, proces pobierania polega na pytaniu zdalnego Gita" Hej, co masz?"i daje Ci zestaw nazw i SHA-1S. Twój Git następnie sprawdza czy ma te same SHA-1s. jeśli tak, rozmowa jest zakończona; jeśli nie, twój Git wtedy mówi" OK, potrzebuję tego co jest w commicie(s) dla tych SHA-1s", który okazuje się być kolejną grupą SHA-1s, a Twój Git i ich Git rozmawiają nad tym, aby dowiedzieć się, które pliki i takie, których potrzebujesz, a także, wszystkie zidentyfikowane przez SHA-1s. Twój Git przenosi te obiekty i wpycha nowe SHA-1s do twojego refs/remotes/, pod nazwą zdalnego, a następnie pod ich lokalnymi nazwami gałęzi.

Jeśli poprosisz o tagi ze swoim fetch, Twój Git zrobi trochę więcej.4 zamiast po prostu pytać ich Git o ich gałęzie, Twój Git również pyta ich również o ich tagi. Ponownie, ich Git po prostu daje listę nazw i SHA-1S. Twój Git następnie przenosi wszystkie potrzebne obiekty, a następnie-oto klucz do całego problemu-to zapisuje ich nazwy znaczników do twojego refs/tags/.

Więc, co się stanie, gdy przejdziesz do zdalnego origin i poprosisz go o tagi, i powie "Mam refs/tags/pinky i refs/tags/brain", jest to, że tworzy to dla Ciebie lokalne tagi pinky i brain, również nazwane refs/tags/pinky i refs/tags/brain w Twoim odnośniku przestrzeń nazw.

Teraz idź do komputera Boba (pilota o nazwie stuff_from_bobs_computer powyżej) i poproś go o tagi. Interesuje się neurologią, a nie neurologią. jego znaczniki to refs/tags/spinal_cord i refs/tags/brain, a drugi prawdopodobnie nie jest spokrewniony z tym na origin. Uh oh!

Dokładnie to, co się tutaj dzieje, staje się trochę skomplikowane,5 ale krótko mówiąc, jest to po prostu zła sytuacja i prawdopodobnie powinieneś tego unikać, jeśli to możliwe. Istnieją dwa łatwe (ok...) sposoby na unikaj tego. Jednym z nich, z oczywistą wadą, jest: po prostu nie dostać ich tagi. Wtedy nie będzie żadnych konfliktów tagów. Druga to: trzymaj wszystkie znaczniki oddzielone od siebie (a może i od twoich). Okazuje się, że ta druga nie jest aż tak trudna. Musisz tylko "wymyślić" zdalne tagi.

Rzućmy okiem na to, jak Git faktycznie implementuje "zdalne gałęzie" i jak działa fetch --tags. Oba używają tego samego podstawowego mechanizmu, co Git nazywa "refspecs".

W swojej najprostszej formie refspec wygląda jak dwie nazwy ref z dwukropkiem między nimi: refs/heads/master:refs/heads/master, na przykład. W rzeczywistości, możesz nawet pominąć refs/heads/ i Git umieści go za Ciebie,6 czasami można pominąć dwukropek i powtórzone imię. To jest coś, czego używasz z git push: git push origin branch oznacza naciśnięcie na origin, używając swojego refs/heads/branch, i nazwanie go refs/heads/branch, gdy pojawi się również na "ich" gitu.

Dla fetch, choć, wykonując zdalne gałęzie, otrzymujesz refspec, który wygląda tak:

+refs/heads/*:refs/remotes/origin/*

+ Z przodu oznacza "siłę", a *robią oczywistą rzecz. Twój Git rozmawia z ich i dostaje listę referentów. Te, które pasują refs/heads/*, Twoje przynosi (wraz z ich obiektami repozytorium w razie potrzeby) - ale potem umieszcza je w Twoje repo pod nazwami patrząc z refs/remotes/origin/, a teraz masz wszystkie "odległe gałęzie" z origin.7

Kiedy biegniesz git fetch --tags, Twój git dodaje +refs/tags/*:refs/tags/* do refspeców, których używa.8 to przynosi ich tagi i umieszcza je w lokalnych tagach. Więc wszystko, co musisz zrobić, to dać fetch refspec, który wygląda następująco:

+refs/tags/*:refs/rtags/origin/*

I nagle pojawi się zupełnie nowa nazwa-przestrzeń" remote tags " pod refs/rtags/ (tylko dla origin, w tym przypadku). Można bezpiecznie używać znacznika + force-flag, ponieważ właśnie aktualizujesz kopię ich tagów: jeśli przenieśli (lub usunęli i utworzyli na nowo) znacznik, wymuszasz przeniesienie swojego znacznika przyjąłem. Możesz również chcieć lub nawet potrzebować --no-tags zachowania, które możesz uzyskać, podając --no-tags w wierszu poleceń, lub, cóż, Zobacz następny akapit.

Jedynym przydatnym elementem jest to, że git fetch pobiera domyślne refspecs, dla dowolnego zdalnego, z pliku konfiguracyjnego Git.9 jeśli sprawdzisz swój plik konfiguracyjny Git, zobaczysz fetch = linię pod każdym zdalnym pilotem, używając +refs/heads/*:refs/remotes/remote-name/* string. Możesz mieć tyle linii fetch =, ile chcesz na pilota, więc możesz dodać jedną do przynieś ich znaczniki, ale umieść je w nowo wynalezionej przestrzeni nazw "Remote tags". Możesz również ustawić --no-tags jako domyślny dla tego pilota, ustawiając tagOpt = --no-tags w tej samej sekcji. Zobacz ten komentarz użytkownika user200783 po szczegóły.

Tak jak w przypadku wszystkich komend Gita, które rozwiązują nazwę do surowego SHA - 1, możesz git checkout poprzez pełną nazwę ref-name przejść do trybu "odłączona głowa" na odpowiednim SHA-1:

git checkout refs/rtag/stuff_from_bobs_computer/spinal_cord

Ponieważ Git nie ma pojęcia " Remote tags" wbudowany, musisz przeliterować długi formularz (zobacz gitrevisions po szczegóły).


1w rzeczywistości jest to prawdziwy katalog, w .git/refs. Jednak istnieje również "spakowana" forma dla refów, która kończy się w .git/packed-refs. Spakowana forma ma na celu zaoszczędzenie czasu i wysiłku z refami, które nie zmieniają się często(lub w ogóle, jak to ma miejsce w przypadku tagów). Trwają również starania o przepisanie" back-endowego " systemu przechowywania referencji, więc w pewnym momencie wiele z tego może zmiana. Ta zmiana jest potrzebna dla Systemów Windows i Mac. Git uważa, że nazwy branch i tagów uwzględniają wielkość liter: że możesz mieć branch polish dla Twojego materiału na buty i Polish dla Twoich kiełbasek. Wersje spakowane uwzględniające wielkość liter, więc to działa; ale wersje przechowywane w plikach czasami nie są , więc tak nie jest!

2omawiam tutaj różnicę między znacznikami lekkimi i z adnotacjami. Znaczniki adnotacji są rzeczywiste obiekty w repozytorium, podczas gdy znaczniki lightweight są etykietami w przestrzeni refs/tags/. Jednak ogólnie każdy znacznik z adnotacjami ma jeden odpowiadający mu lekki znacznik, więc dla tego konkretnego zastosowania działają tak samo.

3prawie zawsze jest to kolejny Git repo, chociaż istnieją teraz Adaptery Dla Git do Mercurial, svn, i tak dalej. Mają swoje sztuczki, żeby udawać Git repos. Również opis ten nie ma być definitywny: rzeczywista Sekwencja operacje są kodowane dla wydajności transferu, a nie dla sensu-do-ludzi.

4w tym miejscu omówiłem nieco wyjątkową dziwność na temat plain fetch i clone, czyli wersji bez --tags. Wersje z --tags są łatwe do wyjaśnienia: przenoszą wszystkie znaczniki używając refspeców, które tutaj opisałem-i, przynajmniej w Git 2.10 i 2.11, --tags wykonuje również wymuszone aktualizacje, tak jakby ustawiono flagę + force. Ale chyba, że wyraźnie wzywasz do --no-tags, zwykły aport (i klon) przynosikilka znaczników. Podstępną rzeczą, jaką robi, jest szukanie tagów odpowiadających obiektom, które przychodzą z powodu pobierania, i dodaje je (bez wymuszania aktualizacji) do przestrzeni nazw (globalnych) tagów. Bez --tags Twój Git nie nadpisze własnych istniejących tagów; z --tags, Twój Git nadpisze własne istniejące tagi, przynajmniej w Git 2.10, na rzeczywiste eksperymenty wykonywane na początku 2017.

5starsze wersje Git stosowały reguły "branch" do tagów podczas push (ale niekoniecznie fetch), pozwalając na aktualizację tagów, jeśli była to opcja szybkiego przewijania do przodu, a poza tym wymagając znacznika force. Nowsza wersja git push wymaga tylko znacznika force. Refspec fetch z --tags nie ma ustawionej flagi siły, ale zachowuje się tak, jakby miała. Nie eksperymentowałem z push z --tags. Jest jeszcze jeden specjalny git fetch dziwny temat --tags vs --no-tags vs explicit refspecs, mając do czynienia z tym, jak --prune działa. Dokumentacja mówi, że --prune stosuje się do wszelkich jawnych poleceń refs/tags/ refspec, ale nie do implicit --tags refspec. Tego też nie eksperymentowałem.

6aby Twój Git mógł wypełnić refs/heads/ lub refs/tags/ dla Ciebie, Twój Git musi być w stanie dowiedzieć się o który chodziło. Są pewne przypadki, w których to robi, a niektóre nie. Jeśli Twój Git nie zrozumie tego, otrzymasz komunikat o błędzie i możesz spróbować ponownie, wypełniając go-ale w skryptach zawsze powinieneś go wypełnić jawnie, aby uzyskać bardziej przewidywalne zachowanie. Jeśli po prostu uruchamiasz git push, aby wypchnąć istniejącą gałąź, prawie zawsze możesz pozwolić swojemu Gitowi to rozgryźć.

7pomijając dwukropek i drugie imię nie działa tak dobrze dla git fetch: mówi twojemu Gitowi, aby w ogóle nie aktualizował własnych referencji! To wydaje się bezsensowne, ale w rzeczywistości może być przydatne, ponieważ git fetch zawsze zapisuje specjalny plik FETCH_HEAD. Możesz wyłowić identyfikatory Git object ID (SHA-1S) ze specjalnego pliku i zobaczyć, co zostało pobrane. Jest to w większości wstrzymanie z bardzo wczesnych wersji Gita, zanim wynaleziono gałęzie zdalnego śledzenia.

8refspec, którego używają git fetch --tags i git push --tags, jest wstępnie skompilowany wewnętrznie, w wersji 2.10 Git i obsługiwany przez specjalny kod przypadku. Wstępnie skompilowany formularz nie ma ustawionej flagi +; jeszcze eksperymenty pokazują, że pobrane znaczniki są aktualizowane siłą w Git 2.10/2.11. Pamiętam eksperymenty sprzed lat z Git 1.x, i stwierdzenie, że te --tags-fetched znaczniki były a nie force-updated, więc myślę, że to się zmieniło, ale to może być po prostu wadliwa pamięć. W każdym razie, jeśli tworzysz (ponownie)zdalne tagi, najprawdopodobniej nie chcesz , a nie używać jawnego --tags.

9tak właśnie działają lustra. Na przykład, z fetch = +*:* otrzymujesz czysty przynieś lustro. Proces pobierania może zobaczyć wszystkie refy. Możesz je zobaczyć sam z git ls-remote. Tak działa --single-branch: jeśli użyjesz --single-branch podczas klonowania, Twój plik konfiguracyjny Git wyświetli tylko jedną gałąź w linii fetch. Aby przekonwertować linię z jednej gałęzi na całą, po prostu edytuj linię, aby zawierała zwykły wpis glob-pattern.

 71
Author: torek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:17

1-pobranie znacznika z pilota za pomocą:

git fetch origin --tags 

Lub, aby pobrać znacznik z innego zdalnego użycia:

git fetch your_remote --tags

2 Sprawdź tag przez running

git checkout tags/<tag_name>

Więcej tutaj: Pobierz konkretny tag z Git

 81
Author: Russell Fair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:32:35

W moim przypadku, gdy nowy tag został dodany do zdalnego repozytorium [używam Stash], nowy tag nie był dostępny w wyniku git tag -l.
Ale udało mi się wyświetlić nowo dodany tag za pomocą git ls-remote --tags.
Musiałem uruchomić następujące polecenie, aby pobrać wszystkie najnowsze tagi do mojego lokalnego repozytorium:
git pull --tags Uruchamianie git tag -l wyświetla teraz również nowo dodane tagi.

Aby sprawdzić tag, użyj:
git checkout <tag_name>

Notatka: normalne jest uruchamianie git status i znajdowanie takiej wiadomości jak to:
HEAD detached at tag_name

 9
Author: hipsandy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-20 16:43:09

Mam kilka pytań na głowie:

  • Dlaczego różne piloty mają mieć inny kod (w tym samym drzewie)?
  • Dlaczego zdalny kod wpływa na sprawdzanie tagów?

Rzecz jest następująca:

Gdy sprawdzasz znacznik używając git checkout tags/fancytag, będzie on szukał znacznika dopasowania w bieżącym repozytorium (na twoim komputerze).

Jeśli chcesz pobrać znacznik z konkretnego pilota, musisz najpierw fetch go (drzewo konkretnego pilota) i Zobacz też

 0
Author: Langusten Gustel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-01 00:52:39