Какво е таг на git, Как да създадете тагове & Как да проверите отдалечен(и) таг(и) на git
когато проверявам отдалечен таг на git, използвам команда като тази:
git checkout -b local_branch_name origin/remote_tag_name
Получавам такава грешка:
error: pathspec `origin/remote_tag_name` did not match any file(s) known to git.
Мога да намеря remote_tag_name, когато използвам командата git tag.
467
3
Нека започнем с обяснение на това какво е таг в git
Няма да можете да изтеглите таговете, ако те не са локално в хранилището ви, така че първо трябва да изтеглите таговете в локалното си хранилище.
На първо място се уверете, че тагът съществува локално, като направите
След това проверете тага, като стартирате
Вместо
origin
използвайте префиксаtags/
.В тази извадка имате 2 тага версия 1.0 и версия 1.1, които можете да проверите с някое от следните действия:
Всички горепосочени действия ще бъдат еднакви, тъй като тагът е само указател към дадена ревизия.
Как да видите списъка с всички тагове?
Как да създаваме тагове?
Има 2 начина за създаване на таг:
Разликата между двата начина е, че когато създавате анотиран таг, можете да добавяте метаданни, както при commit в git:
име, електронна поща, дата, коментар & подпис
Как да изтрием таговете?
Как да клонирате определен таг?
За да вземете съдържанието на даден таг, можете да използвате командата
checkout
.Както беше обяснено по-горе, таговете са като всички останали коммисии, така че можем да използваме
checkout
и вместо да използваме SHA-1, просто да го заменим с името на тагаВариант 1:
Вариант 2:
Използване на командата clone
Тъй като git поддържа плътен клонинг, чрез добавяне на
--отклонение
към командата clone можем да използваме името на тага вместо името на клона. Git знае как да "преведе" дадения SHA-1 към съответния commitКак да избутаме тагове?
git push --tags
За избутване на всички тагове:
За изтласкване на анотирани тагове и тагове от текущата история на веригата използвайте::
git push --follow-tags
Този флаг
--follow-tags
изтласква както съобщения, така и само тагове, които са и двете:От версия 2.4 на Git можете да го зададете с помощта на конфигурацията
(Написването на този отговор отне известно време, а отговорът на codeWizard's е правилен по цел и същност, но не е напълно завършен, така че все пак ще го публикувам.)
Няма такова нещо като "отдалечен таг на Git". Съществуват само "тагове". Изтъквам всичко това не за да бъда педантичен,1 а защото има голямо объркване по този въпрос сред обикновените потребители на Git, а документацията на Git не е много полезна2 за начинаещите. (Не е ясно дали объркването идва заради лошата документация, или лошата документация идва, защото това по своята същност е малко объркващо, или какво.) Съществуват "отдалечени клонове", по-правилно наричани "клонове за отдалечено проследяване", но си струва да се отбележи, че те всъщност са локални единици. Няма обаче отдалечени маркери (освен ако не ги измислите отново). Съществуват само локални тагове, така че трябва да получите локален таг, за да го използвате. Общата форма на имената за конкретни предавания - която Git нарича references - е всеки низ, започващ с
refs/
. Редица, започваща сrefs/heads/
, назовава клон; низ, започващ сrefs/remotes/
, назовава клон за отдалечено проследяване; а низ, започващ сrefs/tags/
, назовава таг. Иметоrefs/stash
е препратка към хранилището (както се използва отgit stash
; обърнете внимание на липсата на завършваща наклонена черта). Съществуват някои необичайни имена от специален тип, които не започват сrefs/
:HEAD
,ORIG_HEAD
,MERGE_HEAD
иCHERRY_PICK_HEAD
в частност са също имена, които могат да се отнасят до конкретни коммисии (въпреки чеHEAD
обикновено съдържа името на клона, т.е. съдържаref: refs/heads/
branch). Но по принцип препратките започват сrefs/
. Едно от нещата, които Git прави, за да направи това объркващо, е, че ви позволява да пропускатеrefs/
, а често и думата следrefs/
. Например, можете да пропуснетеrefs/heads/
илиrefs/tags/
, когато се позовавате на локален клон или таг - и всъщност задължително пропускатеrefs/heads/
, когато проверявате локален клон! Можете да направите това винаги, когато резултатът е недвусмислен, или - както току-що отбелязахме - когато трябва да го направите (заgit checkout
branch*). Вярно е, че препратки съществуват не само в собственото ви хранилище, но и в отдалечени хранилища. Git обаче ви дава достъп до референциите на отдалечено хранилище'само в много специфични моменти: а именно по време на операциитеfetch
иpush
. Можете също така да използватеgit ls-remote
илиgit remote show
, за да ги видите, ноfetch
иpush
са по-интересните точки на контакт.Refspecs
По време на операциите
fetch
иpush
Git използва низове, които нарича refspecs, за да прехвърля референции между локалното и отдалеченото хранилище. По този начин, именно в тези моменти и чрез refspecs, две Git хранилища могат да се синхронизират помежду си. След като имената ви се синхронизират, можете да използвате същото име, което използва някой от отдалеченото. Приfetch
обаче има някаква специална магия, която засяга както имената на клоновете, така и имената на таговете. Трябва да мислите заgit fetch
като за насочване на вашия Git да извика (или може би да изпрати текстово съобщение) друг Git - "отдалечения" - и да проведе разговор с него. В началото на този разговор отдалеченият Git изброява всички свои препратки: всичко вrefs/heads/
и всичко вrefs/tags/
, както и всички други препратки, които има. Вашият Git ги преглежда и (въз основа на обичайния fetch refspec) преименува техните клонове. Нека разгледаме обичайния refspec за отдалеченото устройство с имеоригинал
:Този refspec инструктира вашия Git да вземе всяко име, съответстващо на
refs/heads/*
, т.е. всеки клон на отдалеченото, и да промени името му наrefs/remotes/origin/*
, т.е. да запази съвпадащата част, като промени името на клона (refs/heads/
) на име на клон, проследяващ отдалеченото (refs/remotes/
, по-конкретноrefs/remotes/origin/
). Именно чрез този refspec клоновете наorigin
'стават ваши клонове за отдалечено проследяване за отдалеченияorigin
. Името на клона се превръща в име на клон за отдалечено проследяване, като се включва името на отдалеченото, в този случайorigin
. Знакът плюс+
в началото на refspec задава флага "force", т.е. вашият клон за дистанционно проследяване ще бъде актуализиран, за да съвпадне с името на клона на отдалеченото'устройство, независимо от това какво е необходимо, за да съвпадне. (Без флага+
актуализациите на клона се ограничават до "бързи промени", а актуализациите на таговете просто се игнорират от версия 1.8.2 на Git или подобна - преди това се прилагаха същите правила за бързи промени).Етикети
Но какво да кажем за етикетите? За тях няма рефспект - поне не по подразбиране. Можете да зададете такъв, като в този случай формата на refspec зависи от вас; или можете да стартирате
git fetch --tags
. Използването на--tags
води до добавяне наrefs/tags/*:refs/tags/*
към refspec, т.е., тя пренася всички тагове (но не актуализира вашия таг, ако вече имате таг с това име, независимо от това какво казва тагът на отдалеченото'устройство Редактиране, януари 2017 г.: от Git 2.10, тестването показва, че--tags
принудително актуализира вашите тагове от отдалечените'тагове, все едно refspec гласи+refs/tags/*:refs/tags/*
; това може да е разлика в поведението от по-ранна версия на Git). Обърнете внимание, че тук няма преименуване: ако отдалеченияторигинал
има тагxyzzy
, а вие нямате, и виеgit fetch origin "refs/tags/*:refs/tags/*"
, ще получитеrefs/tags/xyzzy
, добавен към вашето хранилище (сочещ към същия commit като на отдалечения). Ако използвате+refs/tags/*:refs/tags/*
, вашият тагxyzzy
, ако имате такъв, се заменя с този оторигинал
. Това означава, че флагът за сила+
на refspec означава "замени моята референция'със стойността, която моят Git получава от техния Git".Автоматични тагове по време на извличане
По исторически причини,3 ако не използвате нито опцията
--tags
, нито опцията--no-tags
,git fetch
предприема специални действия. Спомнете си, че по-горе казахме, че отдалеченото устройство започва да показва на вашия локален Git всички свои препратки, независимо дали вашият локален Git иска да ги види или не.4 Вашият Git отбелязва всички тагове, които вижда в този момент. След това, когато започне да изтегля всички обекти на предавания, от които се нуждае, за да обработва това, което извлича, ако някое от тези предавания има същия идентификатор като някой от тези тагове, git ще добави този таг - или тези тагове, ако няколко тага имат този идентификатор - към вашето хранилище. Редактиране, януари 2017 г.: тестването показва, че поведението в Git 2.10 вече е такова: Ако техният Git предоставя таг с име T, и вие нямате таг с име T, и идентификаторът на предаването, свързан с T, е родоначалник на един от техните клонове, които вашиятgit fetch
разглежда, вашият Git добавя T към вашите тагове със или без--tags
. Добавянето на--tags
кара вашия Git да получи всичките им тагове, а също и да наложи актуализация.В крайна сметка
Може да се наложи да използвате
git fetch --tags
, за да получите техните тагове. Ако имената на таговете им са в конфликт с имената на съществуващите тагове, може да се наложи (в зависимост от версията на Git) дори да изтриете (или да преименувате) някои от таговете си и след това да стартиратеgit fetch --tags
, за да получите техните тагове. Тъй като таговете - за разлика от отдалечените клонове - нямат автоматично преименуване, имената на вашите тагове трябва да съвпадат с имената на техните тагове, поради което можете да имате проблеми с конфликти. В повечето нормални случаи обаче един обикновенgit fetch
ще свърши работа, като прехвърли техните коммити и съответстващите им тагове, и тъй като те - които и да са те - ще маркират коммитите в момента на публикуването им, вие ще сте в крак с техните тагове. Ако не създавате свои собствени тагове, нито смесвате тяхното хранилище с други хранилища (чрез множество отдалечени устройства), няма да има и колизии в имената на таговете, така че няма да ви се налага да се занимавате с изтриване или преименуване на тагове, за да получите техните тагове.Когато ви трябват квалифицирани имена
По-горе споменах, че можете да пропускате
refs/
почти винаги, аrefs/heads/
иrefs/tags/
и т.н. през повечето време. Но кога не можете? Пълният (или почти пълният) отговор се намира в документацията наgitrevisions
. Git ще преобразува името в идентификатор на ревизия, като използва последователността от шест стъпки, посочена в линка. Любопитно е, че таговете имат предимство пред клоновете: ако има тагxyzzy
и клонxyzzy
и те сочат към различни коммити, тогава:ще ви даде идентификатора, към който сочи тагът. Обаче - и това е нещото, което липсва в
gitrevisions
-git checkout
предпочита имената на клоновете, така чеgit checkout xyzzy
ще ви постави на клона, без да се съобразява с тага. В случай на двусмислие почти винаги можете да изпишете името на реферата, като използвате пълното му име,refs/heads/xyzzy
илиrefs/tags/xyzzy
. (Имайте предвид, че това работи сgit checkout
, но по може би неочакван начин:git checkout refs/heads/xyzzy
предизвиква проверка на отделен глава, а не проверка на клон. Ето защо просто трябва да отбележите, чеgit checkout
ще използва първо краткото име като име на клона: така'ще проверите клонаxyzzy
, дори ако тагътxyzzy
съществува. Ако искате да проверите тага, можете да използватеrefs/tags/xyzzy
.) Тъй като (както отбелязваgitrevisions
) Git ще опитаrefs/name
, можете също така просто да напишетеtags/xyzzy
, за да идентифицирате предаването с етикетxyzzy
. (Ако обаче някой е успял да запише валидна референция с имеxyzzy
в$GIT_DIR
, това ще се разреши като$GIT_DIR/xyzzy
. Обикновено обаче в$GIT_DIR
трябва да има само различните имена*HEAD
.)1Добре, добре, "не само за да бъда педантичен". :-) 2Някой би казал "много не-полезно", и всъщност съм склонен да се съглася. 3По принцип,
git fetch
и цялата концепция за отдалечени обекти и refspecs беше малко късно допълнение към Git, което се появи около времето на Git 1.5. Преди това имаше само някои специални случаи ad-hoc и tag-fetching беше един от тях, така че беше включен чрез специален код. 4Ако ви помогне, мислете за отдалечения Git като за flasher, в жаргонен смисъл.За да получите специфичния код на етикета, опитайте се да създадете нов клон, добавете кода на етикета в него. Направих го с командата :
$git checkout -b newBranchName tagName