όταν ελέγχω απομακρυσμένη ετικέτα 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.
Μια ετικέτα χρησιμοποιείται για την επισήμανση και την επισήμανση μιας συγκεκριμένης επιβίβασης στο ιστορικό.
Συνήθως χρησιμοποιείται για τη σήμανση σημείων έκδοσης (π.χ. v1.0, κ.λπ.).
Παρόλο που μια ετικέτα μπορεί να φαίνεται παρόμοια με ένα υποκατάστημα, μια ετικέτα, ωστόσο, δεν αλλάζει.
Δείχνει άμεσα σε μια συγκεκριμένη δέσμευση στο ιστορικό.
Δεν θα μπορέσετε να ελέγξετε τις ετικέτες αν δεν είναι τοπικά στο αποθετήριο σας, οπότε πρώτα πρέπει να "φέρετε" τις ετικέτες στο τοπικό σας αποθετήριο.
Πρώτα, βεβαιωθείτε ότι η ετικέτα υπάρχει τοπικά κάνοντας
# --all will fetch all the remotes.
# --tags will fetch all tags as well
git fetch --all --tags --prune
Έπειτα ελέγξτε την ετικέτα εκτελώντας
git checkout tags/<tag_name> -b <branch_name>
Αντί για origin
χρησιμοποιήστε το πρόθεμα tags/
.
Σε αυτό το δείγμα έχετε 2 ετικέτες έκδοση 1.0 & έκδοση 1.1 μπορείτε να τις ελέγξετε με οποιοδήποτε από τα ακόλουθα:
git checkout A ...
git checkout version 1.0 ...
git checkout tags/version 1.0 ...
Όλα τα παραπάνω θα κάνουν το ίδιο, αφού η ετικέτα είναι μόνο ένας δείκτης σε μια συγκεκριμένη δέσμευση.
3 προέλευση: https://backlog.com/git-tutorial/img/post/stepup/capture_stepup4_1_1.png
# list all tags
git tag
# list all tags with given pattern ex: v-
git tag --list 'v-*'
Υπάρχουν 2 τρόποι για να δημιουργήσετε μια ετικέτα:
# lightweight tag
git tag
# annotated tag
git tag -a
Η διαφορά μεταξύ των 2 είναι ότι κατά τη δημιουργία μιας ετικέτας με σχόλια μπορείτε να προσθέσετε μεταδεδομένα όπως σε ένα git commit:
υπογραφή.
# delete any given tag
git tag -d <tag name>
# Don't forget to remove the deleted tag form the server with push tags
Για να αρπάξετε το περιεχόμενο μιας συγκεκριμένης ετικέτας μπορείτε να χρησιμοποιήσετε την εντολή checkout
.
Όπως εξηγήσαμε παραπάνω οι ετικέτες είναι σαν οποιεσδήποτε άλλες κοινοποιήσεις, οπότε μπορούμε να χρησιμοποιήσουμε την εντολή checkout
και αντί να χρησιμοποιήσουμε το SHA-1 απλά να το αντικαταστήσουμε με το tag_name
Επιλογή 1:
# Update the local git repo with the latest tags from all remotes
git fetch --all
# checkout the specific tag
git checkout tags/<tag> -b <branch>
Επιλογή 2:
Δεδομένου ότι το git υποστηρίζει shallow clone προσθέτοντας το --branch
στην εντολή clone μπορούμε να χρησιμοποιήσουμε το όνομα της ετικέτας αντί για το όνομα του branch. Το Git ξέρει πώς να "μεταφράσει" το δεδομένο SHA-1 στο σχετικό commit
# Clone a specific tag name using git clone
git clone <url> --branch=<tag_name>
git clone --branch=
>, --branch
μπορεί επίσης να λάβει ετικέτες και να αποσυνδέσει το HEAD σε αυτή τη δέσμευση στο αποθετήριο που προκύπτει.
git push --tags
Για να προωθήσετε όλες τις ετικέτες:
git push --tags
Για να προωθήσετε ετικέτες με σχόλια και ετικέτες της τρέχουσας αλυσίδας ιστορικού χρησιμοποιήστε::
git push --follow-tags
Αυτή η σημαία ---follow-tags
ωθεί και τις commits και μόνο τις ετικέτες που είναι και οι δύο:
Από το Git 2.4 μπορείτε να το ορίσετε χρησιμοποιώντας τη ρύθμιση παραμέτρων
git config --global push.followTags true
Δεν υπάρχει τέτοιο πράγμα όπως μια "απομακρυσμένη ετικέτα Git". Υπάρχουν μόνο "ετικέτες". Τα επισημαίνω όλα αυτά όχι για να γίνω σχολαστικός,1</sup>- αλλά επειδή υπάρχει μεγάλη σύγχυση σχετικά με αυτό στους περιστασιακούς χρήστες του Git, και η τεκμηρίωση του Git δεν είναι πολύ χρήσιμη2</sup>- στους αρχάριους. (Δεν είναι σαφές αν η σύγχυση προέρχεται από την κακή τεκμηρίωση, ή η κακή τεκμηρίωση προέρχεται επειδή αυτό είναι εγγενώς κάπως συγκεχυμένο, ή τι άλλο).
Υπάρχουν υπάρχουν "απομακρυσμένοι κλάδοι", που πιο σωστά ονομάζονται "κλάδοι απομακρυσμένης παρακολούθησης", αλλά αξίζει να σημειωθεί ότι στην πραγματικότητα πρόκειται για τοπικές οντότητες. Δεν υπάρχουν όμως απομακρυσμένες ετικέτες (εκτός αν τις (ξανα)εφεύρετε). Υπάρχουν μόνο τοπικές ετικέτες, οπότε πρέπει να αποκτήσετε την ετικέτα τοπικά για να τη χρησιμοποιήσετε.
Η γενική μορφή για ονόματα για συγκεκριμένες κοινοποιήσεις -που το Git αποκαλεί αναφορές- είναι οποιαδήποτε συμβολοσειρά που αρχίζει με refs/
. Μια συμβολοσειρά που ξεκινά με refs/heads/
ονομάζει ένα κλάδο- μια συμβολοσειρά που ξεκινά με refs/remotes/
ονομάζει έναν κλάδο απομακρυσμένης παρακολούθησης- και μια συμβολοσειρά που ξεκινά με refs/tags/
ονομάζει μια ετικέτα. Το όνομα refs/stash
είναι η αναφορά στην κρυψώνα (όπως χρησιμοποιείται από το git stash
- προσέξτε την έλλειψη της κάθετης που ακολουθεί).
Υπάρχουν μερικά ασυνήθιστα ονόματα ειδικών περιπτώσεων που δεν αρχίζουν με refs/
: τα HEAD
, ORIG_HEAD
, MERGE_HEAD
και CHERRY_PICK_HEAD
ειδικότερα είναι επίσης ονόματα που μπορούν να αναφέρονται σε συγκεκριμένες commits (αν και το HEAD
κανονικά περιέχει το όνομα ενός branch, δηλαδή περιέχει 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
είναι τα πιο ενδιαφέροντα σημεία επαφής.
Κατά τη διάρκεια των fetch
και push
, το Git χρησιμοποιεί συμβολοσειρές που ονομάζει refspecs για να μεταφέρει αναφορές μεταξύ του τοπικού και του απομακρυσμένου αποθετηρίου. Έτσι, σε αυτές τις στιγμές, και μέσω των refspecs, δύο αποθετήρια Git μπορούν να συγχρονιστούν μεταξύ τους. Μόλις τα ονόματά σας συγχρονιστούν, μπορείτε να χρησιμοποιήσετε το ίδιο όνομα που χρησιμοποιεί κάποιος με το απομακρυσμένο. Υπάρχει κάποια ειδική μαγεία εδώ στο fetch
, όμως, και επηρεάζει τόσο τα ονόματα κλάδων όσο και τα ονόματα ετικετών.
Θα πρέπει να σκεφτείτε ότι το git fetch
είναι σαν να κατευθύνει το Git σας να καλέσει (ή ίσως να στείλει μήνυμα κειμένου) ένα άλλο Git -το "remote"- και να συνομιλήσει μαζί του. Στην αρχή αυτής της συνομιλίας, το απομακρυσμένο παραθέτει όλες τις αναφορές του: τα πάντα στο refs/heads/
και τα πάντα στο refs/tags/
, μαζί με οποιεσδήποτε άλλες αναφορές έχει. Το Git σας σαρώνει αυτές και (με βάση το συνηθισμένο fetch refspec) ονομάζει τους κλάδους τους.
Ας ρίξουμε μια ματιά στο κανονικό refspec για το απομακρυσμένο που ονομάζεται origin
:
$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
$
Αυτό το refspec δίνει εντολή στο Git σας να παίρνει κάθε όνομα που ταιριάζει με το refs/heads/*
-δηλαδή, κάθε κλαδί στο απομακρυσμένο- και να αλλάζει το όνομά του σε refs/remotes/origin/*
, δηλαδή να κρατάει το μέρος που ταιριάζει το ίδιο, αλλάζοντας το όνομα του κλαδιού (refs/heads/
) σε ένα όνομα κλαδιού που παρακολουθεί το απομακρυσμένο (refs/remotes/
, συγκεκριμένα, refs/remotes/origin/
).
Είναι μέσω αυτού του refspec που τα κλαδιά του origin
'γίνονται τα κλαδιά απομακρυσμένης παρακολούθησης για το απομακρυσμένο origin
. Το όνομα του κλάδου γίνεται όνομα κλάδου απομακρυσμένης παρακολούθησης, με το όνομα του απομακρυσμένου, σε αυτή την περίπτωση του origin
, να συμπεριλαμβάνεται. Το σύμβολο συν +
στο μπροστινό μέρος του refspec θέτει τη σημαία "force", δηλαδή, ο κλάδος σας remote-tracking θα ενημερωθεί ώστε να ταιριάζει με το όνομα του remote'κλάδου, ανεξάρτητα από το τι χρειάζεται για να ταυτιστεί. (Χωρίς το +
, οι ενημερώσεις κλάδων περιορίζονται στις αλλαγές "fast forward" και οι ενημερώσεις ετικετών απλά αγνοούνται από την έκδοση 1.8.2 του Git περίπου - πριν από τότε ίσχυαν οι ίδιοι κανόνες fast-forward).
Αλλά τι γίνεται με τις ετικέτες; Δεν υπάρχει refspec για αυτές - τουλάχιστον, όχι από προεπιλογή. Μπορείτε να ορίσετε μία, οπότε η μορφή του refspec εξαρτάται από εσάς- ή μπορείτε να εκτελέσετε το git fetch --tags
. Η χρήση του --tags
έχει ως αποτέλεσμα την προσθήκη του refs/tags/*:refs/tags/*
στο refspec, δηλ, φέρνει όλες τις ετικέτες (αλλά δεν ενημερώνει την ετικέτα σας αν έχετε ήδη μια ετικέτα με αυτό το όνομα, ανεξάρτητα από το τι λέει η ετικέτα του απομακρυσμένου's Επεξεργασία, Ιαν 2017: από το Git 2.10, η δοκιμή δείχνει ότι το --tags
ενημερώνει με τη βία τις ετικέτες σας από τις ετικέτες του απομακρυσμένου's, σαν το refspec να διάβαζε +refs/tags/*:refs/tags/*
- αυτό μπορεί να είναι μια διαφορά στη συμπεριφορά από μια προηγούμενη έκδοση του Git).
Σημειώστε ότι δεν υπάρχει μετονομασία εδώ: αν το απομακρυσμένο origin
έχει την ετικέτα xyzzy
, ενώ εσείς όχι, και κάνετε git fetch origin "refs/tags/*:refs/tags/*"
, θα έχετε την προσθήκη του refs/tags/xyzzy
στο αποθετήριο σας (δείχνοντας στην ίδια δέσμευση όπως στο απομακρυσμένο). Αν χρησιμοποιήσετε το +refs/tags/*:refs/tags/*
, τότε η ετικέτα xyzzy
, αν έχετε, αντικαθίσταται από την ετικέτα origin
. Δηλαδή, η σημαία ισχύος +
σε ένα refspec σημαίνει "αντικαταστήστε την τιμή της αναφοράς μου'με αυτήν που παίρνει το Git μου από το δικό τους Git".
Για ιστορικούς λόγους,3 αν δεν χρησιμοποιήσετε ούτε την επιλογή --tags
ούτε την επιλογή --no-tags
, το git fetch
αναλαμβάνει ειδική δράση. Θυμηθείτε ότι είπαμε παραπάνω ότι το απομακρυσμένο ξεκινά εμφανίζοντας στο τοπικό σας Git όλες τις αναφορές του, είτε το τοπικό σας Git θέλει να τις δει είτε όχι.4 Το Git σας λαμβάνει υπόψη του όλες τις ετικέτες που βλέπει σε αυτό το σημείο. Στη συνέχεια, καθώς αρχίζει να κατεβάζει οποιαδήποτε αντικείμενα commit που χρειάζεται για να χειριστεί οτιδήποτε φέρνει, αν ένα από αυτά τα commit έχει το ίδιο ID με κάποια από αυτές τις ετικέτες, το git θα προσθέσει αυτή την ετικέτα -ή αυτές τις ετικέτες, αν πολλαπλές ετικέτες έχουν αυτό το ID- στο αποθετήριό σας.</s>,
Επεξεργασία, Ιανουάριος 2017: Η δοκιμή δείχνει ότι η συμπεριφορά στο Git 2.10 είναι τώρα: Αν το Git τους παρέχει μια ετικέτα με όνομα T, και εσείς δεν έχετε μια ετικέτα με όνομα T, και το commit ID που σχετίζεται με το T είναι πρόγονος ενός από τους κλάδους τους που εξετάζει το git fetch
, το Git σας προσθέτει το T στις ετικέτες σας με ή χωρίς --tags
. Η προσθήκη του --tags
προκαλεί το Git σας να λάβει όλες τις ετικέτες τους, και επίσης να επιβάλει ενημέρωση.
Μπορεί να χρειαστεί να χρησιμοποιήσετε το git fetch --tags
για να λάβετε τις ετικέτες τους. Αν τα ονόματα των ετικετών τους έρχονται σε σύγκρουση με τα υπάρχοντα ονόματα των ετικετών σας, ίσως (ανάλογα με την έκδοση του Git) θα πρέπει να διαγράψετε (ή να μετονομάσετε) μερικές από τις ετικέτες σας, και στη συνέχεια να εκτελέσετε το git fetch --tags
, για να λάβετε τις ετικέτες τους. Δεδομένου ότι οι ετικέτες -σε αντίθεση με τους απομακρυσμένους κλάδους- δεν έχουν αυτόματη μετονομασία, τα ονόματα των ετικετών σας πρέπει να ταιριάζουν με τα ονόματα των ετικετών τους, γι' αυτό και μπορεί να έχετε προβλήματα με συγκρούσεις.
Στις περισσότερες συνήθεις περιπτώσεις, όμως, ένα απλό git fetch
θα κάνει τη δουλειά, φέρνοντας τα commits τους και τις αντίστοιχες ετικέτες τους, και αφού αυτοί -όποιοι κι αν είναι- θα επισημάνουν τα commits τη στιγμή που θα τα δημοσιεύσουν, θα συμβαδίζετε με τις ετικέτες τους. Αν δεν φτιάχνετε τις δικές σας ετικέτες, ούτε αναμειγνύετε το αποθετήριό τους και άλλα αποθετήρια (μέσω πολλαπλών απομακρυσμένων συνδέσεων), δεν θα έχετε ούτε συγκρούσεις ονομάτων ετικετών, οπότε δεν θα χρειάζεται να ασχοληθείτε με τη διαγραφή ή τη μετονομασία ετικετών προκειμένου να αποκτήσετε τις ετικέτες τους.
Ανέφερα παραπάνω ότι μπορείτε να παραλείπετε το refs/
σχεδόν πάντα, και τα refs/heads/
και refs/tags/
και ούτω καθεξής τις περισσότερες φορές. Αλλά πότε δεν μπορείτε;
Η πλήρης (ή σχεδόν πλήρης τέλος πάντων) απάντηση βρίσκεται στην τεκμηρίωση gitrevisions
. Το Git θα επιλύσει ένα όνομα σε ένα αναγνωριστικό δέσμευσης χρησιμοποιώντας την ακολουθία έξι βημάτων που δίνεται στο σύνδεσμο. Περιέργως, οι ετικέτες υπερισχύουν των κλάδων: αν υπάρχει μια ετικέτα xyzzy
και ένας κλάδος xyzzy
, και δείχνουν σε διαφορετικές commits, τότε:
git rev-parse xyzzy
gitrevisions
- το git checkout
προτιμά τα ονόματα κλάδων, οπότε το git checkout xyzzy
θα σας βάλει στον κλάδο, αγνοώντας την ετικέτα.
Σε περίπτωση ασάφειας, μπορείτε σχεδόν πάντα να συλλαβίζετε το όνομα του ref χρησιμοποιώντας το πλήρες όνομά του, refs/heads/xyzzy
ή refs/tags/xyzzy
. (Σημειώστε ότι αυτό λειτουργεί με το git checkout
, αλλά με έναν ίσως απροσδόκητο τρόπο: Το git checkout refs/heads/xyzzy
προκαλεί ένα detached-HEAD checkout και όχι ένα branch checkout. Γι' αυτό το λόγο πρέπει απλώς να σημειώσετε ότι το git checkout
θα χρησιμοποιήσει πρώτα το σύντομο όνομα ως όνομα κλάδου: με αυτόν τον'τρόπο κάνετε check out τον κλάδο xyzzy
ακόμα και αν υπάρχει η ετικέτα xyzzy
. Αν θέλετε να ελέγξετε την ετικέτα, μπορείτε να χρησιμοποιήσετε το refs/tags/xyzzy
).
Επειδή (όπως σημειώνει το gitrevisions
) το Git θα δοκιμάσει το refs/name
, μπορείτε επίσης απλά να γράψετε tags/xyzzy
για να εντοπίσετε το commit με ετικέτα xyzzy
. (Αν κάποιος έχει καταφέρει να γράψει μια έγκυρη αναφορά με όνομα xyzzy
στο $GIT_DIR
, ωστόσο, αυτό θα επιλυθεί ως $GIT_DIR/xyzzy
. Αλλά κανονικά μόνο τα διάφορα ονόματα *HEAD
θα πρέπει να βρίσκονται στο $GIT_DIR
).1Εντάξει, εντάξει, "όχι απλά για να είμαι σχολαστικός" :-)
2Κάποιοι θα έλεγαν "πολύ μη βοηθητικό"και θα έτεινα να συμφωνήσω, στην πραγματικότητα.
3Βασικά, το git fetch
, και η όλη έννοια των remotes και refspecs, ήταν μια κάπως καθυστερημένη προσθήκη στο Git, που συνέβη περίπου την εποχή του Git 1.5. Πριν από αυτό υπήρχαν μόνο κάποιες ad-hoc ειδικές περιπτώσεις, και το tag-fetching ήταν μία από αυτές, οπότε καθιερώθηκε μέσω ειδικού κώδικα.
4Αν σας βοηθάει, σκεφτείτε το απομακρυσμένο Git ως flasher, με την αργκό έννοια.
Για να λάβετε τον συγκεκριμένο κωδικό ετικέτας προσπαθήστε να δημιουργήσετε ένα νέο υποκατάστημα προσθέστε τον κωδικό ετικέτας σε αυτό.
Το έκανα με την εντολή : $git checkout -b newBranchName tagName