-
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 Αποθέματα και Καθαρισμός
- 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 στο Visual Studio Code
- A1.4 Git στο IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git στο Sublime Text
- A1.6 Το Git στο Bash
- A1.7 Το Git στο Zsh
- A1.8 Το Git στο Powershell
- A1.9 Ανακεφαλαίωση
-
A2. Appendix B: Ενσωμάτωση του Git στις εφαρμογές μας
- A2.1 Γραμμή εντολών Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
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 Εντολές διοχέτευσης
3.5 Διακλαδώσεις στο Git - Απομακρυσμένοι κλάδοι
Απομακρυσμένοι κλάδοι
Οι απομακρυσμένες αναφορές είναι αναφορές (δείκτες) που βρίσκονται στα απομακρυσμένα αποθετήριά μας και συμπεριλαμβάνουν κλάδους, ετικέτες και ούτω καθεξής.
Μπορούμε να πάρουμε μία πλήρη λίστα των απομακρυσμένων αναφορών με την εντολή git ls-remote <remote> ή git remote show <remote> για απομακρυσμένους κλάδους καθώς και άλλες πληροφορίες.
Παρόλα αυτά, ένας πιο συνηθισμένος τρόπος είναι να εκμεταλλευτούμε τους κλάδους απομακρυσμένης παρακολούθησης (remote-tracking branches).
Οι κλάδοι απομακρυσμένης παρακολούθησης είναι αναφορές στην κατάσταση απομακρυσμένων κλάδων. Είναι τοπικές αναφορές τις οποίες δεν μπορούμε να μετακινήσουμε· μετακινούνται αυτόματα όποτε υπάρχει κάποια δικτυακή επικοινωνία, ώστε να διασφαλίζεται η ακριβής αναπαράσταση της κατάστασης του απομακρυσμένου αποθετηρίου. Μπορούμε να τους σκέφτομαστε ως σελιδοδείκτες που μας θυμίζουν πού βρίσκονταν οι κλάδοι στα απομακρυσμένα αποθετήριά μας την τελευταία φορά που είχαμε συνδεθεί σε αυτά.
Έχουν τη μορφή <απομακρυσμένο-αποθετήριο>/<κλάδος> (<remote>/<branch>).
Για παράδειγμα, αν θέλουμε να δούμε σε ποια κατάσταση ήταν ο κλάδος master στο απομακρυσμένο αποθετήριό μας origin την τελευταία φορά που επικοινωνήσαμε μαζί του, θα πρέπει να μεταβούμε στον κλάδο origin/master.
Αν δουλεύαμε σε ένα θέμα με κάποιον συνεργάτη και αυτός είχε ωθήσει έναν κλάδο iss53, ενδεχομένως να είχαμε κι εμείς έναν δικό μας τοπικό κλάδο iss53, αλλά ο κλάδος στον διακομιστή θα αναπαρίστατο με τον κλάδο απομακρυσμένης παρακολούθησης origin/iss53.
Ίσως όλα αυτά φαίνονται συγκεχυμένα, οπότε ας τα ξεμπερδέψουμε με ένα παράδειγμα.
Ας υποθέσουμε ότι έχουμε έναν διακομιστή Git στο δίκτυό μας στη διεύθυνση git.ourcompany.com.
Αν τον κλωνοποιήσουμε, η εντολή clone του Git θα τον ονομάσει origin, θα τραβήξει όλα τα δεδομένα και θα δημιουργήσει έναν δείκτη που δείχνει εκεί όπου βρίσκεται ο κλάδος του master και θα τον ονομάσει τοπικά origin/master.
Το Git επίσης θα δημιουργήσει έναν τοπικό κλάδο master για εμάς, ώστε να έχουμε έναν κλάδο στον οποίο μπορούμε να δουλέψουμε. Αυτός ο κλάδος ξεκινά από το ίδιο σημείο από όπου ξεκινά και ο κλάδος master του αποθετηρίου origin.
|
Note
|
Το αποθετήριο “origin” δεν είναι κάτι ιδιαίτερο
Ακριβώς όπως το όνομα κλάδου “master” δεν έχει κάποια ιδιαίτερη σημασία στο Git, το ίδιο συμβαίνει και με το όνομα κλάδου “origin”.
Ενώ “master” είναι το προεπιλεγμένο όνομα για τον αρχικό κλάδο όταν τρέχετε την εντολή |
Αν κάνουμε λίγη δουλίτσα στον τοπικό μας κλάδο master και στο μεταξύ κάποιος άλλος ωθήσει στο git.ourcompany.com και ενημερώσει τον κλάδο master, τότε τα δύο ιστορικά θα προχωρήσουν διαφορετικά.
Επιπλέον, για όσο χρονικό διάστημε δεν είμαστε συνδεδεμένοι με τον διακομιστή origin, ο δείκτης μας origin/master δεν μετακινείται.
Για να συγχρονίσουμε τη δουλειά μας με κάποιο απομακρυσμένο αποθετήριο, τρέχουμε την εντολή git fetch <remote> (στην περίπτωσή μας git fetch <origin>).
Αυτή η εντολή αναζητά ποιος διακομιστής είναι ο “origin” (στη συγκεκριμένη περίπτωση είναι ο git.ourcompany.com), ανακτά (fetch) από αυτόν ό,τι δεδομένα δεν έχουμε ακόμα και ενημερώνει την τοπική βάση δεδομένων μας, μετακινώντας τον δείκτη origin/master στη νέα του πιο ενημερωμένη θέση.
git fetch ενημερώνει τους κλάδους απομακρυσμένης παρακολούθησηςΓια να δείξουμε τι συμβαίνει όταν έχουμε πολλούς απομακρυσμένους διακομιστές και με τι μοιάζουν οι απομακρυσμένοι κλάδοι των απομακρυσμένων έργων, ας υποθέσουμε ότι έχουμε ένα άλλο εσωτερικό διακομιστή Git που χρησιμοποιείται μόνον για ανάπτυξη κώδικα από μία συγκεκριμένη ομάδα.
Αυτός ο διακομιστής βρίσκεται στη διεύθυνση git.team1.ourcompany.com.
Μπορούμε να τον προσθέσουμε στο έργο στο οποίο δουλεύουμε ως μία νέα απομακρυσμένη αναφορά εκτελώντας την εντολή git remote add όπως εξηγήσαμε στο κεφάλαιο Τα θεμελιώδη στοιχεία του Git.
Ονομάστε αυτό τον απομακρυσμένο διακομιστή teamone, που θα είναι και το σύντομο όνομα του παραπάνω URL.
Τώρα μπορούμε να τρέξουμε την εντολή git fetch teamone για να ανακτήσουμε οτιδήποτε ο απομακρυσμένος διακομιστής teamone έχει που δεν το έχουμε ακόμα εμείς.
Επειδή ο διακομιστής έχει ένα υποσύνολο από τα δεδομένα που έχει ο διακομιστής origin αυτή τη στιγμή, το Git δεν ανακτά δεδομένα, αλλά τοποθετεί έναν κλάδο απομακρυσμένης παρακολούθησης με όνομα teamone/master να δείχνει στην υποβολή που έχει ο teamone στον δικό του κλάδο master.
teamone/master
Ωθήσεις
Όταν θέλουμε να μοιραστούμε έναν κλάδο με τον υπόλοιπο κόσμο, πρέπει να τον ωθήσουμε σε έναν απομακρυσμένο διακομιστή στον οποίο έχουμε δικαίωμα εγγραφής (write access). Οι τοπικοί μας κλάδοι δεν συγχρονίζονται αυτόματα με τους απομακρυσμένους διακομιστές στους οποίους έχουμε δικαίωμα να αποθηκεύσουμε — πρέπει να ωθήσουμε χειροκίνητα τους κλάδους που θέλουμε να κοινοποιήσουμε σε άλλους. Με αυτό τον τρόπο, μπορούμε να χρησιμοποιήσουμε ιδιωτικούς κλάδους για δουλειά που δεν θέλουμε να μοιραστούμε με άλλους και να ωθούμε μόνον τους θεματικούς κλάδους στους οποίους θέλουμε να συνεργαστούμε.
Αν έχουμε έναν κλάδο με όνομα serverfix στον οποίο θέλουμε να δουλέψουμε με άλλους, μπορούμε να τον ωθήσουμε με τον ίδιο τρόπο που ωθήσαμε τον πρώτο μας κλάδο.
Εκτελούμε την εντολή git push <remote> <branch>:
$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
* [new branch] serverfix -> serverfix
Στην πραγματικότητα αυτή η εντολή είναι μία συντόμευση.
Το Git αναπτύσσει αυτόματα το όνομα κλάδου serverfix σε refs/heads/serverfix:refs/heads/serverfix, που σημαίνει “Πάρε τον τοπικό μου κλάδο serverfix και ώθησέ τον ώστε να ενημερωθεί ο αντίστοιχος κλάδος serverfix του απομακρυσμένου διακομιστή”.
Θα δούμε πιο λεπτομερώς το κομμάτι refs/heads/ στην ενότητα Εσωτερική λειτουργία του Git· προς το παρόν μπορούμε να το αγνοήσουμε.
Επίσης μπορούμε να τρέξουμε την εντολή git push origin serverfix:serverfix, που κάνει ακριβώς το ίδιο πράγμα — λέει, “Πάρε το δικό μου serverfix και κάνε τον, το serverfix του απομακρυσμένου διακομιστή”.
Χρησιμοποιήσουμε αυτή την εντολή για να ωθήσουμε έναν τοπικό κλάδο σε έναν απομακρυσμένο που έχει διαφορετικό όνομα.
Αν δεν θέλουμε να ονομάζεται serverfix στο απομακρυσμένο αποθετήριο, τότε μπορούμε να τρέξουμε την εντολή git push origin serverfix:awesomebranch ώστε να ωθήσουμε τον τοπικό μας κλάδο serverfix στον κλάδο με όνομα awesomebranch στο απομακρυσμένο αποθετήριο.
|
Note
|
Δεν χρειάζεται να γράφετε τον κωδικό πρόσβασής σας κάθε φορά.
Αν θέλετε να ωθήσετε κάτι σε ένα URL με HTTPS, ο διακομιστής Git θα σας ζητήσει το όνομα χρήστη και τον κωδικό σας για ταυτοποίηση. Η προεπιλεγμένη ρύθμιση είναι να σας ζητήσει αυτή την πληροφορία στο τερματικό, ώστε ο διακομιστής να αποφανθεί αν έχετε το δικαίωμα να ωθήσετε αλλαγές. Αν δεν θέλετε να πληκτρολογείτε τον κωδικό πρόσβασής σας κάθε φορά που ωθείτε κάτι, μπορείτε να ορίσετε μία “προσωρινή μνήμη διαπιστευτηρίων” (“credential cache”).
Ο πιο απλός τρόπος είναι να παραμένουν στη μνήμη για μερικά λεπτά, κάτι που μπορεί να οριστεί εύκολα με την εντολή Περισσότερες πληροφορίες σχετικά με τις διάφορες επιλογές προσωρινής αποθήκευσης διαπιστευτηρίων βλ. Αποθήκευση διαπιστευτηρίων. |
Την επόμενη φορά που κάποιος από τους συνεργάτες μας ανακτήσει δεδομένα από τον διακομιστή, θα πάρει μία αναφορά που θα δείχνει εκεί όπου βρίσκεται ο κλάδος serverfix του διακομιστή, δηλαδή κάτω από τον απομακρυσμένο κλάδο origin/serverfix:
$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
* [new branch] serverfix -> origin/serverfix
Είναι σημαντικό να σημειώσουμε πως όταν εκτελούμε μία εντολή git fetch, που φέρνει νέους κλάδους απομακρυσμένης παρακολούθησης στον υπολογιστή μας, δεν έχουμε αυτόματα τοπικά επεξεργάσιμα αρχεία.
Με άλλα λόγια, σε αυτή την περίπτωση, δεν έχουμε έναν νέο κλάδο serverfix — έχουμε μόνον έναν δείκτη στον origin/serverfix που δεν μπορούμε να τροποποιήσουμε.
Για να συγχωνεύσουμε αυτή τη δουλειά στον τρέχοντα κλάδο εργασίας μας, μπορούμε να τρέξουμε την εντολή git merge origin/serverfix.
Αν θέλουμε τον δικό μας κλάδο serverfix στον οποίο μπορούμε να εργαστούμε, μπορούμε να τον βασίσουμε στον κλάδο απομακρυσμένης παρακολούθησης:
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
Η παραπάνω εντολή μας δίνει έναν τοπικό κλάδο στον οποίο μπορούμε να δουλέψουμε και ξεκινά από το σημείο που βρίσκεται ο κλάδος origin/serverfix.
Παρακολούθηση κλάδων
Όταν κάνουμε checkout έναν τοπικό κλάδο από έναν κλάδο απομακρυσμένης παρακολούθησης, αυτόματα δημιουργείται ένας “κλάδος παρακολούθησης” (και ο κλάδος που παρακολουθείται ονομάζεται “κλάδος upstream”).
Οι κλάδοι παρακολούθησης είναι τοπικοί κλάδοι που σχετίζονται άμεσα με κάποιο απομακρυσμένο κλάδο.
Αν είμαστε σε έναν κλάδο παρακολούθησης και πληκτρολογήσουμε git pull, το Git αυτόματα γνωρίζει από ποιον διακομιστή να ανακτήσει και σε ποιον κλάδο να συγχωνεύσει.
Όταν κλωνοποιούμε ένα αποθετήριο, αυτό δημιουργεί αυτόματα έναν κλάδο master που παρακολουθεί τον κλάδο origin/master.
Όμως μπορούμε να ορίσουμε και άλλους κλάδους παρακολούθησης, αν θέλουμε — κλάδους που παρακολουθούν κλάδους σε άλλα απομακρυσμένα αποθετήρια ή δεν παρακολουθούν τον κλάδο master.
Η πιο απλή περίπτωση είναι αυτή που μόλις είδαμε, η εντολή git checkout -b <branch> <remote>/<branch>.
Αυτή η περίπτωση είναι τόσο συνηθισμένη που το Git μας παρέχει την επιλογή --track:
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
Μάλιστα, είναι τόσο συνηθισμένη που υπάρχει συντόμευση για την παραπάνω επιλογή. Αν το όνομα του κλάδου στον οποίο προσπαθούμε να μεταβούμε (α) δεν υπάρχει και (β) έχει το ίδιο όνομα με μόνο έναν απομακρυσμένο, το Git θα δημιουργήσει αυτόματα έναν κλάδο παρακολούθησης.
$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
Για να ορίσουμε έναν τοπικό κλάδο με διαφορετικό όνομα από αυτό του απομακρυσμένου κλάδου, μπορούμε εύκολα να χρησιμοποιήσουμε την πρώτη εκδοχή με διαφορετικό όνομα τοπικού κλάδου:
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'
Τώρα ο τοπικός μας κλάδος sf θα τραβά αυτόματα από τον κλάδο origin/serverfix.
Αν έχουμε ήδη έναν τοπικό κλάδο και θέλουμε να τον συνδέσουμε με έναν απομακρυσμένο κλάδο που μόλις τραβήξαμε ή θέλουμε να αλλάξουμε τον κλάδο upstream που παρακολουθούμε, μπορούμε να χρησιμοποιήσουμε την επιλογή -u ή --set-upstream-to με την εντολή git branch ώστε να τον συνδέσουμε οποιαδήποτε στιγμή.
$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
|
Note
|
Συντόμευση upstream
Όταν έχετε ορίσει έναν κλάδο παρακολούθησης, μπορείτε να αναφερόσατε σε αυτόν ως |
Αν θέλουμε να δούμε ποιους κλάδους παρακολούθησης έχουμε ορίσει, μπορούμε να χρησιμοποιήσουμε την επιλογή -vv στην εντολή git branch.
Αυτή θα παραθέσει όλους τους τοπικούς κλάδους με περισσότερες πληροφορίες, όπως ποιον κλάδο παρακολουθεί κάθε κλάδος και αν ο τοπικός μας κλάδος προηγείται ή υστερεί σε σχέση με τον απομακρυσμένο κλάδο ή και τα δύο.
$ git branch -vv
iss53 7e424c3 [origin/iss53: ahead 2] Add forgotten brackets
master 1ae2a45 [origin/master] Deploy index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] This should do it
testing 5ea463a Try something new
Εδώ μπορούμε να δούμε ότι ο κλάδος μας iss53 παρακολουθεί τον origin/iss53 και “προηγείται” κατά δύο (ahead 2), δηλαδή έχουμε κάνει δύο υποβολές τοπικά που δεν έχουν ωθηθεί στον διακομιστή.
Επίσης μπορούμε να δούμε ότι ο τοπικός μας κλάδος master παρακολουθεί τον origin/master και είναι ενημερωμένος.
Στη συνέχεια βλέπουμε ότι ο κλάδος μας serverfix παρακολουθεί τον κλάδο server-fix-good στον διακομιστή teamone και προηγείται κατά τρεις και υστερεί κατά μία, που σημαίνει ότι υπάρχει μία υποβολή στον διακομιστή που δεν την έχουμε συγχωνεύσει ακόμη και τρεις τοπικές υποβολές που δεν έχουμε ωθήσει ακόμη.
Τέλος, βλέπουμε ότι ο κλάδος μας testing δεν παρακολουθεί κανέναν απομακρυσμένο κλάδο.
Είναι σημαντικό να σημειώσουμε ότι αυτοί οι αριθμοί είναι οι υποβολές από την τελευταία φορά που ανακτήσαμε (fetch) από τον κάθε διακομιστή.
Αυτή η εντολή δεν ρωτά τους διακομιστές, απλά μας λέει τι έχει ήδη αποθηκευμένο τοπικά από τους διακομιστές.
Αν θέλουμε εντελώς ενημερωμένους αριθμούς υποβολών με τις οποίες προηγείται και υστερεί ο κλάδος μας, πρέπει να τρέξουμε μία εντολή fetch προς όλους τους απομακρυσμένους πριν τρέξουμε την παραπάνω εντολή.
Αυτό μπορούμε να το κάνουμε ως εξής:
$ git fetch --all; git branch -vv
Ελκυσμοί
Ενώ η εντολή git fetch ανακτά όλες τις αλλαγές που δεν έχουμε ήδη από τον διακομιστή, δεν θα αλλάξει τον κατάλογο εργασίας μας καθόλου.
Απλά θα πάρει τα δεδομένα και θα μας αφήσει να τα συγχωνεύσουμε μόνοι μας.
Πάντως, υπάρχει η εντολή git pull η οποία ουσιαστικά στις περισσότερες περιπτώσεις είναι μία εντολή git fetch που ακολουθείται από μία εντολή git merge.
Αν έχουμε ορίσει κάποιον κλάδο παρακολούθησης όπως σας δείξαμε στην προηγούμενη ενότητα, είτε με ρητό ορισμό είτε επειδή τον έχουμε δημιουργήσει με τις εντολές clone ή checkout, η git pull θα αναζητήσει τον διακομιστή και κλάδο τον οποίο παρακολουθεί ο τρέχων κλάδος μας, θα ανακτήσει από τον διακομιστή και θα προσπαθήσει να συγχωνεύσει σε αυτό τον απομακρυσμένο κλάδο.
Διαγραφή απομακρυσμένων κλάδων
Ας υποθέσουμε ότι τελειώσαμε με τον απομακρυσμένο κλάδο — π.χ. οι συνεργάτες μας και εσείς τελειώσαμε με ένα χαρακτηριστικό και το έχουμε συγχωνεύσει στον κλάδο master του απομακρυσμένου αποθετηρίου (ή τέλος πάντων σε οποιονδήποτε κλάδο υπάρχει η ευσταθής έκδοσή του έργου μας).
Μπορούμε να διαγράψουμε τον απομακρυσμένο κλάδο χρησιμοποιώντας την επιλογή --delete στην εντολή git push.
Αν θέλουμε να διαγράψουμε τον κλάδο serverfix από τον διακομιστή, τρέχουμε τα παρακάτω:
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
- [deleted] serverfix
Βασικά αυτό που κάνει αυτή η εντολή είναι να απομακρύνει τον δείκτη από τον διακομιστή. Ο διακομιστής Git γενικά θα διατηρήσει τα δεδομένα εκεί για λίγο καιρό, μέχρι να τρέξει μία διαδικασία συλλογής σκουπιδιών (garbage collection) ώστε αν ο κλάδος διαγράφηκε κατά λάθος, να είναι εύκολο να αποκατασταθεί.