Git
Chapters ▾ 2nd Edition

5.2 Κατανεμημένο Git - Συνεισφέροντας σε ένα έργο

Συνεισφέροντας σε ένα έργο

Η κύρια δυσκολία με την περιγραφή του τρόπου με τον οποίο μπορεί να συνεισφέρει κανείς σε ένα έργο είναι ότι υπάρχει ένας τεράστιος αριθμός παραλλαγών στον τρόπο με τον οποίο γίνεται. Επειδή το Git είναι πολύ ευέλικτο, οι χρήστες του έχουν τη δυνατότητα και πράγματι συνεργάζονται με πολλούς τρόπους και είναι προβληματικό να περιγράψουμε πώς πρέπει να συνεισφέρουμε –-κάθε έργο είναι λίγο διαφορετικό από τα άλλα. Ορισμένοι από τους παράγοντες που χρειάζεται να λάβουμε υπόψη είναι ο ενεργός αριθμός συνεισφερόντων, η επιλεγμένη ροή εργασίας, η πρόσβασή μας στις υποβολές και ενδεχομένως η μέθοδος εξωτερικής συνεισφοράς.

Ο πρώτος παράγοντας είναι ο ενεργός αριθμός συνεισφερόντων –-πόσοι χρήστες συμβάλλουν ενεργά στον κώδικα αυτού του έργου και πόσο συχνά; Σε πολλές περιπτώσεις, θα έχουμε δύο ή τρεις προγραμματιστές με λίγες υποβολές την ημέρα ή ενδεχομένως λιγότερες για κάπως αδρανή έργα. Για μεγαλύτερες εταιρείες ή έργα, ο αριθμός των προγραμματιστών θα μπορούσε να είναι χιλιάδες, με εκατοντάδες ή χιλιάδες υποβολές να καταφτάνουν κάθε μέρα. Αυτός ο παράγοντας είναι σημαντικό επειδή με όσο περισσότεροι προγραμματιστές εμπλέκονται, τόσο περισσότερα ζητήματα αντιμετωπίζουμε όσον αφορά την καθαρή εφαρμογή και ευκολία συγχώνευσης του κώδικά μας. Οι αλλαγές που υποβάλουμε ενδέχεται να καταστούν παρωχημένες ή να αλλοιωθούν σε σημαντικό βαθμό από εργασίες που συγχωνεύονται ενώ εργάζόμαστε ή ενώ οι αλλαγές μας αναμένουν έγκριση ή εφαρμογή. Πώς, λοιπόν, μπορούμε να διατηρήσουμε τον κώδικά μας συνεχώς ενημερωμένο και τις υποβολές μας έγκυρες;

Ο επόμενος παράγοντας είναι η ροή εργασίας που χρησιμοποιείται στο έργο. Είναι συγκεντρωτικό με κάθε προγραμματιστή να έχει ισότιμη πρόσβαση για εγγραφή στην κύρια γραμμή παραγωγής κώδικα; Έχει το πρόγραμμα κάποιον διαχειριστή ή ενοποιητή ο οποίος ελέγχει όλα τα επιθέματα; Περνούν τα επιθέματα κάποια διαδικασία ελέγχου από συνεργάτες και έγκρισης; Συμμετέχουμε εμείς σε αυτήν τη διαδικασία; Υπάρχει σύστημα υπολοχαγού και πρέπει πρώτα να υποβάλλουμε την εργασία μας σε αυτόν πρώτα;

Το επόμενο θέμα είναι η πρόσβασή υποβολών μας. Η ροή εργασίας που απαιτείται για να συνεισφέρουμε σε ένα έργο είναι πολύ διαφορετική εάν έχουμε πρόσβαση για εγγραφή στο έργο απ' ό,τι αν δεν έχουμε. Εάν δεν έχουμε πρόσβαση για εγγραφή, πώς προτιμά το έργο να δέχεται συνεισφερόμενη εργασία; Υπάρχει κάποια σχετική πολιτική; Πόση δουλειά συμβάλλουμε κάθε φορά; Πόσο συχνά συμβάλλουμε;

Όλα αυτά τα ερωτήματα επηρεάζουν τον τρόπο με τον οποίο συνεισφέρουμε αποτελεσματικά σε ένα έργο και ποιες ροές εργασίας προτιμώνται ή είναι διαθέσιμες σε εμάς. Θα καλύψουμε πτυχές καθεμιάς από αυτές σε μια σειρά περιπτώσεων χρήσης, οι οποίες κινούνται από απλές σε πιο περίπλοκες. θα πρέπει να είμαστε σε θέση να κατασκευάζουμε τις συγκεκριμένες ροές εργασίας που χρειάζόμαστε στην πράξη από αυτά τα παραδείγματα.

Κατευθυντήριες γραμμές για υποβολές

Πριν ξεκινήσουμε να εξετάζουμε τις συγκεκριμένες περιπτώσεις χρήσης, ας δούμε σύντομη υπενθύμιση σχετικά με τα μηνύματα υποβολής. Το να έχουμε μια καποιες καλές κατευθυντήριες γραμμές σχετικά με τη δημιουργία υποβολών και η τήρησή τους κάνουν την εργασία με το Git και τη συνεργασία με άλλους πολύ πιο εύκολη. Το έργο Git παρέχει ένα έγγραφο που παραθέτοι πολλές καλές συμβουλές για τη δημιουργία υποβολών από τις οποίες μπορούμε να υποβάλουμε επιδορθώσεις κώδικα —μπορούμε να το διαβάσουμε στον πηγαίο κώδικα του Git στο αρχείο Documentation/SubmittingPatches.

Καταρχάς δεν θέλουμε να υποβάλουμε σφάλματα σχετικά με τα λευκά διαστημάτων (whitespace). Το Git παρέχει έναν εύκολο τρόπο για να ελέγξουμε τέτοιου είδους σφάλματα – προτού υποβάλλουμε, τρέχουμε εκτελούμε το git diff --check, το οποίο προσδιορίζει πιθανά σφάλματα κενών διαστημάτων και μας τα παραθέτει.

Έξοδος μίας `git diff --check`.
Figure 57. Έξοδος μίας git diff --check.

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

Δεύτερον, προσπαθούμε ώστε κάθε υποβολή να έχει ένα λογικά διακριτό σύνολο αλλαγών. Αν είναι δυνατό, προσπαθούμε να κάνουμε τις αλλαγές μας εύπεπτες – ας μην γράφουμε κώδικα για ένα ολόκληρο Σαββατοκύριακο σε πέντε διαφορετικά θέματα και στη συνέχεια τα υποβάλλουμε όλα ως μια τεράστια υποβολή τη Δευτέρα. Ακόμη και αν δεν υποβάλλουμε κατά τη διάρκεια του Σαββατοκύριακου, ας χρησιμοποιήσουμε το στάδιο καταχώρισης τη Δευτέρα για να χωρίσουμε την εργασία μας σε τουλάχιστον μία υποβολή ανά ζήτημα, με ένα χρήσιμο μήνυμα ανά υποβολή. Εάν ορισμένες από τις αλλαγές τροποποιούν το ίδιο αρχείο, προσπαθούμε να χρησιμοποιήσουμε το git add --patch ώστε να τοποθετούμε μερικώς αρχεία (αυτό καλύπτεται σε βάθος στην ενότητα Διαδραστική εργασία με το στάδιο καταχώρισης). Το στιγμιότυπο του έργου στην άκρη του κλάδου είναι το ίδιο είτε πραγματοποιούμε μία υποβολή είτε πέντε, εφόσον όλες οι αλλαγές προστίθενται σε κάποιο σημείο, οπότε ας προσπαθούμε να διευκολύνουμε τους συμπρογραμματιστές μας όταν πρέπει να ελέγξουν τις αλλαγές μας. Αυτή η προσέγγιση διευκολύνει επίσης το απόσυρση ή επαναφορά κάποιου συνόλου αλλαγών, εφόσον χρειαστεί να γίνει κάτι τέτοιο αργότερα. Η ενότητα Η ιστορία ξαναγράφεται περιγράφει μια σειρά από χρήσιμα κόλπα που παρέχει το Git για την επανεγγραφή του ιστορικού και την αλληλεπιδραστική τοποθέτηση αρχείων στο στάδιο καταχώρισης –ας χρησιμοποιούμε αυτά τα εργαλεία για να δημιουργήσουμε ένα καθαρό και κατανοητό ιστορικό πριν στείλουμε το έργο σε κάποιον άλλο.

Το τελευταίο πράγμα που πρέπει να έχουμε υπόψη είναι το μήνυμα υποβολής. Η απόκτηση της συνήθειας να δημιουργούμε μηνύματα υψηλής ποιότητας κάνει τη χρήση του Git και τη συνεργασία πολύ πιο εύκολη. Κατά γενικό κανόνα, τα μηνύματά μας πρέπει να ξεκινούν με μία μόνο γραμμή που δεν υπερβαίνει τους 50 χαρακτήρες και περιγράφει συνοπτικά το σύνολο αλλαγών, ακολουθούμενο από μια κενή γραμμή, ακολουθούμενη από μια πιο λεπτομερή εξήγηση. Το έργο Git απαιτεί η λεπτομερέστερη εξήγηση να περιλαμβάνει το κίνητρό μας για την αλλαγή και να αντιπαραβάλλουμε την εφαρμογή της με την προηγούμενη συμπεριφορά – αυτή είναι μια καλή κατευθυντήρια γραμμή που πρέπει να ακολουθούμε. Είναι επίσης καλή ιδέα να χρησιμοποιούμε την προστακτική έγκλιση σε αυτά τα μηνύματα. Με άλλα λόγια, χρησιμοποιούμε εντολές. Αντί για “Πρόσθεσα δοκιμές για” ή “Προσθήκη εξετάσεων για”, χρησιμοποιούμε “Πρόσθεσε δοκιμασίες για”. Ακολουθεί ένα πρότυπο που γράφτηκε αρχικά από τον Tim Pope:

Σύντομη (το πολύ 50 χαρακτήρες) περίληψη των αλλαγών

Λεπτομερέστερη περιγραφή, εφόσον είναι απαραίτητη. Αναδιπλώνουμε σε
περίπου 72 χαρακτήρες. Σε κάποιες περιστάσεις η πρώτη γραμμή
αντιμετωπίζεται ως το θέμα ενός e-mail και οι υπόλοιπες ως το σώμα του.
Η κενή γραμμή που χωρίζει την περίληψη από τη λεπτομερή περιγραφή
είναι κρίσιμη (εκτός κι αν η λεπτομερής περιγραφή παραλείπεται
τελείως)· εργαλεία όπως η αλλαγή βάσης (rebase) μπορεί να
μπερδευτούν όταν τρέχουμε ταυτόχρονα.

Περαιτέρω παράγραφοι έρχονται μετά από κενές γραμμές.

  - Λίστες με κουκκίδες είναι αποδεκτές.
  - Συνήθως χρησιμοποιείται παύλα ή αστερίσκος αντί για κουκκίδα,
    που ακολουθεί ένα κενό με κενές γραμμές ανάμεσα στα σημεία
    αλλά οι συμβάσεις ποικίλλουν σε αυτό το σημείο.

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

Στα παραδείγματα που ακολουθούν όπως και στο μεγαλύτερο μέρος αυτού του βιβλίου, χάριν συντομίας, δεν υπάρχουν όμορφα διαμορφωμένα μηνύματα όπως αυτό. Αντίθετα, χρησιμοποιούμε την επιλογή -m στις εντολές git commit. Κάντε ό,τι λέμε, όχι ό,τι κάνουμε.

Ιδιωτικές μικρές ομάδες

Η απλούστερη ρύθμιση που ενδεχομένως θα συναντήσουμε είναι ένα ιδιωτικό έργο με έναν ή δύο άλλους προγραμματιστές. “Ιδιωτικό” εδώ σημαίνει κλειστού-κώδικα –που δεν είναι προσβάσιμος από τον έξω κόσμο. Εμείς και όλοι οι άλλοι προγραμματιστές έχουμε πρόσβαση ώθησης στο αποθετήριο.

Σε αυτό το περιβάλλον, μπορούμε να ακολουθήσουμε μια ροή εργασίας παρόμοια με αυτήν που θα ακολουθούσαμε αν χρησιμοποιούσαμε το Subversion ή κάποιο άλλο συγκεντρωτικό σύστημα. Συνεχίσουμε να έχουμε πλεονεκτήματα όπως η υποβολή εκτός σύνδεσης και η απλούστερη διακλάδωση και συγχώνευση, αλλά η ροή εργασίας μπορεί να είναι πολύ παρόμοια· η κύρια διαφορά είναι ότι οι συγχωνεύσεις συμβαίνουν στην πλευρά του πελάτη αντί στον διακομιστή κατά τη διάρκεια της υποβολής. Ας δούμε τι μπορεί να συμβαίνει όταν δύο προγραμματιστές αρχίζουν να συνεργάζονται σε ένα κοινό αποθετήριο. Ο πρώτος προγραμματιστής, ο John, κλωνοποιεί το αποθετήριο, κάνει μια αλλαγή και την υποβάλλει τοπικά. (Τα μηνύματα πρωτοκόλλου έχουν αντικατασταθεί με ... σε αυτά τα παραδείγματα για να τα συντομεύσουμε κάπως.)

# Μηχάνημα του John
$ git clone john@githost:simplegit.git
Initialized empty Git repository in /home/john/simplegit/.git/
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'removed invalid default value'
[master 738ee87] removed invalid default value
 1 files changed, 1 insertions(+), 1 deletions(-)

Η δεύτερη προγραμματίστρια, η Jessica, κάνει το ίδιο πράγμα —κλωνοποιεί το αποθετήριο και κάνει μια αλλαγή:

# Μηχάνημα της Jessica
$ git clone jessica@githost:simplegit.git
Initialized empty Git repository in /home/jessica/simplegit/.git/
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
 1 files changed, 1 insertions(+), 0 deletions(-)

Τώρα, η Jessica ωθεί την εργασία της στον διακομιστή:

# Μηχάνημα της Jessica
$ git push origin master
...
To jessica@githost:simplegit.git
   1edee6b..fbff5bc  master -> master

Ο John προσπαθεί επίσης να ωθήσει την αλλαγή:

# Μηχάνημα τοηυ John
$ git push origin master
To john@githost:simplegit.git
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'

Στον John δεν επιτρέπεται να ωθήσει επειδή η Τζέσικα έχει ωθήσει στο μεταξύ. Αυτό πρέπει να το καταλάβουμε καλά, εφόσον είμαστε συνηθισμένοι στο Subversion, επειδή όπως παρατηρούμε οι δύο προγραμματιστές δεν επεξεργάστηκαν το ίδιο αρχείο. Παρόλο που το Subversion πραγματοποιεί αυτόματα μια τέτοια συγχώνευση στον διακομιστή, αν τα αρχεία που έχουν υποστεί επεξεργασία είναι διαφορετικά, στο Git πρέπει να συγχωνεύσουμε τις υποβολές σε τοπικό επίπεδο. Ο John πρέπει να ανακτήσει τις αλλαγές της Jessica και να τις συγχωνεύσει προτού του επιτραπεί να ωθήσει:

$ git fetch origin
...
From john@githost:simplegit
 + 049d078...fbff5bc master     -> origin/master

Σε αυτό το σημείο, το τοπικό αποθετήριο του John μοιάζει με αυτό:

Το αποκλίνον ιστορικό του John
Figure 58. Το αποκλίνον ιστορικό του John.

Ο John έχει μια αναφορά στις αλλαγές που ώθησε η Jessica, αλλά πρέπει να τις συγχωνεύσει στη δουλειά του, προτού του επιτραπεί να ωθήσει:

$ git merge origin/master
Merge made by recursive.
 TODO |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

Η συγχώνευση γίνεται ομαλά —το ιστορικό της υποβολής του John τώρα μοιάζει με αυτό:

Το αποθετήριο του John μετά τη συγχώνευση του `origin/master`.
Figure 59. Το αποθετήριο του John μετά τη συγχώνευση του origin/master.

Τώρα, ο John μπορεί να δοκιμάσει τον κώδικά του για να βεβαιωθεί ότι εξακολουθεί να λειτουργεί σωστά και τότε μπορεί να ωθήσει τη νέα συγχωνευμένη εργασία του στον διακομιστή:

$ git push origin master
...
To john@githost:simplegit.git
   fbff5bc..72bbc59  master -> master

Τέλος, το ιστορικό υποβολών του John μοιάζει με αυτό:

Ιστορικό του John μετά την ώθηση στον διακομιστή `origin`.
Figure 60. Ιστορικό του John μετά την ώθηση στον διακομιστή origin.

Στο μεταξύ, η Jessica εργαζόταν πάνω σε έναν θεματικό κλάδο. Δημιούργησε έναν θεματικό κλάδο με το όνομα issue54 και έκανε τρεις υποβολές σε αυτόν. Δεν έχει ακόμη ανακτήσει τις αλλαγές του John, επομένως το ιστορικό υποβολών της μοιάζει ως εξής:

Θεματικός κλάδος της Jessica.
Figure 61. Θεματικός κλάδος της Jessica.

Η Jessica θέλει να συγχρονιστεί με τον John και γι' αυτό ανακτά:

# Μηχάνημα της Jessica
$ git fetch origin
...
From jessica@githost:simplegit
   fbff5bc..72bbc59  master     -> origin/master

Αυτό ανακτά τη δουλειά που έχει ωθήσει ο John στο μεταξύ. To ιστορικό της Jessica μοιάζει τώρα με:

Ιστορικό της Jessica μετά την ανάκτηση των αλλαγών του John.
Figure 62. Ιστορικό της Jessica μετά την ανάκτηση των αλλαγών του John.

Η Jessica θεωρεί ότι το θέμα της είναι έτοιμο, αλλά θέλει να ξέρει τι πρέπει να συγχωνεύσει στο έργο της ώστε να μπορέσει να ωθήσει. Εκτελεί το git log για να πληροφορηθεί σχετικά:

$ git log --no-merges issue54..origin/master
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date:   Fri May 29 16:01:27 2009 -0700

   removed invalid default value

Η σύνταξη issue54..origin/master είναι ένα φίλτρο αρχείου καταγραφής (log filter) που ζητά από το Git να εμφανίσει μόνο τον κατάλογο των υποβολών που βρίσκονται στον τελευταίο κλάδο (στη συγκεκριμένη περίπτωση αυτή origin/master) που δεν βρίσκονται στον πρώτο κλάδο (στη συγκεκριμένη περίπτωση ``issue54``). Θα αναφερθούμε λεπτομερώς σε αυτήν τη σύνταξη στην ενότητα Εύρος υποβολών.

Προς το παρόν, μπορούμε να δούμε από την έξοδο ότι υπάρχει μόνο μία υποβολή που έχει κάνει ο John την οποία δεν έχει συγχωνεύσει η Jessica. Αν συγχωνεύσει τον κλάδο origin/master, αυτή είναι η μόνη υποβολή που θα τροποποιήσει την τοπική εργασία της.

Τώρα, η Jessica μπορεί να συγχωνεύσει τον θεματικό της κλάδο στον κύριο κλάδο της, να συγχωνεύσει τη δουλειά του John (origin/master) στον δικό της κλάδο master και στη συνέχεια να ωθήσει ξανά στον διακομιστή. Πρώτα, μεταβαίνει στον κύριο κλάδο της για να ενοποιήσει όλη αυτήν τη δουλειά:

$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.

Μπορεί να συγχωνεύσει πρώτα είτε τον κλάδο origin/master είτε τον issue54 —και οι δύο είναι upstream, οπότε η σειρά δεν έχει σημασία. Το τελικό στιγμιότυπο θα είναι πανομοιότυπο ανεξάρτητα από τη σειρά που επιλέγει· μόνο το ιστορικό θα είναι ελαφρώς διαφορετικό. Επιλέγει να συγχωνευτεί πρώτα στον issue54:

$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
 README           |    1 +
 lib/simplegit.rb |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

Δεν παρουσιάζονται προβλήματα· όπως μπορούμε να δούμε ήταν μια απλή ταχυπροώθηση. Τώρα η Jessica συγχωνεύεται στη δουλειά του John (origin/master):

$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by recursive.
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Τα πάντα συγχωνεύονται καθαρά και το ιστορικό της Jessica μοιάζει με αυτό:

Το ιστορικό της Jessica μετά τη συγχώνευση των αλλαγών του John.
Figure 63. Το ιστορικό της Jessica μετά τη συγχώνευση των αλλαγών του John.

Τώρα, ο κλάδος origin/master είναι προσβάσιμος από τον κλάδο master της Jessica, οπότε θα πρέπει να είναι σε θέση να ωθήσει με επιτυχία (αν υποτεθεί ότι ο John δεν ώθησε ξανά στο μεταξύ):

$ git push origin master
...
To jessica@githost:simplegit.git
   72bbc59..8059c15  master -> master

Κάθε προγραμματιστής έχει υποβάλλει μερικές φορές και έχει συγχωνευθεί επιτυχώς στο έργο του άλλου.

Το ιστορικό της Jessica μετά την ώθηση όλων των αλλαγών πίσω στον διακομιστή.
Figure 64. Το ιστορικό της Jessica μετά την ώθηση όλων των αλλαγών πίσω στον διακομιστή.

Αυτή είναι μία από τις πιο απλές ροές εργασίας. Εργάζόμαστε για κάποιο χρονικό διάστημα, συνήθως σε έναν θεματικό κλάδο, και συγχωνεύουμε τον κύριο κλάδο μας όταν είναι έτοιμος να ενσωματωθεί. Όταν θέλουμε να μοιραστούμε αυτήν τη δουλειά, μπορούμε να τη συγχωνεύσουμε στον δικό μας κύριο κλάδο, στη συνέχεια να ανακτήσουμε και να συγχωνεύσουμε τον κλάδο origin/master αν έχει αλλάξει και, τέλος, να ωθήσουμε στον κλάδο master του διακομιστή. Η συνήθης ακολουθία γεγονότων είναι κάτι σαν:

Γενική ακολουθία γεγονότων για μια απλή ροή εργασίας πολλών προγραμματιστών.
Figure 65. Γενική ακολουθία γεγονότων για μια απλή ροή εργασίας πολλών προγραμματιστών.

Ιδιωτική ομάδα με διαχειριστή

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

Ας πούμε ότι ο John και η Jessica δουλεύουν μαζί σε ένα θέμα ενώ η Jessica και ο Josie εργάζονται σε ένα δεύτερο. Σε αυτήν την περίπτωση, η εταιρεία χρησιμοποιεί ένα είδος ροής εργασίας με διαχειριστή ενοποίησης, στην οποία η εργασία των μεμονωμένων ομάδων ενσωματώνεται μόνο από ορισμένους μηχανικούς και ο κλάδος master του κύριου αποθετηρίου μπορεί να ενημερωθεί μόνο από αυτούς τους μηχανικούς. Σε αυτό το σενάριο όλη η δουλειά γίνεται σε κλάδους κοινούς σε ομάδες και συγκεντρώνονται αργότερα από τους ενοποιητές.

Ας ακολουθήσουμε τη ροή εργασίας της Jessica καθώς εργάζεται στα δύο θέματά της, συνεργαζόμενη παράλληλα με δύο διαφορετικούς προγραμματιστές σε αυτό το περιβάλλον. Υποθέτοντας ότι έχει ήδη κλωνοποιήσει το αποθετήριό της, αποφασίζει να εργαστεί πρώτα στο θέμα featureA. Δημιουργεί έναν νέο κλάδο για το θέμα και κάνει κάποια δουλειά σε αυτό:

# Μηχάνημα της Jessica
$ git checkout -b featureA
Switched to a new branch 'featureA'
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[featureA 3300904] add limit to log function
 1 files changed, 1 insertions(+), 1 deletions(-)

Σε αυτό το σημείο, πρέπει να μοιραστεί τη δουλειά της με τον John, οπότε ωθεί τις υποβολές του κλάδο της featureA στον διακομιστή. Η Jessica δεν έχει πρόσβαση ώθησης στον κλάδο master —μόνον οι ενοποιητές έχουν— γι' αυτό πρέπει να ωθήσει σε έναν άλλο κλάδο για να συνεργαστεί με τον John:

$ git push -u origin featureA
...
To jessica@githost:simplegit.git
 * [new branch]      featureA -> featureA

Η Jessica ειδοποιεί τον John για να του πει ότι έχει ωθήσει κάποια δουλειά της σε έναν κλάδο που ονομάζεται featureA και μπορεί να τον δει τώρα. Ενώ περιμένει κάποια ανταπόκριση από τον John, η Jessica αποφασίζει να αρχίσει να δουλεύει στο featureB με τον Josie. Για να ξεκινήσει, ξεκινά έναν νέο κλάδο, με βάση τον κλάδο master του διακομιστή:

# Μηχάνημα της Jessica
$ git fetch origin
$ git checkout -b featureB origin/master
Switched to a new branch 'featureB'

Τώρα, η Jessica κάνει μερικές υποβολές στον κλάδο featureB:

$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
 1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
 1 files changed, 5 insertions(+), 0 deletions(-)

Το αποθετήριο της Jessica μοιάζει με αυτό:

Αρχικό ιστορικό υποβολών της Jessica.
Figure 66. Αρχικό ιστορικό υποβολών της Jessica.

Είναι έτοιμη να ωθήσει τη δουλειά της, αλλά λαμβάνει ένα e-mail από τον Josie ότι ένας κλάδος με κάποια αρχική εργασία σε αυτό το θέμα είχε ήδη ωθηθεί στον διακομιστή ως featureBee. Η Jessica πρέπει πρώτα να συγχωνεύσει αυτές τις αλλαγές με τις δικές της, προτού να μπορέσει να ωθήσει στον διακομιστή. Στη συνέχεια μπορεί να ανακτήσει τις αλλαγές του Josie με git fetch:

$ git fetch origin
...
From jessica@githost:simplegit
 * [new branch]      featureBee -> origin/featureBee

Η Jessica μπορεί τώρα να συγχωνεύσει αυτήν τη δουλειά με git merge:

$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by recursive.
 lib/simplegit.rb |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

Υπάρχει κάποιο πρόβλημα —πρέπει να ωθήσει τη συγχωνευμένη δουλειά του κλάδου της featureB στον κλάδο featureBee του διακομιστή. Μπορεί να το κάνει καθορίζοντας τον τοπικό κλάδο ακολουθούμενο από μία τελεία (:) ακολουθούμενο από τον απομακρυσμένο κλάδο στην εντολή git push:

$ git push -u origin featureB:featureBee
...
To jessica@githost:simplegit.git
   fba9af8..cd685d1  featureB -> featureBee

Αυτό ονομάζεται refspec. Πιο λεπτομερής συζήτηση των refspecs του Git και διάφορα πράγματα που μπορούμε να κάνουμε με αυτά υπάρχουν στην ενότητα Τα refspec. Παρατηρούμε επίσης τη σήμανση -u· είναι συντομογραφία του --set-upstream, που ρυθμίζει τους κλάδους για ευκολότερη ώθηση και έλξη αργότερα.

Στη συνέχεια, ο John αποστέλλει e-mail στην Jessica για να της πει ότι έχει ωθήσει κάποιες αλλαγές στον κλάδο featureA και της ζητά να τις επαληθεύσει. Εκείνη εκτελεί ένα git fetch για να ανακτήσει αυτές τις αλλαγές:

$ git fetch origin
...
From jessica@githost:simplegit
   3300904..aad881d  featureA   -> origin/featureA

Στη συνέχεια, μπορεί να δει τι έχει αλλάξει με git log:

$ git log featureA..origin/featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date:   Fri May 29 19:57:33 2009 -0700

    changed log output to 30 from 25

Τέλος, συγχωνεύει τη δουλειά του John στον δικό της κλάδο featureA:

$ git checkout featureA
Switched to branch 'featureA'
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
 lib/simplegit.rb |   10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)

Η Jessica θέλει να κάνει κάποιες μικροαλλαγές, έτσι υποβάλλει ξανά και στη συνέχεια ωθεί την υποβολή στον διακομιστή:

$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
 1 files changed, 1 insertions(+), 1 deletions(-)
$ git push
...
To jessica@githost:simplegit.git
   3300904..774b3ed  featureA -> featureA

Το ιστορικό της υποβολών της Jessica τώρα μοιάζει κάτι τέτοιο:

Ιστορικό της Jessica μετά την υποβολή σε έναν θεματικό κλάδο.
Figure 67. Ιστορικό της Jessica μετά την υποβολή σε έναν θεματικό κλάδο.

Οι Jessica, Josie και John ενημερώνουν τους ενοποιητές ότι οι κλάδοι featureA και featureBee στον διακομιστή είναι έτοιμοι για ενσωμάτωση στον κύριο κλάδο. Αφού οι ενοποιητές συγχωνεύσουν αυτούς τους κλάδους στον κύριο κλάδο, μία ανάκτηση θα κατεβάσει τη νέα υποβολή συγχώνευσης, κάνοντας το ιστορικό να μοιάζει με αυτό:

Ιστορικό της Jessica μετά τη συγχώνευση και των δύο θεματικών κλάδων της.
Figure 68. Ιστορικό της Jessica μετά τη συγχώνευση και των δύο θεματικών κλάδων της.

Πολλές ομάδες καταφεύγουν στο Git εξαιτίας αυτής της δυνατότητας να έχουν πολλές ομάδες που εργάζονται παράλληλα, και να συγχωνεύουν τις διαφορετικές γραμμές εργασίας αργότερα. Η ικανότητα μικρότερων υποομάδων μιας ομάδας να συνεργάζονται μέσω απομακρυσμένων κλάδων χωρίς να χρειάζεται απαραίτητα να εμπλέξουν ή να παρεμποδίσουν ολόκληρη την ομάδα είναι ένα τεράστιο όφελος που παρέχει το Git. Η ακολουθία για τη ροή εργασίας που είδαμε εδώ είναι κάτι σαν αυτό:

Βασική ακολουθία αυτής της ροής εργασίας διαχειριζόμενη ομάδα.
Figure 69. Βασική ακολουθία αυτής της ροής εργασίας διαχειριζόμενη ομάδα.

Αποσχισμένα δημόσια έργα

Η συνεργασία στα δημόσια έργα είναι κάπως διαφορετική. Επειδή δεν έχουμε δικαιώματα για άμεση ενημέρωση κλάδων στο έργο, θα πρέπει να στείλουμε τη δουλειά μας στους διαχειριστές με κάποιον άλλο τρόπο. Το πρώτο παράδειγμα περιγράφει τη συνεισφορά μέσω απόσχισης (forking) σε διακομιστές Git που υποστηρίζουν την εύκολη απόσχιση. Πολλοί ιστότοποι φιλοξενίας ιστοσελίδων την υποστηρίζουν (συμπεριλαμβανομένων των GitHub, BitBucket, Google Code, repo.or.cz και άλλους) και πολλοί διαχειριστές έργων αναμένουν αυτό το στυλ συνεισφοράς. Η επόμενη ενότητα ασχολείται με έργα που προτιμούν να δέχονται συνεισφορές/επιθέματα μέσω ηλεκτρονικού ταχυδρομείου.

Πρώτα απ 'όλα, ίσως θέλουμε να κλωνοποιήσουμε το κύριο αποθετήριο, να δημιουργήσουμε έναν θεματικό κλάδο για το επίθεμα ή τα επιθέματα που σκοπεύουμε να συνεισφέρουμε και να δουλεύουμε εκεί. Η ακολουθία μοιάζει ως εξής:

$ git clone (url)
$ cd project
$ git checkout -b featureA
# (work)
$ git commit
# (work)
$ git commit
Note

Ίσως θελήσουμε να χρησιμοποιήσουμε την εντολή rebase -i για να συναρμόσουμε την εργασία μας σε μία μόνο υποβολή ή να αναδιατάξουμε την εργασία μας στις υποβολές για να κάνουμε διευκολύνουμε τον διαχειριστή να ελέγξει το επίθεμά μας —βλ. Η ιστορία ξαναγράφεται για περισσότερες πληροφορίες σχετικά με τη διαδραστική αλλαγή βάσης.

Όταν ολοκληρωθεί η εργασία στον κλάδο μας και είμαστε έτοιμοι να τον επιστρέψουμε στους διαχειριστές, μεταβαίνουμε στην αρχική σελίδα του έργου και κάνουμε κλικ στο κουμπί “Fork”, ώστε να δημιουργήσουμε τη δική μας εγγράψιμη διχάλα του έργου. Στη συνέχεια, πρέπει να προσθέσουμε αυτήν τη διεύθυνση URL του νέου αποθετηρίου ως δεύτερο απομακρυσμένο αποθετήριο, στη συγκεκριμένη περίπτωση με το όνομα myfork:

$ git remote add myfork (url)

Μετά πρέπει να του ωθήσουμε την εργασία μας. Είναι πιο εύκολο να ωθήσουμε τον θεματικό κλάδο στον οποίο εργαζόμαστε στο δικό μας αποθετήριο αντί να συγχωνευθούμε στον κύριο κλάδο μας και να ωθήσουμε τον συγχωνευμένο κλάδο. Ο λόγος είναι ότι εάν η εργασία δεν γίνει αποδεκτή ή γίνουν αποδεκτά μόνο κάποια κομμάτια της, δεν χρειάζεται να επαναφέρουμε τον κύριο κλάδο μας. Αν οι διαχειριστές συγχωνεύσουν, επανατοποθετήσουν ή επιλέξουν μόνον τμήματα της δουλειάς μας, τότε κάποια στιγμή θα την πάρουμε πίσω έλκοντας από το αποθετήριό τους:

$ git push -u myfork featureA

Όταν έχουμε ωθήσει τη δουλειά μας στη διχάλα μας, πρέπει να ειδοποιήσουμε τον διαχειριστή. Αυτό συχνά ονομάζεται αίτημα έλξης και μπορούμε είτε να το δημιουργήσουμε μέσω της ιστοσελίδας —το GitHub έχει τον δικό του μηχανισμό αιτημάτων έλξης, τον οποίο θα δούμε στην ενότητα GitHub— είτε να τρέξουμε την εντολή git request-pull και να στείλουμε την έξοδό της με e-mail στον διαχειριστή του έργου.

Η εντολή request-pull παίρνει τον βασικό κλάδο από τον οποίο θέλουμε να ελχθεί ο θεματικός μας κλάδος και το URL του αποθετηρίου Git από το οποίο θέλουμε να ελχθεί και εξάγει μια σύνοψη όλων των αλλαγών που ζητάμε να έλξηχτούν. Για παράδειγμα, αν η Jessica θέλει να στείλει ένα αίτημα έλξης στον John και έχει κάνει δύο υποβολές στον θεματικό κλάδο που μόλις ώθησε, μπορεί να τρέξει αυτό:

$ git request-pull origin/master myfork
The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
  John Smith (1):
        added a new function

are available in the git repository at:

  git://githost/simplegit.git featureA

Jessica Smith (2):
      add limit to log function
      change log output to 30 from 25

 lib/simplegit.rb |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

Η έξοδος μπορεί να αποσταλεί στον διαχειριστή —του λέει από όπου διακλαδώθηκε η δουλειά, συνοψίζει τις υποβολές και λέει από πού να την έλξει.

Σε ένα έργο, στο οποίο δεν είμαστε διαχειριστές, είναι γενικά ευκολότερο να έχουμε έναν κλάδο όπως ο master να παρακολουθεί πάντα τον origin/master και να σδουλεύουμε σε θεματικούς κλάδους τους οποίους μπορούμε εύκολα να διαγράψουμε αν απορριφθούν. Η διατήρηση ξεχωριστών θεματικών κλάδων για διαφορετικά θέματα διευκολύνει επίσης την αλλαγή βάσης της εργασίας μας, αν η άκρη του κύριου αποθετηρίου έχει μετακινηθεί εν τω μεταξύ και οι υποβολές μας δεν εφαρμόζονται πλέον με καθαρό τρόπο. Για παράδειγμα, εάν θέλουμε να δημιουργήσουμε ένα δεύτερο θέμα στο έργο, καλό είναι να μην συνεχίζουμε να εργαζόμαστε στον κλάδο του θέματος το οποίο μόλις ωθήσαμε, αλλά να ξεκινήσουμε από τον κλάδο master του αποθετηρίου:

$ git checkout -b featureB origin/master
# (work)
$ git commit
$ git push myfork featureB
# (email maintainer)
$ git fetch origin

Τώρα, κάθε θέμα μας περιέχεται μέσα σε ένα σιλό —παρόμοια με μια ουρά επιθεμάτων— το οποίο μπορούμε να ξαναγράψουμε, να επανατοποθετήσουμε και να τροποποιήσουμε χωρίς τα θέματα να παρεμβαίνουν ή να αλληλεπιδρούν μεταξύ τους, όπως π.χ.:

Αρχικό ιστορικό υποβολών με τη δουλειά στο `featureB`.
Figure 70. Αρχικό ιστορικό υποβολών με τη δουλειά στο featureB.

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

$ git checkout featureA
$ git rebase origin/master
$ git push -f myfork featureA

Αυτό επαναφέρει το ιστορικό μας τώρα να μοιάζει με το Ιστορικό υποβολών μετά τη δουλειά στο featureA..

Ιστορικό υποβολών μετά τη δουλειά στο `featureA`.
Figure 71. Ιστορικό υποβολών μετά τη δουλειά στο featureA.

Επειδή αλλάξαμε τη βάση του κλάδου, πρέπει να χρησιμοποιήσουμε την επιλογή -f στην εντολή push, ώστε να μπορέσουμε να αντικαταστήσουμε τον κλάδο featureA στον διακομιστή με μια υποβολή που δεν είναι απόγονος του. Μια εναλλακτική λύση θα ήταν να ωθήσουμε αυτήν τη νέα δουλειά σε ένα διαφορετικό κλάδο στον διακομίστή (ίσως με όνομα featureAv2).

Ας δούμε ένα ακόμα πιθανό σενάριο: ο διαχειριστής έχει εξετάσει την εργασία στον δεύτερό μας κλάδο και του αρέσει η ιδέα, αλλά θα ήθελε να αλλάξουμε μια-δυο λεπτομέρειες στην υλοποίησή της. Θα εκμεταλλευτούμε αυτήν την ευκαιρία για να μετακινήσουμε τη δουλειά μας ώστε να διακλαδίζεται από τον τρέχοντα κλάδο master του έργου. Ξεκινάμε έναν νέο κλάδο που διακλαδίζεται από τον τρέχοντα κλάδο origin/master, στριμώχνουμε το featureB εκεί, αλλάζουμε τυχόν συγκρούσεις, κάνουμε την αλλαγές στην υλοποίηση που μας ζητήθηκαν και στη συνέχεια ωθούμε όλα αυτά ως έναν νέο κλάδο:

$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
# (change implementation)
$ git commit
$ git push myfork featureBv2

Η επιλογή --squash παίρνει όλη τη δουλειά που υπάρχει στον συγχωνευμένο κλάδο και τον στριμώχνει σε ένα σύνολο αλλαγών ώστε παράγει μία κατάσταση του αποθετηρίου σαν να συνέβη πραγματικά συγχώνευση χωρίς όμως να πραγματοποιήσει υποβολή συγχώνευσης. Αυτό σημαίνει ότι η μελλοντική μας υποβολή θα έχει μόνο έναν γονέα και μας επιτρέπει να εισάγουμε όλες τις αλλαγές από κάποιον άλλο κλάδο και μετά να κάνουμε περισσότερες αλλαγές πριν καταγράψουμε τη νέα υποβολή. Επίσης, μία άλλη χρήσιμη επιλογή στην περίπτωση της προεπιλεγμένης διαδικασίας συγχώνευσης είναι --no-commit που αναβάλλει της υποβολής συγχώνευσης .

Τώρα μπορούμε να στείλουμε στον διαχειριστή ένα μήνυμα ότι έχουμε κάνει τις ζητούμενες αλλαγές και μπορεί να τις βρει στον κλάδο featureBv2.

Ιστορικό υποβολών μετά τη δουλειά στο `featureBv2`.
Figure 72. Ιστορικό υποβολών μετά τη δουλειά στο featureBv2.

Δημόσιο έργο μέσω e-mail

Πολλά έργα έχουν θεσπίσει διαδικασίες για την αποδοχή των επιθεμάτων —θα πρέπει να ελέγξουμε τους συγκεκριμένους κανόνες του έργου, επειδή διαφέρουν από έργο σε έργο. Δεδομένου ότι υπάρχουν πολλά παλαιότερα, μεγαλύτερα έργα που αποδέχονται επιθέματα μέσω μιας λίστας ηλεκτρονικής αλληλογραφίας προγραμματιστών, θα εξετάσουμε ένα τέτοιο παράδειγμα.

Η ροή εργασίας είναι παρόμοια με την προηγούμενη περίπτωση —δημιουργούμε θεματικούς κλάδους έναν για κάθε σειρά επιθεμάτων στην οποία εργαζόμαστε. Η διαφορά είναι στο πώς τους υποβάλλουμε στο έργο. Αντί να αποσχίσουμε μία διχάλα από το έργο και να την ωθήσουμε στη δική μας εγγράψιμη έκδοση, μπορούμε να δημιουργήσουμε εκδόσεις ηλεκτρονικού ταχυδρομείου για κάθε σειρά υποβολών και να τις στείλουμε με e-mail στη λίστα ηλεκτρονικής αλληλογραφίας προγραμματιστών:

$ git checkout -b topicA
# (work)
$ git commit
# (work)
$ git commit

Τώρα έχουμε δύο υποβολές που θέλουμε να στείλουμε στη λίστα αλληλογραφίας. Χρησιμοποιούμε την git format-patch για να δημιουργήσουμε τα μορφοποιημένα αρχεία mbox που μπορούμε να στείλουμε με e-mail στη λίστα —μετατρέπει κάθε υποβολή σε μήνυμα e-mail με την πρώτη γραμμή του μηνύματος υποβολής ως θέμα και το υπόλοιπο μήνυμα συν το επίθεμα, που εισάγει η υποβολή, ως σώμα του e-mail. Η ομορφιά σε αυτό είναι ότι η εφαρμογή ενός επιθέματος από ένα μήνυμα e-mail που έχει παραχθεί με format-patch διατηρεί όλες τις πληροφορίες υποβολής σωστά.

$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch

Η εντολή format-patch εκτυπώνει τα ονόματα των αρχείων-επιθεμάτων που δημιουργεί. Ο διακόπτης -M λέει στο Git να αναζητήσει μετονομασίες. Τα αρχεία καταλήγουν να μοιάζουν ως εξής:

$ cat 0001-add-limit-to-log-function.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

---
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
   end

   def log(treeish = 'master')
-    command("git log #{treeish}")
+    command("git log -n 20 #{treeish}")
   end

   def ls_tree(treeish = 'master')
--
2.1.0

Μπορούμε επίσης να επεξεργαστούμε αυτά τα αρχεία/επιθέματα για να προσθέσουμε περισσότερες πληροφορίες για τη λίστα ηλεκτρονικής αλληλογραφίας που δεν θέλουμε να εμφανίζονται στο μήνυμα υποβολής. Αν προσθέσουμε κείμενο μεταξύ της γραμμής --- και της αρχής του επιθέματος (τη γραμμή diff --git), τότε οι προγραμματιστές μπορούν να τη διαβάσουν· αλλά όταν εφαρμόζεται το επίθεμα, το κείμενο αυτό παραλείπεται.

Για να στείλουμε το παραπάνω ως e-mail σε μια λίστα ηλεκτρονικής αλληλογραφίας, μπορούμε είτε να επικολλήσουμε το αρχείο στο πρόγραμμα ηλεκτρονικού ταχυδρομείου είτε να το στείλουμε μέσω ενός προγράμματος γραμμής εντολών. Η επικόλληση του κειμένου προκαλεί συχνά ζητήματα μορφοποίησης, ειδικά με “ευφυέστερους” πελάτες που δεν διατηρούν κατάλληλα τους χαρακτήρες αλλαγής γραμμής και άλλους λευκούς χαρακτήρες. Ευτυχώς, το Git παρέχει ένα εργαλείο που μας βοηθά να στέλνουμε κατάλληλα μορφοποιημένα επιθέματα μέσω IMAP, κάτι που ενδεχομένως είναι ευκολότερο. Θα επιδείξουμε πώς στείλουμε ένα επίθεμα μέσω του Gmail, που τυγχάνει να είναι το πρόγραμμα e-mail που γνωρίζουμε καλύτερα· μπορούμε να διαβάσουμε λεπτομερείς οδηγίες για ένα πλήθος προγραμμάτων ηλεκτρονικής αλληλογραφίας στο τέλος του προαναφερθέντος αρχείου Documentation/SubmittingPatches στον πηγαίο κώδικα του Git.

Πρώτα, πρέπει να ρυθμίσουμε την ενότητα imap στο αρχείο ~/.gitconfig. Μπορούμε να ορίσουμε ξεχωριστά κάθε τιμή με μια σειρά εντολών git config ή μπορούμε να τις προσθέσουμε χειροκίνητα· όπως και νά 'χει στο τέλος το αρχείο config θα πρέπει να φαίνεται σαν αυτό:

[imap]
  folder = "[Gmail]/Drafts"
  host = imaps://imap.gmail.com
  user = user@gmail.com
  pass = p4ssw0rd
  port = 993
  sslverify = false

Αν ο διακομιστής IMAP δεν χρησιμοποιεί SSL, οι δύο τελευταίες γραμμές πιθανώς δεν είναι απαραίτητες και η τιμή host θα είναι imap:// αντί για 'imaps://. Όταν έχει ρυθμιστεί το αρχείο `~/.gitconfig, μπορούμε να χρησιμοποιήσουμε την git imap-send για να τοποθετήσουμε τη σειρά επιθεμάτων στον φάκελο “Πρόχειρα” (“Drafts”) του καθορισμένου διακομιστή IMAP:

$ cat *.patch |git imap-send
Resolving imap.gmail.com... ok
Connecting to [74.125.142.109]:993... ok
Logging in...
sending 2 messages
100% (2/2) done

Σε αυτό το σημείο, θα πρέπει να μπορούμε να μεταβούμε στον φάκελο “Πρόχειρα”, να αλλάξουμε το πεδίο “Προς” στη λίστα αλληλογραφίας στην οποία αποστέλλουμε την ενημερωμένη έκδοση κώδικα, ενδεχομένως να κοινοποιήσουμε με “CC:” στον υπεύθυνο συντήρησης ή όποιον είναι υπεύθυνος για αυτήν την ενότητα και να το αποστείλουμε.

Μπορούμε επίσης να στείλουμε τα επιθέματα μέσω ενός διακομιστή SMTP. Όπως και πριν, μπορούμε να ορίσουμε ξεχωριστά κάθε τιμή με μια σειρά εντολών git config ή μπορούμε να τις προσθέσουμε χειροκίνητα στην ενότητα sendemail στο αρχείο ~/.gitconfig:

[sendemail]
  smtpencryption = tls
  smtpserver = smtp.gmail.com
  smtpuser = user@gmail.com
  smtpserverport = 587

Μετά από αυτό, μπορούμε να χρησιμοποιήσουμε το git send-email για να αποστείλουμε τα επιθέματά μας:

$ git send-email *.patch
0001-added-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
Who should the emails appear to be from? [Jessica Smith <jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y

Στη συνέχεια, το Git εκτοξεύει κάμποσες πληροφορίες αρχείου καταγραφής που μοιάζουν με κάτι σαν το παρακάτω για κάθε επίθεμα που στέλνουμε:

(mbox) Adding cc: Jessica Smith <jessica@example.com> from
  \line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>
To: jessica@example.com
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>

Result: OK

Ανακεφαλαίωση

Αυτή η ενότητα κάλυψε διάφορες συνηθισμένες ροές εργασίας για την αντιμετώπιση πολλών πολύ διαφορετικών τύπων έργων Git που είναι πιθανό να συναντήσουμε και εισήγαγε μερικά νέα εργαλεία που θα μας βοηθήσουν να διαχειριστούμε αυτήν τη διαδικασία. Στη συνέχεια, θα δούμε πώς εργαζόμαστε στην άλλη όψη του νομίσματος: τη διατήρηση ενός έργου Git. Θα μάθουμε πώς να είμαστε καλοπροαίρετοι δικτάτορες ή διαχειριστές ενοποίησης.