-
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.2 Διακλαδώσεις στο Git - Βασικές έννοιες διακλαδώσεων και συγχωνεύσεων
Βασικές έννοιες διακλαδώσεων και συγχωνεύσεων
Ας δούμε ένα απλό παράδειγμα διακλάδωσης και συγχώνευσης με μία ροή εργασίας που είναι πιθανό να χρησιμοποιήσουμε στον πραγματικό κόσμο. Θα ακολουθήσουμε τα παρακάτω βήματα:
-
Θα κάνουμε αλλαγές σε μία ιστοσελίδα.
-
Θα δημιουργήσουμε έναν κλάδο για μία νέα ιστορία χρήστη (user story) την οποία δουλεύουμε.
-
θα κάνουμε αλλαγές σε αυτό τον κλάδο.
Σε αυτό το σημείο θα δεχτούμε ένα τηλεφώνημα ότι υπάρχει ένα άλλο κρίσιμο πρόβλημα και πρέπει να αναπτύξουμε μία άμεση λύση. Θα κάνουμε τα παρακάτω:
-
Θα μεταβούμε στον κλάδο παραγωγής.
-
Θα δημιουργήσουμε έναν κλάδο στον οποίο θα προσθέσουμε την επείγουσα λυση (hotfix).
-
Αφού ο κώδικάς μας δοκιμαστεί, θα συγχωνεύσουμε τον κλάδο με το hotfix και θα τον ωθήσουμε στην παραγωγή.
-
Θα επιστρέψουμε στην αρχική ιστορία χρήστη και θα συνεχίσουμε να την δουλεύουμε.
Διακλαδώσεις — τα βασικά
Αρχικά ας υποθέσουμε ότι δουλεύουμε σε ένα έργο και έχουμε κάνει ήδη μερικές υποβολές στον κλάδο master.
Αποφασίζουμε ότι θα δουλέψουμε στο πρόβλημα #53 του συστήματος παρακολούθησης προβλημάτων που χρησιμοποιεί η εταιρεία μας.
Για να δημιουργήσουμε έναν κλάδο και να μεταβούμε σε αυτό συγχρόνως, μπορούμε να τρέξουμε την εντολή git checkout με τη σημαία -b:
$ git checkout -b iss53
Switched to a new branch "iss53"
Η παραπάνω εντολή είναι συντομογραφία για το εξής:
$ git branch iss53
$ git checkout iss53
Επεξεργαζόμαστε την ιστοσελίδα μας και κάνουμε μερικές υποβολές.
Με τις υποβολές ο κλάδος iss53 προχωρά, διότι τον έχουμε κάνει checkout (δηλαδή ο HEAD δείχνει σε αυτό τον κλάδο):
$ vim index.html
$ git commit -a -m 'Create new footer [issue 53]'
iss53 προχώρησε εξαιτίας των αλλαγών μας.Τώρα λαμβάνουμε το τηλεφώνημα ότι υπάρχει ένα άλλο επείγον πρόβλημα στην ιστοσελίδα και πρέπει να το αντιμετωπίσουμε αμέσως.
Στο Git, δεν είναι απαραίτητο να δουλέψουμε σε αυτό το πρόβλημα παράλληλα με τις αλλαγές που έχουμε ήδη κάνει στον κλάδο iss53, ούτε να καταβάλλουμε πολλή δουλειά ώστε να αναιρέσουμε τις αλλαγές που έχουμε ήδη κάνει και να δουλέψουμε στο επείγον πρόβλημα και να εφαρμόσουμε τη λύση μας σε ό,τι βρίσκεται εκείνη τη στιγμή στη γραμμή της παραγωγής.
Το μόνο που έχουμε να κάνουμε είναι να επιστρέψουμε στον κλάδο master.
Ωστόσο πριν το κάνουμε αυτό, σημειώστε ότι αν υπάρχουν στον κατάλογο εργασίας μας ή στον προθάλαμο αλλάγες που δεν έχουν υποβληθεί και έρχονται σε σύγκρουση με τον κλάδο στον οποίο θέλουμε να μεταβούμε, το Git δεν θα μας αφήσει να αλλάξουμε κλάδο.
Το καλύτερο είναι να έχουμε μία καθαρή κατασταση εργασίας όταν μεταβαίνουμε από έναν κλάδο σε άλλο.
Υπάρχουν τρόποι να παρακάμψουμε αυτή τη συμπεριφορά (με τις εντολές git stash και git commit --amend) που θα καλύψουμε στη συνέχεια, στην ενότητα Αποθέματα και Καθαρισμός.
Προς το παρόν, ας υποθέσουμε ότι έχουμε υποβάλλει όλες τις αλλαγές μας, ώστε να μπορέσουμε να επιστρέψουμε στον κλάδο master:
$ git checkout master
Switched to branch 'master'
Σε αυτό το σημείο, ο κατάλογος εργασίας του έργου μας βρίσκεται ακριβώς στην κατάσταση στην οποία βρισκόταν πριν ξεκινήσουμε να δουλεύουμε για το πρόβλημα #53 και μπορούμε να συγκεντρωθούμε στο hotfix. Αυτό είναι ένα σημαντικό σημείο που αξίζει να θυμόμαστε: όταν μεταβαίνουμε από έναν κλάδο σε έναν άλλο, το Git επαναφέρει τον κατάλογο εργασίας στην κατάσταση που είχε την τελευταία φορά που είχαμε κάνει κάποια υποβολή (commit) σε αυτό τον κλάδο. Προσθέτει, διαγράφει και τροποποιεί αρχεία αυτόματα ώστε να βεβαιωθεί ότι το αντίγραφο εργασίας μας είναι ίδιο με την κατάσταση του κλάδου αμέσως μετά την τελευταία υποβολή σε αυτό τον κλάδο.
Στη συνέχεια, πρέπει να δουλέψουμε για το hotfix.
Ας φτιάξουμε έναν κλάδο hotfix στον οποίο θα εργαστούμε:
$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'Fix broken email address'
[hotfix 1fb7853] Fix broken email address
1 file changed, 2 insertions(+)
master
Τώρα μπορούμε να κάνουμε τα τεστ μας, να βεβαιωθούμε ότι ο κώδικάς μας κάνει αυτό που θέλουμε, να τον συγχωνεύσουμε με τον κλάδο master και να τον προωθήσουμε στην παραγωγή.
Το τελευταίο το κάνουμε με την εντολή git merge:
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
Σε αυτή τη συγχώνευση υπάρχει η έκφραση “fast-forward”.
Επειδή η υποβολή C4 στον οποίο έδειχνε ο κλάδος hotfix τον οποίο συγχωνεύσαμε ήταν ακριβώς μπροστά από την υποβολή C2 στην οποία είμαστε, το Git απλά μετακίνησε τον δείκτη προς τα εμπρός.
Με άλλα λόγια όταν προσπαθούμε να συγχωνεύσουμε μία υποβολή με μία άλλη υποβολή στην οποία μπορούμε να φτάσουμε ακολουθώντας το ιστορικό της πρώτης, το Git απλοποιεί τη διαδικασία μετακινώντας τον δείκτη σε εκείνο το σημείο, διότι δεν υπάρχει άλλη αποκλίνουσα εργασία που θα πρέπει να συγχωνευτεί — αυτό ονομάζεται “ταχυπροώθηση” (“fast-forward”).
Η αλλαγή μας τώρα υπάρχει στο στιγμιότυπο της υποβολής στην οποία δείχνει ο κλάδος master και μπορούμε να δημοσιεύσουμε τη διόρθωσή μας.
master ταχυπροωθήθηκε στον κλάδο hotfix.Αφού ο σημαντικότατος διορθωτικός μας κώδικας έχει δημοσιευτεί, είμαστε έτοιμοι να επανέλθουμε στην εργασία την οποία κάναμε πριν μας διακόψει το τηλεφώνημα.
Προτού όμως συνεχίσουμε, θα διαγράψουμε τον κλάδο hotfix, διότι δεν τον χρειαζόμαστε πλέον — ο κλάδος master δείχνει ακριβώς στην ίδια θέση.
Μπορούμε να τον διαγράψουμε με την επιλογή -d στην εντολή git branch:
$ git branch -d hotfix
Deleted branch hotfix (3a0874c).
Τώρα μπορούμε να επιστρέψουμε στον κλάδο εργασίας του προβλήματος #53 και να συνεχίσουμε να δουλεύουμε σ' αυτό.
$ git checkout iss53
Switched to branch "iss53"
$ vim index.html
$ git commit -a -m 'Finish the new footer [issue 53]'
[iss53 ad82d7a] Finish the new footer [issue 53]
1 file changed, 1 insertion(+)
iss53
Σε αυτό το σημείο αξίζει να σημειωθεί ότι οι αλλαγές που κάναμε στον κλάδο hotfix δεν περιέχονται στα αρχεία του κλάδου iss53.
Αν θέλουμε να τα ενσωματώσουμε, μπορούμε να συγχωνεύσουμε τον κλάδο master στον κλάδο iss53 τρέχοντας την εντολή git merge master ή μπορούμε να αναβάλουμε την ενσωμάτωση αυτών των αλλαγών μέχρι να αποφασίσουμε να ξαναβάλουμε τον κλάδο iss53 μέσα στον κλάδο master αργότερα.
Συγχωνεύσεις — τα βασικά
Ας υποθέσουμε τώρα ότι έχουμε αποφασίσει ότι η εργασία μας για το πρόβλημα #53 έχει ολοκληρωθεί και είναι έτοιμη να συγχωνευτεί στον κλάδο master.
Για να το κάνουμε αυτό, αρκεί να συγχωνεύσουμε τον κλάδο iss53 στον κλάδο master, λίγο-πολύ με τον ίδιο τρόπο που συγχωνεύσαμε τον κλάδο hotfix προηγουμένως.
Το μόνο που έχουμε να κάνουμε είναι να μεταβούμε στον κλάδο στον οποίο θέλουμε να ενσωματώσουμε τον άλλο κλάδο και να τρέξουμε την εντολή git merge:
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)
Το μήνυμα στην οθόνη διαφέρει λίγο από εκείνο που πήραμε όταν συγχωνεύσαμε τον κλάδο hotfix προηγουμένως.
Σε αυτή την περίπτωση, το ιστορικό των αλλαγών απέκλινε σε κάποιο παλιότερο σημείο.
Επειδή η υποβολή στον κλάδο στον οποίο βρίσκεστε δεν είναι άμεσος πρόγονος του κλάδου τον οποίο ενσωματώνουμε, το Git πρέπει να κάνει λίγη δουλίτσα.
Σε αυτή την περίπτωση, το Git κάνει μία απλή τριμερή συγχώνευση, χρησιμοποιώντας τα στιγμιότυπα στο τέλος του κάθε κλάδου και τον κοινό πρόγονο των δύο.
Αντί, λοιπόν, το Git να μετακινήσει τον δείκτη του κλάδου προς τα εμπρός, δημιουργεί ένα νέο στιγμιότυπο που προκύπτει από αυτή την τριμερή συγχώνευση και αυτομάτως δημιουργεί μία νέα υποβολή που δείχνει σε αυτό το στιγμιότυπο. Αυτό ονομάζεται υποβολή συγχώνευσης (merge commit) και έχει την ιδιαιτερότητα ότι έχει περισσότερους από έναν γονείς.
Τώρα που η εργασία μας έχει συγχωνευτεί, δεν χρειαζόμαστε πλέον τον κλάδο iss53.
Μπορούμε να κλείσουμε το ζήτημα στο σύστημα παρακολούθησης προβλημάτων μας και να διαγράψουμε τον κλάδο:
$ git branch -d iss53
Συγκρούσεις συγχωνεύσεων — τα βασικά
Ενίοτε, η διαδικασία συγχώνευσης δεν εξελίσσεται τόσο ομαλά. Αν έχουμε τροποποιήσει το ίδιο σημείο του ίδιου αρχείου με διαφορετικό τρόπο στους δύο κλάδους που συγχωνεύουμε, το Git δεν θα μπορέσει να τους συγχωνεύσει παστρικά. Αν η λύση μας για το πρόβλημα #53 και η λύση μας για το επείγον πρόβλημα τροποποίησαν το ίδιο τμήμα ενός αρχείου, θα πάρουμε ένα μήνυμα σύγκρουσης συγχώνευσης περίπου σαν το παρακάτω:
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Το Git δεν μπόρεσε να δημιουργήσει αυτόματα μία νέα υποβολή συγχώνευσης.
Διέκοψε τη διαδικασία, ώστε να επιλύσουμε τη σύγκρουση.
Αν θέλουμε να δούμε ποια αρχεία δεν έχουν συγχωνευτεί σε οποιοδήπτε σημείο μετά από μία σύγκρουση συγχώνευσης, τρέχουμε την εντολή git status:
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")
Οτιδήποτε εμπλέκεται σε σύγκρουση συγχώνευσης και δεν έχει επιλυθεί καταγράφεται ως unmerged. Το Git προσθέτει τυποποιημένους σημειωτές “επίλυσης σύγκρουσης” στα αρχεία που εμπλέκονται σε συγκρούσεις, ώστε να τα ανοίξουμε και να επιλύσουμε αυτές τις διαφορές. Το αρχείο μας θα περιέχει ένα τμήμα που θα φαίνεται κάπως έτσι:
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
Αυτό σημαίνει πως η έκδοση στο HEAD (δηλαδή το master κλάδο, γιατί σε αυτόν ήμασταν όταν τρέξαμε στην εντολή συγχώνευσης) είναι το πάνω μέρος του μπλόκ (οτιδήποτε πάνω από =======), ενώ η έκδοση του κλάδου iss53 είναι ότι φαίνεται στο κάτω μέρος του μπλόκ.
Προκειμένου να επιλύσουμε τη σύγκρουση, πρέπει είτε να επιλέξουμε τη μία ή την άλλη έκδοση είτε να συγχωνεύσουμε τα περιεχόμενα οι ίδιοι.
Για παράδειγμα, μπορεί να θέλουμε να επιλύσουμε αυτή τη σύγκρουση αντικαθιστώντας ολόκληρο το τμήμα με το παρακάτω:
<div id="footer">
please contact us at email.support@github.com
</div>
Αυτή η επίλυση της σύγκρουσης περιέχει λίγο από κάθε τμήμα και οι γραμμές που περιέχουν τα <<<<<<<, ======= και >>>>>>> έχουν αφαιρεθεί εντελώς.
Αφού έχουμε επιλύσει όλα τα τμήματα σε κάθε αρχείο που εμπλέκεται σε σύγκρουση, τρέχουμε git add σε καθένα από αυτά τα αρχεία, ώστε να επισημανθεί ως επιλυμένο.
Αν το αρχείο περάσει στο στάδιο καταχώρησης, αυτό σημαίνει ότι έχει επιλυθεί.
Αν θέλουμε να χρησιμοποιήσουμε κάποιο γραφικό εργαλείο για να επιλύσουμε αυτές τις συγκρούσεις, τρέχουμε git mergetool για να εκκινήσουμε ένα κατάλληλο γραφικό εργαλείο συγχώνευσης που μας καθοδηγεί κατά την επίλυση των συγκρούσεων:
$ git mergetool
This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge
Merging:
index.html
Normal merge conflict for 'index.html':
{local}: modified file
{remote}: modified file
Hit return to start merge resolution tool (opendiff):
Αν θέλουμε να χρησιμοποιήσουμε κάποιο εργαλείο συγχώνευσης διαφορετικό από το προεπιλεγμένο (το Git επέλεξε το opendiff σε αυτή την περίπτωση, διότι εκτελέσαμε την εντολή σε Mac), μπορούμε να δούμε όλα τα εργαλεία που υποστηρίζονται στο πάνω μέρος μετά από το “one of the following tools.”
Απλά γράφουμε το όνομα του εργαλείου που προτιμάμε.
|
Note
|
Αν χρειάζεστε πιο προχωρημένα εργαλεία για να επιλύσετε περίπλοκες συγκρούσεις συγχωνεύσεων, θα μιλήσουμε σχετικά στην ενότητα Προχωρημένη Συγχώνευση. |
Αφού βγούμε από το εργαλείο συγχώνευσης, το Git μας ρωτάει αν η συγχώνευση ήταν επιτυχής.
Αν του πούμε ότι ήταν, ωθεί το αρχείο στον προθάλαμο ώστε να επισημανθεί ως επιλυμένο.
Μπορούμε να τρέξουμε την εντολή git status ξανά για να επιβεβαιωθούμε ότι όλες οι συγκρούσεις έχουν επιλυθεί:
$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: index.html
Αν είμαστε ευχαριστημένοι με το αποτέλεσμα και επιβεβαιωθούμε ότι όλα τα αρχεία που εμπλέκονται σε συγκρούσεις έχουν τοποθετηθεί στο στάδιο καταχώρησης, μπορούμε να πληκτρολογήσουμε git commit για να οριστικοποιήσουμε την υποβολή συγχώνευσης.
Το μήνυμα υποβολής είναι εξ ορισμού κάπως έτσι:
Merge branch 'iss53'
Conflicts:
index.html
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
# modified: index.html
#
Εφόσον θεωρούμε ότι θα είναι χρήσιμο σε όσους δουν αυτή τη συγχώνευση στο μέλλον, μπορούμε να τροποποιήσουμε αυτό το μήνυμα με λεπτομέρειες σχετικά με το πώς επιλύσαμε τη συγχώνευση και να εξηγήσουμε γιατί κάναμε ό,τι κάναμε, εφόσον δεν είναι προφανές.