# Περιγραφή Σκοπός του οδηγού είναι να καθορίσει τις αρχές και την μεθοδολογία χρήσης του git στο gitlabs, προκειμένου να μπορεί μια ομάδα 3 ή και παραπάνω προγραμματιστών να συνεργαστούν μεταξύ τους, με σκοπό την ανάπτυξη μίας εφαρμογής # Βασικοί στόχοι 1. Να καθοριστούν κανόνες-αρχές σχετικά απλοί ώστε να διευκολύνουν την λειτουργία της ομάδας 2. Να διασφαλίζεται η αποφυγή λαθών στον συντονισμό του repository λόγω απειρίας των προγραμματιστών στο git Βάση των παραπάνω αρχών, προτείνεται το forking workflow, το οποίο διασφαλίζει το 2 σε βάρος του 1, άλλα θεωρούμε ότι έχει την κατάλληλη ισορροπία. Σχετικά με τα workflows διαβάστε στις παραπομπές. Ακολουθώντας το forking workflow, θα πρέπει να τηρήσουμε τις παρακάτω αρχές: 1. Κανείς δεν κάνει αλλαγές στο κεντρικό repo (canonical repository) 2. Οι αλλαγές στο κεντρικό repo γίνονται μόνο με merge requests από forked repositories 3. Η εργασία πάνω σε αλλαγές πρέπει γίνεται σε τοπικά cloned repositories 4. Κάθε νέα λειτουργία ή αλλαγή αναπτύσσεται σε ξεχωριστό branch 5. Φροντίζουμε να διατηρούμε το ιστορικό αλλαγών (commit history) σε μικρό μέγεθος για να μην επιβαρύνουμε το commit history στο canonical repository # Περίγραμμα ενεργειών Για να ξεκινήσει κάποιος προγραμματιστής να εργάζεται σε ένα έργο μπορεί να ακολουθήσει τα παρακάτω βήματα. Για τις ανάγκες τους παραδείγματος θεωρούμε πως: * ο χρήστης αυτός έχει παντού το όνομα χρήστη `developer` * το κεντρικό αποθετήριο ή το canonical repository είναι το `itminedu/application` * τα αποθετήρια φιλοξενούνται στον εξυπηρετητή με όνομα `gitlab`, όπως για παράδειγμα είναι ο [git.minedu.gov.gr](https://git.minedu.gov.gr) Τα βασικά βήματα περιλαμβάνουν: ## 1. Fork του αποθετηρίου στο gitlab Ο `developer` κάνει fork το κεντρικό αποθετήριο `itminedu/application` στο `gitlab`. Έτσι θα έχει ένα _δικό του_ αποθετήριο του έργου `developer/application` ![Fork repository στο gitlab](assets/images/gitlab-fork.png) ## 2. Fork του αποθετηρίου τοπικά Ο `developer` κάνει clone το δικό του αποθετήριο τοπικά. Έτσι ο `developer` αποκτά τοπικά ένα αποθετήριο `application` για το οποίο έχει αυτόματα οριστεί ως remote `origin` το `git@gitlab:developer/application.git` Ενδεικτικά: ```sh git clone git@gitlab:developer/application.git ``` Για προβολή όλων των remote repositories ο χρήστης του git μπορεί να χρησιμοποιήσει την εντολή: `git remote -v` η οποία θα εμφανίσει λίστα της μορφής: ``` origin git@gitlab:developer/application.git (fetch) origin git@gitlab:developer/application.git (push) ``` ## 3. Προσθήκη του κεντρικού αποθετήριου του έργου Ο `developer` προσθέτει ένα επιπλέον απομακρυσμένο αποθετήριο, το κεντρικό αποθετήριο του έργου `developer/application`. Δίνει στο απομακρυσμένο αποθετήριο το όνομα `canonical` Ενδεικτικά: ```sh git remote add canonical https://gitlab/itminedu/application.git ``` ``` origin git@gitlab:developer/application.git (fetch) origin git@gitlab:developer/application.git (push) canonical https://gitlab/itminedu/application.git (fetch) canonical https://gitlab/itminedu/application.git (push) ``` > Στο παράδειγμα χρησιμοποιείται το git@gitlab:developer/application.git ακριβώς όπως θα μπορούσε να χρησιμοποιηθεί και το https://git.minedu.gov.gr/developer/application.git. Το πρώτο αφορά πρόσβαση με πρωτόκολλο SSH το δεύτερο αφορά πρόσβαση με HTTPS. ## 4. Δημιουργία και εργασία σε χωριστό τοπικό branch για κάθε νέα λειτουργία Για κάθε νέα λειτουργία ο `developer` δημιουργεί και εργάζεται σε ένα χωριστό branch. Στο παράδειγμα μας το νέο branch ονομάζεται `new-feature`. Για χάρη του παραδείγματος θεωρούμε ότι το έργο έχει ένα κύριο branch `master` και δεν χρησιμοποιείται χωριστό branch (π.χ. `develop`) για την ανάπτυξη. Ενδεικτικά: ```sh # ας σιγουρευτούμε πως έχουμε ενεργό το master branch git checkout master # δημιουργία του νέου branch ωα αντίγραφο του master branch # αυτό πρέπει να γίνει μόνο **μία φορά** git checkout -b new-feature # εργασία και χαρά... # αποθήκευση της εργασίας git commit -m "New page layout" ``` Η εντολή που δημιουργεί το νέο branch είναι η `git checkout -b <όνομα>`. Εάν το branch υπάρχει ήδη απλώς το ενεργοποιούμε με την εντολή `git checkout <όνομα>`. ## 5. Ανέβασμα της νέας λειτουργίας στο προσωπικό απομακρυσμένο αποθετήριο Όταν πρέπει να γίνει προώθηση των αλλαγών για έλεγχο από την υπόλοιπη ομάδα ή για ενσωμάτωση στο κεντρικό αποθετήριο, ο `developer` ανεβάζει το τοπικό branch στο απομακρυσμένο αποθετήριο `git@gitlab:developer/application.git`. Ενδεικτικά: ```sh # το -u δεν είναι υποχρεωτικό git push -u origin new-feature ``` Από αυτό το σημείο και μετά οποιοσδήποτε έχει πρόσβαση στο απομακρυσμένο αποθετήριο `git@gitlab:developer/application.git` μπορεί να πάρει το `new-feature` branch, να εργαστεί σε αυτό και να ανεβάσει εκ νέου αλλαγές. Εφόσον ένας συνεργάτης κάνει αλλαγές στο `new-feature` branch ή ο ίδιος ο `developer` κάνει κάποια αλλαγή από το γραφικό περιβάλλον του εξυπηρετητή, τότε οφείλει να ενσωματώσει αυτές τις αλλαγές και στο τοπικό του αντίγραφο, εκτελώντας μια εντολή pull, όπως ενδεικτικά `git pull my-gitlab new-feature` ## 6. Αίτημα ενσωμάτωσης στο κεντρικό αποθετήριο Όταν ολοκληρωθούν οι αλλαγές ο `developer` πραγματοποιεί *pull request* μέσω του προσωπικού του αποθετήριου `developer/application` στο master branch στο κεντρικό αποθετήριο `itminedu/application`. ![Merge request στο gitlab](assets/images/pull-request-btn.png) Εάν χρειαστεί να συμμαζευτεί το ιστορικό αλλαγών, μπορεί να γίνει και στο τοπικό repository αλλά _μόνο σε νέο branch και ποτέ αλλάζοντας το ιστορικό commits που έχουν γίνει ήδη push_. Ενδεικτικό παράδειγμα: ```sh # το ιστορικό των αλλαγών έχει 3 commits για μία μικρή αλλαγή $ git log --oneline 86f01d8 Typo fix 60de953 Add assets dir 85ab329 Some work 440af4d Update README.md 89ac5da Update README.md b0fb40a Add readme.md # θα "συμμαζέψουμε" το ιστορικό, ξεκινώντας από το σημείο που είναι το κεντρικό αποθετήριο $ git rebase -i canonical/master # το -i είναι η μαγική παράμετρος για να αλλάξουμε το ιστορικό # χωρίς το -i η εντολή θα επανεκτελέσει όλες τις αλλαγές από το σημείο που είναι το κεντρικό αποθετήριο # αρχικά το git μα δίνει το ιστορικό αλλαγών, προτείνοντας να επανεκτελέσει (pick) τα commits pick 85ab329 Some work pick 60de953 Add assets dir pick 86f01d8 Typo fix # εμείς αλλάζουμε τα δύο τελευταία ώστε να ενσωματωθούν στο προηγούμενο commit, τελικά σε ένα commit όλα, στο παράδειγμα μας pick 85ab329 Some work f 60de953 Add assets dir f 86f01d8 Typo fix # αποθηκεύουμε το αρχείο και το git εκτελεί τις αλλαγές # αν όλα πάνε καλά θα δούμε κάτι αντίστοιχο με το παρακάτω [detached HEAD a5affda] Some work Date: Thu Mar 16 09:41:46 2017 +0200 2 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 assets/images/gitlab-fork.png Successfully rebased and updated refs/heads/master. # αν υπάρχουν αρχεία με "συγκρούσεις", θα πρέπει να γίνει "conflict resolution" # το ιστορικό μετά την αλλαγή $ git log --oneline a5affda Some work 440af4d Update README.md 89ac5da Update README.md b0fb40a Add readme.md ``` # Διαδικασία συγχρονισμού αποθετήριων Μια σύντομη διαδικασία συγχρονισμού του απομακρυσμένου αποθετήριου του `developer`, μέσω του τοπικού αποθετήριου, με τις τελευταίες αλλαγές στο κεντρικό αποθετήριο είναι η εξής. ```sh # επιλέγω το σωστό branch git checkout master # συγχρονίζω τις αλλαγές του κεντρικού εποθετήριου στο τοπικό git pull canonical master # συγχρονίζω τις αλλαγές στο δικό μου απομακρυσμένο αποθετήριο git push origin master ``` **Προσοχή!** Η διατήρηση πολλαπλών repositories για ένα έργο θα απαιτήσει να κρατήσει ο κάθε χρήστης συγχρονισμένα τα σχετικά repositories. Οδηγίες στα σχετικά links που παρατίθενται στο τέλος της σελίδας. # Παραπομπές 1. https://git-scm.com/book 2. https://www.atlassian.com/git/tutorials/comparing-workflows 3. Understanding the GitHub Flow https://guides.github.com/introduction/flow/ 4. Syncing a fork https://help.github.com/articles/syncing-a-fork/