-
1. Ξεκινώντας με το Git
-
2. Τα θεμελιώδη στοιχεία του Git
-
3. Διακλαδώσεις στο Git
-
4. Το Git στον διακομιστή
- 4.1 Τα πρωτόκολλα
- 4.2 Εγκατάσταση του Git σε διακομιστή
- 4.3 Δημιουργία δημόσιου κλειδιού SSH
- 4.4 Στήσιμο του διακομιστή
- 4.5 Δαίμονες του Git
- 4.6 Έξυπνο HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Επιλογές φιλοξενίας από τρίτους
- 4.10 Ανακεφαλαίωση
-
5. Κατανεμημένο Git
-
6. GitHub
-
7. Εργαλεία του Git
- 7.1 Επιλογή αναθεώρησης
- 7.2 Διαδραστική εργασία με το στάδιο καταχώρισης
- 7.3 stash και clean
- 7.4 Υπογραφή της δουλειάς μας
- 7.5 Αναζήτηση
- 7.6 Η ιστορία ξαναγράφεται
- 7.7 Απομυθοποίηση της reset
- 7.8 Συγχωνεύσεις για προχωρημένους
- 7.9 Rerere
- 7.10 Αποσφαλμάτωση με το Git
- 7.11 Λειτουργικές υπομονάδες
- 7.12 Δεμάτιασμα δεδομένων
- 7.13 Replace
- 7.14 Αποθήκευση διαπιστευτηρίων
- 7.15 Ανακεφαλαίωση
-
8. Εξατομίκευση του Git
-
9. Το Git και άλλα συστήματα
- 9.1 Το Git ως πελάτης
- 9.2 Μετανάστευση στο Git
- 9.3 Ανακεφαλαίωση
-
10. Εσωτερική λειτουργία του Git
- 10.1 Διοχετεύσεις και πορσελάνες
- 10.2 Αντικείμενα του Git
- 10.3 Αναφορές του Git
- 10.4 Πακετάρισμα αρχείων
- 10.5 Τα refspec
- 10.6 Πρωτόκολλα μεταφοράς
- 10.7 Διατήρηση και ανάκτηση δεδομένων
- 10.8 Μεταβλητές περιβάλλοντος
- 10.9 Ανακεφαλαίωση
-
A1. Appendix A: Το Git σε άλλα περιβάλλοντα
- A1.1 Γραφικές διεπαφές
- A1.2 Το Git στο Visual Studio
- A1.3 Git στο Eclipse
- A1.4 Το Git στο Bash
- A1.5 Το Git στο Zsh
- A1.6 Το Git στο Powershell
- A1.7 Ανακεφαλαίωση
-
A2. Appendix B: Ενσωμάτωση του Git στις εφαρμογές μας
- A2.1 Γραμμή εντολών Git
- A2.2 Libgit2
- A2.3 JGit
-
A3. Appendix C: Εντολές Git
- A3.1 Ρύθμιση και διαμόρφωση
- A3.2 Λήψη και δημιουργία έργων
- A3.3 Βασική λήψη στιγμιοτύπων
- A3.4 Διακλάδωση και συγχώνευση
- A3.5 Κοινή χρήση και ενημέρωση έργων
- A3.6 Επιθεώρηση και σύγκριση
- A3.7 Αποσφαλμάτωση
- A3.8 Επιθέματα
- A3.9 Ηλεκτρονικό ταχυδρομείο
- A3.10 Εξωτερικά Συστήματα
- A3.11 Διοίκηση
- A3.12 Εντολές διοχέτευσης
7.7 Εργαλεία του Git - Απομυθοποίηση της reset
Απομυθοποίηση της reset
Πριν προχωρήσουμε σε πιο εξειδικευμένα εργαλεία, ας μιλήσουμε για τα reset
και checkout
.
Αυτές οι εντολές είναι δύο από τα πιο δυσνόητα σημεία του Git όταν τα συναντά κανείς για πρώτη φορά.
Κάνουν τόσο πολλά πράγματα, που φαίνεται να μην υπάρχει καμία ελπίδα πραγματικής κατανόησης σωστής χρήσης τους.
Γι' αυτό, θα κάνουμε μία απλή μεταφορά.
Τα τρία δέντρα
Ένας ευκολότερος τρόπος για να σκεφτούμε τα reset
και checkout
είναι μέσα από ένα νοητική πλαίσιο στο οποίο το Git είναι διαχειριστής του περιεχομένου τριών διαφορετικών δέντρων.
Με τον όρο “δέντρο” εδώ εννοούμε ουσιαστικά “συλλογή αρχείων”, όχι ειδικότερα τη δομή δεδομένων.
(Υπάρχουν μερικές περιπτώσεις στις οποίες το Ευρετήριο δεν λειτουργεί ακριβώς όπως ένα δέντρο, αλλά για τον σκοπό μας είναι ευκολότερο να το σκεφτούμε με αυτόν τον τρόπο προς το παρόν.)
Το Git, ως σύστημα, διαχειρίζεται και μεταχειρίζεται τρία δέντρα στην κανονική του λειτουργία:
Δέντρο | Ρόλος |
---|---|
HEAD |
Στιγμιότυπο τελευταίας υποβολής, επόμενος γονέας |
Ευρετήριο |
Προτεινόμενο στιγμιότυπο για την επόμενη υποβολή |
Κατάλογος Εργασίας |
Αμμοδοχείο |
Το δέντρο HEAD
Ο HEAD είναι ο δείκτης στην αναφορά του τρέχοντος κλάδου, ο οποίος με τη σειρά του είναι ένας δείκτης στην τελευταία υποβολή που έγινε σε αυτόν τον κλάδο. Αυτό σημαίνει ότι ο HEAD θα είναι ο γονέας της επόμενης υποβολής που δημιουργείται. Είναι γενικά απλούστερο να σκεφτόμαστε τον HEAD ως το στιγμιότυπο της τελευταίας μας υποβολής σε αυτόν τον κλάδο.
Στην πραγματικότητα, είναι αρκετά εύκολο να δούμε με τι μοιάζει αυτό το στιγμιότυπο. Ακολουθεί ένα παράδειγμα της πραγματικής λίστας καταλόγου και των αθροισμάτων ελέγχου SHA-1 για κάθε αρχείο στο στιγμιότυπο HEAD:
$ git cat-file -p HEAD
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
author Scott Chacon 1301511835 -0700
committer Scott Chacon 1301511835 -0700
initial commit
$ git ls-tree -r HEAD
100644 blob a906cb2a4a904a152... README
100644 blob 8f94139338f9404f2... Rakefile
040000 tree 99f1a6d12cb4b6f19... lib
Οι εντολές cat-file
και ls-tree
είναι εντολές “διοχέτευσης” που χρησιμοποιούνται για πράγματα χαμηλότερου επιπέδου και σπάνια χρησιμοποιούνται στην καθημερινή εργασία μας, αλλά μας βοηθούν να δούμε τι συμβαίνει εδώ.
Το Ευρετήριο
Το Ευρετήριο είναι η προτεινόμενη επόμενη υποβολή. Έχουμε επίσης αναφερθεί σε αυτήν την έννοια ως “στάδιο καταχώρισης” του Git, καθώς αυτό εξετάζει το Git όταν τρέχουμε την ‘git commit’.
Από τεχνικής άποψης το Ευρετήριο δεν είναι δομή δέντρου —στην πραγματικότητα έχει υλοποιηθεί ως ισοπεδωμένο δηλωτικό (manifest— αλλά για τον σκοπό μας είναι αρκετά κοντά σε ένα δένδρο.
Το Git γεμίζει αυτό το ευρετήριο με μια λίστα των περιεχομένων όλων των τελευταίων αρχείων που έχουν ενημερωθεί (checkout) στον κατάλογο εργασίας μας και με τι έμοιαζαν τα αρχεία όταν ενημερώθηκαν.
Στη συνέχεια, αντικαθιστούμε μερικά από αυτά τα αρχεία με νέες εκδόσεις τους και εκτελούμε μία git commit
που το μετατρέπει στο δέντρο για μια νέα υποβολή.
$ git ls-files -s
100644 a906cb2a4a904a152e80877d4088654daad0c859 0 README
100644 8f94139338f9404f26296befa88755fc2598c289 0 Rakefile
100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb
Και πάλι εδώ χρησιμοποιούμε την εντολή `ls-files ', η οποία είναι περισσότερο μια εντολή παρασκηνίου που μας δείχνει με τι μοιάζει το Ευρετήριο μας αυτήν τη στιγμή.
Ο Κατάλογος Εργασίας
Τέλος, έχουμε τον κατάλογο εργασίας μας.
Τα άλλα δύο δέντρα αποθηκεύουν το περιεχόμενό τους με έναν αποτελεσματικό αλλά καθόλου βολικό τρόπο, μέσα στον φάκελο .git
.
Ο κατάλογος εργασίας το απλώνει σε πραγματικά αρχεία, πράγμα που καθιστά την επεξεργασία τους πολύ πιο εύκολη για μας.
Μπορούμε να σκεφτούμε τον κατάλογο εργασίας ως αμμοδοχείο, όπου μπορούμε να δοκιμάσουμε αλλαγές πριν να τις υποβάλλουμε στο στάδιο καταχώρισης (Ευρετήριο) και στη συνέχεια στο ιστορικό.
$ tree
.
├── README
├── Rakefile
└── lib
└── simplegit.rb
1 directory, 3 files
Η ροή εργασίας
Ο κύριος σκοπός του Git είναι να καταγράφει στιγμιότυπα του έργου μας σε διαδοχικά καλύτερες καταστάσεις, χειριζόμενο αυτά τα τρία δέντρα.

Ας οπτικοποιήσουμε αυτήν τη διαδικασία: ας πούμε ότι πηγαίνουμε σε έναν νέο κατάλογο με μόνον ένα αρχείο σε αυτόν.
Θα ονομάσουμε αυτήν την έκδοση του αρχείου v1 και θα το απεικονίζουμε με μπλε χρώμα.
Τώρα τρέχουμε την git init
, η οποία θα δημιουργήσει ένα αποθετήριο Git με μια αναφορά HEAD που δείχνει σε έναν κλάδο που δεν υπάρχει (ο master
δεν υπάρχει ακόμα).

Σε αυτό το σημείο, μόνο το δέντρο του Καταλόγου Εργασίας έχει κάποιο περιεχόμενο.
Τώρα θέλουμε να υποβάλουμε αυτό το αρχείο, οπότε χρησιμοποιούμε την git add
για να πάρουμε το περιεχόμενο που βρίσκεται στον Κατάλογο Εργασίας και να το αντιγράψουμε στο Ευρετήριο.

Στη συνέχεια, τρέχουμε την git commit
, η οποία παίρνει τα περιεχόμενα του Ευρετηρίου και τα αποθηκεύει ως μόνιμο στιγμιότυπο, δημιουργεί ένα αντικείμενο υποβολής το οποίο δείχνει σε αυτό το στιγμιότυπο και ενημερώνει τον master
να δείχνει σε αυτήν την υποβολή.

Αν εκτελέσουμε την git status
, δεν θα δούμε αλλαγές, αφού και τα τρία δέντρα είναι τα ίδια.
Τώρα θέλουμε να κάνουμε μια αλλαγή σε αυτό το αρχείο και να την υποβάλλουμε. Θα επαναληφθεί η ίδια διαδικασία· πρώτα αλλάζουμε το αρχείο στον Κατάλογο Εργασίας μας. Ας ονομάσουμε αυτην την έκδοση του αρχείου v2 και θα την απεικονίζουμε με κόκκινο χρώμα.

Αν εκτελέσουμε την εντολή git status
τώρα, το αρχείο θα εμφανιστεί με κόκκινο χρώμα με την ένδειξη “Changes not staged for commit”, επειδή αυτή η εγγραφή διαφέρει μεταξύ του Ευρετηρίου και του Καταλόγου Εργασίας.
Στη συνέχεια τρέχουμε την git add
σε αυτό για να το προσθέσουμε στο Ευρετήριο μας.

Σε αυτό το σημείο, αν εκτελέσουμε την git status
θα δούμε το αρχείο πράσινο κάτω από την ένδειξη Changes to be committed
επειδή το Ευρετήριο και ο HEAD διαφέρουν —δηλαδή, η προτεινόμενη επόμενη υποβολή μας τώρα είναι διαφορετική από την τελευταία μας υποβολή.
Τέλος, τρέχουμε git commit
για να οριστικοποιήσουμε την υποβολή.

Τώρα η git status
δεν θα μας δώσει καμία έξοδο, αφού και τα τρία δέντρα είναι τα ίδια ξανά.
Όταν μεταβαίνουμε από έναν κλάδο σε άλλον ή κλωνοποιούμε, γίνεται μία παρόμοια διαδικασία. Όταν μεταβαίνουμε σε έναν κλάδο, αλλάζει ο HEAD ώστε να δείχνει στο ref του νέου κλάδου, το Ευρετήριο γεμίζει με το στιγμιότυπο αυτής της υποβολής και στη συνέχεια τα περιεχόμενα του Ευρετηρίου αντιγράφουνται στον Κατάλογο Εργασίας.
Ο ρόλος της reset
Η εντολή reset
γίνεται κατανοητή πιο εύκολα στο παρακάτω πλαίσιο.
Για τους σκοπούς αυτών των παραδειγμάτων, ας πούμε ότι τροποποιήσαμε ξανά το file.txt
και το υποβάλαμε για τρίτη φορά.
Έτσι τώρα το ιστορικό μας μοιάζει με αυτό:

Ας δούμε τώρα τι ακριβώς κάνει η reset
όταν την καλούμε.
Χειραγωγεί άμεσα αυτά τα τρία δέντρα με έναν απλό και προβλέψιμο τρόπο.
Κάνει το πολύ μέχρι τρεις βασικές λειτουργίες.
Βήμα 1: μετακίνηση του HEAD
Το πρώτο πράγμα που κάνει η reset
είναι να μετακινήσει το πού δείχνει ο HEAD.
Αυτό δεν είναι το ίδιο με το να αλλάζει τον ίδιο τον HEAD (που είναι αυτό που κάνει η checkout
). Η reset
μετακινεί τον κλάδο στον οποίο δείχνει ο HEAD.
Αυτό σημαίνει ότι αν ο HEAD έχει τεθεί στον κλάδο master
(δηλ. βρισκόμαστε στον κλάδο master
), η git reset 9e5e6a4
θα ξεκινήσει κάνοντας τον master
να δείχνει στην 9e5e6a4
.

Ανεξάρτητα από το με τι διακόπτες καλούμε την reset
, αυτό είναι το πρώτο πράγμα που θα προσπαθήσει πάντα να κάνει.
Με τον διακόπτη `--soft ', απλά θα σταματήσει εκεί.
Τώρα ας σταθούμε λίγο σε αυτό το διάγραμμα και για να συνειδητοποιήσουμε τι συνέβη: ουσιαστικά ξέκανε την τελευταία εντολή git commit
.
Όταν εκτελούμε την git commit
, το Git δημιουργεί μια νέα υποβολή και μετακινεί τον κλάδο στον οποίο δείχνει ο HEAD σε αυτήν.
Όταν επαναφέρουμε (reset
) στον HEAD~
(τον γονέα του HEAD
), μετακινούμε τον κλάδο πίσω στο σημείο στο οποίο βρισκόταν, χωρίς να αλλάξουμε τον Ευρετήριο ή τον Κατάλογο Εργασίας.
Θα μπορούσαμε τώρα να ενημερώσουμε τον Ευρετήριο και να εκτελέσουμε ξανά την git commit
για να ολοκληρώσουμε τι θα έκανε η git commit --amend
(βλ. ενότητα Αλλαγή της τελευταίας υποβολής).
Βήμα 2: Ενημέρωση του Ευρετηρίου (--mixed
)
Υπόψη ότι αν αν εκτελέσουμε την git status
τώρα, θα δούμε με πράσινο τη διαφορά μεταξύ του Ευρετηρίου και του τι είναι ο νέος HEAD.
Το επόμενο πράγμα που θα κάνει η reset
είναι να ενημερώσει το Ευρετήριο με τα περιεχόμενα εκείνου του στιγμιότυπου στο οποίο δείχνει τώρα ο HEAD.

Εάν καθορίσουμε την επιλογή --mixed
, η reset
θα σταματήσει σε αυτό το σημείο.
Αυτή είναι και η προεπιλογή, οπότε αν δεν καθορίσουμε καμία επιλογή (μόνο git reset HEAD~
σε αυτήν την περίπτωση), η εντολή θα σταματήσει εδώ.
Τώρα ας σταθούμε για λίγο σε αυτό το διάγραμμα και να συνειδητοποιήσουμε τι συνέβη: πάλι ξέκανε την τελευταία μας υποβολή, αλλά επίσης αφαίρεσε ό,τι υπήρχε στο στάδιο καταχώρισης.
Επιστρέψαμε στο σημείο που είμασταν πριν εκτελέσουμε τις εντολές git add
και git commit
.
Βήμα 3: Ενημέρωση του Καταλόγου Εργασίας (--hard
)
Το τρίτο πράγμα που μπορεί να κάνει η reset
είναι να κάνει τον Κατάλογο Εργασίας να είναι ίδιος με το Ευρετήριο.
Αν χρησιμοποιήσουμε την επιλογή --hard
, θα συνεχίσει να κάνει ακριβώς αυτό.

Ας αναλογιστούμε λοιπόν τι συνέβη.
Ξεκάναμε την τελευταία υποβολή μας, τις εντολές git add
και git commit
και όλη την εργασία που κάναμε στον Κατάλογο Εργασίας μας.
Είναι σημαντικό να σημειωθεί ότι αυτή η σημαία (--hard
) είναι ο μόνος τρόπος για να γίνει η εντολή reset
επικίνδυνη και μια από τις ελάχιστες περιπτώσεις όπου το Git πραγματικά θα καταστρέψει δεδομένα.
Οποιαδήποτε άλλη επίκληση της reset
μπορεί εύκολα να αναιρεθεί, αλλά η επιλογή --hard
δεν μπορεί, αφού αντικαθιστά με το ζόρι τα αρχεία στον Κατάλογο Εργασίας.
Στη συγκεκριμένη περίπτωση, εξακολουθούμε να έχουμε την έκδοση v3 του αρχείου μας σε μια υποβολή στη βάση δεδομένων του Git και θα μπορούσαμε να την επαναφέρουμε εξετάζοντας το reflog
μας, αλλά αν δεν το είχαμε υποβάλει, το Git θα είχε και πάλι αντικαταστήσει το αρχείο και αυτήν τη φορά δεν θα ήταν ανακτήσιμο.
Ανακεφαλαίωση
Η εντολή reset
αντικαθιστά αυτά τα τρία δέντρα με συγκεκριμένη σειρά και σταματά όταν της λέμε:
-
Μετακινεί τον κλάδο στον οποίο δείχνει ο HEAD (εάν
--soft
, σταμάτα εδώ) -
Κάνει το Ευρετήριο να είναι ιδιο με τον HEAD (εάν όχι
--hard
, σταμάτα εδώ) -
Κάνει τον Κατάλογο Εργασίας να μοιάζει με το Ευρετήριο.
Επαναφορά με διαδρομή
Τα προηγούμενα καλύπτουν τη συμπεριφορά της reset
στη βασική της μορφή, αλλά μπορούμε επίσης να της παράσχουμε μία διαδρομή στην οποία να δράσει.
Αν καθορίσουμε μια διαδρομή, η reset
θα παραλείψει το Βήμα 1 και θα περιορίσει το υπόλοιπο των ενεργειών της σε ένα συγκεκριμένο αρχείο ή σύνολο αρχείων.
Αυτό πραγματικά έχει μία λογική —ο HEAD είναι απλώς ένας δείκτης και δεν μπορεί να δείχνει σε ένα τμήμα μίας υποβολής και σε ένα τμήμα μίας άλλης.
Αλλά το Ευρετήριο και ο Κατάλογος Εργασίας μπορούν να ενημερώνονται εν μέρει, οπότε η reset
συνεχίζει με τα Bήματα 2 και 3.
Ας υποθέσουμε, λοιπόν, ότι τρέχουμε την git reset file.txt
.
Αυτή η φόρμα (αφού δεν έχουμε καθορίσει τον αριθμό SHA-1 μιας υποβολής ή έναν κλάδο και δεν έχουμε ορίσει --soft
ή --hard
) είναι συντομογραφία της git reset --mixed HEAD file.txt
, η οποίο θα:
-
Μετακινήσει τον κλάδο στον οποίο δείχνει ο HEAD (παρακάμπτεται)
-
Κάνει το Ευρετήριο να μοιάζει με τον HEAD (σταμάτα εδώ)
Έτσι, ουσιαστικά απλά αντιγράφει το file.txt
από τον HEAD στο Ευρετήριο.

Αυτό έχει το πρακτικό αποτέλεσμα της αφαίρεσης του αρχείου από το στάδιο καταχώρισης.
Αν κοιτάξουμε το διάγραμμα για αυτήν την εντολή και σκεφτούμε τι κάνει η git add
, είναι ακριβώς το αντίθετο.

Αυτός είναι ο λόγος για τον οποίο η έξοδος της εντολής git status
υπονοεί ότι την εκτελούμε για να αφαιρέσουμε ένα αρχείο από το στάδιο καταχώρισης.
(Περισσότερα σχετικά με αυτό υπάρχουν στην ενότητα Αφαίρεση αρχείου από το στάδιο καταχώρισης.)
Θα μπορούσαμε εξίσου εύκολα να μην αφήσουμε τον Git να υποθέσει ότι εννοούσαμε “έλξε τα δεδομένα από τον HEAD”, καθορίζοντας μια συγκεκριμένη υποβολή από την οποία θέλαμε αν έλξουμε αυτήν την έκδοση του αρχείου.
Απλά θα έπρεπε να τρέξουμε κάτι σαν την git reset eb43bf file.txt
.

Αυτό ουσιαστικά κάνει το ίδιο πράγμα με το να είχαμε επαναφέρει το περιεχόμενο του αρχείου στη v1 στον Κατάλογο Εργασίας, να τρέξουμε git add
σε αυτό και στη συνέχεια να το επαναφέρουμε ξανά στην v3 (χωρίς στην πραγματικότητα να περάσουμε όλα αυτά τα στάδια).
Αν εκτελέσουμε τώρα την git commit
, θα καταγράψει μια αλλαγή που θα επαναφέρει αυτό το αρχείο πίσω στην v1, παρόλο που στην πραγματικότητα ποτέ δεν το ξαναείχαμε στον Κατάλογο Εργασίας .
Είναι επίσης ενδιαφέρον να σημειώσουμε ότι όπως και η git add
, η εντολή reset
θα δέχεται μια επιλογή --patch
για την αφαίρεση από το στάδιο καταχώρισης περιεχομένου κομμάτι-κομμάτι.
Επομένως, μπορούμε να αφαιρέσουμε από το στάδιο καταχώρισης ή να επαναφέρουμε περιεχόμενο, επιλεκτικά.
ert content.
Συναρμογή
Ας δούμε πώς να κάνουμε κάτι ενδιαφέρον με αυτήν τη νέα δύναμη —τη συναρμογή υποβολών.
Ας πούμε ότι έχουμε μια σειρά υποβολών με μηνύματα όπως oops.
, WIP
και forgot this file
.
Μπορούμε να χρησιμοποιήσουμε την reset
για να τα συναρμόσουμε γρήγορα και εύκολα σε μια ενιαία υποβολή που μας κάνει να φανούμε πραγματικά έξυπνοι.
(Στην ενότητα Squashing Commits υπάρχει ένας άλλος τρόπος για να το κάνουμε αυτό, αλλά σε αυτό το παράδειγμα θα χρησιμοποιήσουμε τη reset επειδή είναι απλούστερο.)
Ας υποθέσουμε ότι έχουμε ένα έργο στο οποίο η πρώτη υποβολή έχει ένα αρχείο, η δεύτερη υποβολή προσθέτει ένα νέο αρχείο και αλλάζει το πρώτο, και η τρίτη υποβολή αλλάζει το πρώτο αρχείο για άλλη μία φορά. Η δεύτερη υποβολή ήταν έργο σε εξέλιξη και θέλουμε να τη συναρμόσουμε με την πρώτη.

Μπορούμε να εκτελέσουμε την git reset --soft HEAD~2
για να μετακινήσουμε τον κλάδο HEAD πίσω σε μια παλαιότερη υποβολή (την πρώτη υποβολή που θέλουμε να κρατήσουμε):

Στη συνέχεια εκτελούμε ξανά την git commit
:

Τώρα μπορούμε να δούμε ότι το προσβάσιμο ιστορικό μας, δηλαδή το ιστορικό που θα ωθήσουμε, τώρα μοιάζει σαν να είχαμε μία υποβολή με το αρχείο file-a.txt
(v1), και στη συνέχεια μία δεύτερη που τροποποίησε το file-a.txt
στο v3 και πρόσθεσε το file-b.txt
.
Η υποβολη με την έκδοση v2 του αρχείου δεν βρίσκεται πλέον στο ιστορικό.
Check out
Τέλος, θα μπορούσε να αναρωτηθεί κανείς ποια είναι η διαφορά ανάμεσα στις checkout
και reset
.
Όπως η reset
, έτσι και η checkout
χειρίζεται τα τρία δέντρα και είναι λίγο διαφορετική ανάλογα με το αν της δίνουμε και μια διαδρομή αρχείου ή όχι.
Χωρίς διαδρομή
Το τρέξιμο της git checkout [branch]
είναι αρκετά παρόμοιο με το τρέξιμο της git reset --hard [branch]
επειδή ενημερώνει και τα τρία δέντρα ώστε να μοιάζουν με τον [branch]
, αλλά υπάρχουν δύο σημαντικές διαφορές.
Καταρχάς, σε αντίθεση με τη reset --hard
, η checkout
είναι ασφαλής για τον Κατάλογο Εργασίας· θα ελέγξει ώστε να βεβαιωθεί ότι δεν πετάει αρχεία που έχουν αλλαγές.
Στην πραγματικότητα, είναι λίγο πιο έξυπνο από αυτό —προσπαθεί να κάνει μια τετριμμένη συγχώνευση στον Κατάλογο Εργασίας, έτσι ώστε όλα τα αρχεία που δεν έχουμε αλλάξει να ενημερωθούν.
Αντίθετα η reset --hard
απλά θα αντικαταστήσει τα πάντα χωρίς κανέναν έλεγχο.
Η δεύτερη σημαντική διαφορά είναι ο τρόπος ενημέρωσης του HEAD.
Ενώ η reset
μετακινεί τον κλάδο στον οποίο ο HEAD, η checkout
θα μετακινήσει τον ίδιο τον HEAD για να δείξει σε κάποιον άλλο κλάδο.
Για παράδειγμα, ας πούμε ότι έχουμε τους κλάδους master
και develop
που δείχνουν σε διαφορετικές υποβολές και αυτήν τη στιγμή βρισκόμαστε στον develop
(άρα ο HEAD δείχνει σε αυτόν).
Εάν εκτελέσουμε την git reset master
, ο develop
θα δείχνει τώρα στην ίδια υποβολή που δείχνει ο master
.
Αν αντίθετα τρέξουμε τη git master checkout
, δεν θα κινηθεί ο develop
αλλά ο HEAD
.
Ο HEAD θα δείχνει τώρα στον master
.
Επομένως και στις δύο περιπτώσεις ο HEAD
μετακινείται, ώστε να δείχνει στην υποβολή A, αλλά το πώς γίνεται αυτό είναι πολύ διαφορετικό.
Η reset
θα μετακινήσει τον κλάδο στον οποίο δείχνει ο HEAD
ενώ η checkout
μετακινεί τον ίδιο το HEAD.

Με διαδρομή
Ο άλλος τρόπος για να εκτελέσουμε την checkout
είναι με διαδρομή αρχείου, η οποία, όπως η reset
, δεν μετακινεί τον HEAD
.
Είναι ακριβώς όπως η git reset [branch] file
ως προς το ότι ενημερώνει το Ευρετήριο με αυτό το αρχείο σε αυτήν την υποβολή, αλλά επίσης αντικαθιστά το αρχείο στον Κατάλογο Εργασίας.
Θα ήταν ακριβώς όπως η git reset --hard [branch] file
(αν η reset
μας επέτρεπε να τρέξουμε κάτι τέτοιο) —δεν είναι ασφαλές για τον Κατάλογο Εργασίας και δεν μετακινεί το HEAD.
Επίσης, όπως οι git reset
και git add
, η checkout
δέχεται επιλογή --patch
για να μπορούμε να επαναφέρουμε επιλεκτικά τα περιεχόμενα του αρχείου κομμάτι-κομμάτι.
Ανακεφαλαίωση
Πλέον καταλαβαίνουμε περισσότερο και αισθανόμαστε πιο άνετα με την εντολή reset
, αλλά ίσως εξακολουθούμε να είμαστε λίγο μπερδεμένοι σχετικά με τον τρόπο που διαφέρει από την checkout
και σίγουρα δεν μπορούμε να θυμηθούμε όλους τους κανόνες των διαφορετικών κλήσεων.
Ακολουθεί ένα σκονάκι σχετικά με το ποιες εντολές επηρεάζουν ποια δέντρα.
Η στήλη HEAD
γίνεται REF
αν αυτή η εντολή μετακινεί την αναφορά (κλάδο) στην οποία δείχνει ο HEAD
και HEAD
αν μετακινεί τον ίδιο τον HEAD
.
Ιδιαίτερη προσοχή χρειάζεται η στήλη “Ασφαλής για ΚΕ;” —αν αναφέρει ΟΧΙ, τότε πρέπει να ξανασκεφτούμε αν πραγματικά θέλουμε να εκτελέσουμε αυτήν την εντολή.
HEAD | Ευρετήριο | Κατάλογος Εργασίας | Ασφαλές για ΚΕ; | |
---|---|---|---|---|
Επίπεδο υποβολής |
||||
|
REF |
ΟΧΙ |
ΟΧΙ |
ΝΑΙ |
|
REF |
ΝΑΙ |
ΟΧΙ |
ΝΑΙ |
|
REF |
ΝΑΙ |
ΝΑΙ |
ΟΧΙ |
|
HEAD |
ΝΑΙ |
ΝΑΙ |
ΝΑΙ |
Επίπεδο αρχείου |
||||
|
ΟΧΙ |
ΝΑΙ |
ΟΧΙ |
ΝΑΙ |
|
ΟΧΙ |
ΝΑΙ |
ΝΑΙ |
ΟΧΙ |