-
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 Εντολές διοχέτευσης
3.2 Διακλαδώσεις στο Git - Βασικές έννοιες διακλαδώσεων και συγχωνεύσεων
Βασικές έννοιες διακλαδώσεων και συγχωνεύσεων
Ας δούμε ένα απλό παράδειγμα διακλάδωσης και συγχώνευσης με μία ροή εργασίας που είναι πιθανό να αντιμετωπίσουμε στην πραγματικότητα. Θα ακολουθήσουμε τα παρακάτω βήματα:
-
θα κάνουμε αλλαγές σε μία ιστοσελίδα.
-
θα δημιουργήσουμε έναν κλάδο για μία νέα ιστορία την οποία επεξεργαζόμαστε.
-
θα κάνουμε αλλαγές σε αυτόν τον κλάδο.
Σε αυτό το στάδιο θα δεχτούμε ένα τηλεφώνημα ότι υπάρχει ένα άλλο κρίσιμο πρόβλημα και πρέπει να αναπτύξουμε μία άμεση λύση. Θα κάνουμε τα παρακάτω:
-
Θα μεταβούμε στον κλάδο παραγωγής.
-
θα δημιουργήσουμε έναν κλάδο στον οποίο θα προσθέσουμε τον κώδικά μας που λύνει το πρόβλημα.
-
Αφού ο κώδικάς μας δοκιμαστεί, θα συγχωνεύσουμε τον κλάδο που περιέχει τον νέο αυτό κώδικα και θα τον ωθήσουμε στην παραγωγή.
-
Θα επιστρέψουμε στην αρχική ιστορία μας και θα συνεχίσουμε να την επεξεργαζόμαστε.
Διακλαδώσεις —τα βασικά
Αρχικά ας υποθέσουμε ότι δουλεύουμε σε ένα έργο και έχουμε κάνει ήδη μερικές υποβολές στον κλάδο 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 'added a new footer [issue 53]'

iss53
μετατοπίστηκε εξαιτίας των αλλαγών μαςΤώρα λαμβάνουμε το τηλεφώνημα ότι υπάρχει ένα άλλο επείγον πρόβλημα στην ιστοσελίδα και πρέπει να το αντιμετωπίσουμε άμεσα.
Χάρη στο Git, δεν είναι απαραίτητο να αναπτύξουμε την επίλυση του προβλήματος παράλληλα με τις αλλαγές που έχουμε κάνει στον κλάδο iss53
και δεν χρειάζεται να καταβάλλουμε μεγάλη προσπάθεια ώστε να αναιρέσουμε όλες τις αλλαγές που έχουμε κάνει και να δουλέψουμε στο επείγον πρόβλημα και να εφαρμόσουμε τη λύση μας σε ό,τι βρίσκεται εκείνη τη στιγμή στη γραμμή της παραγωγής. Το μόνο που έχουμε να κάνουμε είναι να μεταβούμε στον κλάδο master
.
Ωστόσο πρέπει να τονιστεί ότι αν πριν το κάνουμε αυτό υπάρχουν στον κατάλογο εργασίας μας ή στο στάδιο καταχώρισης αλλάγες που δεν έχουν υποβληθεί και έρχονται σε σύγκρουση με τον κλάδο στον οποίο θέλουμε να μεταβούμε, το Git δεν θα μας αφήσει να αλλάξουμε κλάδο.
Το καλύτερο είναι να έχουμε μία καθαρή κατασταση εργασίας όταν μεταβαίνουμε από έναν κλάδο σε άλλο.
Υπάρχουν τρόποι να παρακάμψουμε αυτήν τη συμπεριφορά (με τις εντολές git stash
και git commit -amend
που θα καλύψουμε στη συνέχεια, στην ενότητα stash
και clean
.
Προς το παρόν, ας υποθέσουμε ότι έχουμε υποβάλλει όλες τις αλλαγές μας, ώστε να μπορούμε να μεταβαίνουμε από και προς τον κλάδο master
χωρίς προβλήματα:
$ git checkout master
Switched to branch 'master'
Σε αυτό το σημείο, ο κατάλογος εργασίας του έργου μας βρίσκεται ακριβώς στην κατάσταση στην οποία βρισκόταν πριν ξεκινήσουμε να δουλεύουμε για το πρόβλημα #53 και μπορούμε να εστιάσουμε στην επίλυση του επείγοντος προβλήματος. Αυτό είναι ένα σημαντικό σημείο που αξίζει να θυμόμαστε: όταν μεταπηδούμε από έναν κλάδο σε άλλο, το Git επαναφέρει τον κατάλογο εργασίας στην κατάσταση που είχε την τελευταία φορά που είχατε κάνει υποβολή σε αυτόν τον κλάδο. Προσθέτει, διαγράφει και τροποποιεί αρχεία αυτόματα ώστε να βεβαιωθεί ότι το αντίγραφο εργασίας μας είναι ίδιο με την κατάσταση του κλάδου αμέσως μετά την τελευταία υποβολή σε αυτόν τον κλάδο.
Στη συνέχεια, πρέπει να δουλέψουμε στο επείγον πρόβλημα. Ας φτιάξουμε έναν κλάδο hotfix
στον οποίο θα δουλέψουμε μέχρι να το λύσουμε:
$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'fixed the broken email address'
[hotfix 1fb7853] fixed the broken email address
1 file changed, 2 insertions(+)

hotfix
που βασίζεται στον κλάδο 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
.
Επειδή η υποβολή στην οποία έδειχνε ο κλάδος τον οποίο συγχωνεύσαμε ήταν αμέσως μετά την υποβολή στην οποία βρισκόμαστε τώρα, το 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 'finished the new footer [issue 53]'
[iss53 ad82d7a] finished 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) και έχει την ιδιαιτερότητα ότι έχει περισσότερους από έναν γονείς.

Αξίζει να σημειωθεί ότι το ίδιο το Git αποφασίζει ποιος είναι ο κοινός πρόγονος που αποτελεί την καλύτερη δυνατή βάση για τη συγχώνευση· αυτή είναι μία διαφορά ανάμεσα στο Git και παλιότερα εργαλεία όπως το CVS ή το Subversion (πριν την έκδοση 1.5), στα οποία ο χρήστης που έκανε τη συγχώνευση έπρεπε ο ίδιος να βρει ποια πρότερη κατάσταση ήταν η καλύτερη δυνατή βάση. Αυτό κάνει τις συγχωνεύσεις στο Git πολύ ευκολότερες από ότι σε αυτά τα παλιότερα συστήματα.
Τώρα που η εργασία μας έχει συγχωνευτεί, δεν χρειάζόμαστε πλέον τον κλάδο 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
Προκειμένου να επιλύσουμε τη σύγκρουση, πρέπει είτε να επιλέξουμε τη μία ή την άλλη έκδοση είτε να συγχωνεύσουμε τα περιεχόμενα οι ίδιοι. Για παράδειγμα, μπορεί να θέλουμε να επιλύσουμε αυτήν τη σύγκρουση αντικαθιστώντας ολόκληρο το τμήμα με το παρακάτω:
<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
#
Μπορούμε να τροποποιήσουμε αυτό το μήνυμα με λεπτομέρειες σχετικά με το πώς επιλύσατε τη συγχώνευση, εφόσον θεωρούμε ότι θα είναι χρήσιμο σε όσους δουν αυτήν τη συγχώνευση στο μέλλον —γιατί κάνατε ό,τι κάνατε, εφόσον δεν είναι προφανές.