![it-logo-100x100.png](https://hackmd.io/_uploads/HkjdnyFXp.png) # Introduction to `git` --- ## Χρήση version control - Προτερήματα: - Εύκολη αρχικοποίηση - Πλήρες και αναζητήσιμο ιστορικό αλλαγών - Ευκολότερη συνεργασία στην ανάπτυξη του κώδικα - Αρνητικά: - Προσθήκη επιπλέων διαδικασιών - Ακατάλληλο για αρχεία που δεν είναι text based - Δημοφιλή συνεργατικά εργαλεία: - GitHub (μεγάλη κοινότητα χρηστών) - GitLab (εύκολη υλοποίηση "on-prem") --- ## Δημοφιλή εργαλεία version control ### Κεντρικοποιημένα - cvs - subversion ### Κατανεμημένα - git - mercurial --- ## Μερικές βασικές έννοιες - **commit**: ένα καταγεγραμμένο σύνολο αλλαγών. Τα commits αποτελούν εικόνες ("snapshots") του κώδικά μας οπότε και μπορούμε να επανέλθουμε σε αυτά αν το θελήσουμε - **repository** (αποθετήριο): όλο το ιστορικό ενός κώδικα/project - **branches**: κλαδιά ανάπτυξης (το default branch στο git ονομάζεται `master` ή `main`) --- ## Αρχικοποίηση περιβάλλοντος ```bash $ git config --global user.name "John Doe" $ git config --global user.email "john@example.com" ``` ή εναλλακτικά: ```bash $ git config --global --edit ``` --- ## Βοήθεια! Όλες οι εντολές του `git` συντάσσονται ως δύο λέξεις, π.χ.: ``` $ git branch ... $ git remote ... $ git clone ... $ git commit ... ``` Για να δούμε το εκάστοτε help page απλά δίνουμε στην εντολή που μας ενδιαφέρει την παράμετρο `--help`, δηλαδή: ``` $ git branch --help $ git remote --help $ git clone --help $ git commit --help ``` --- ## Αρχικοποίηση repository ```bash $ cd Repositories/git-lesson $ ls -lR $ ls -la $ git init $ ls -la $ git status On branch main No commits yet ... ``` --- ## Stage and commit Στο `git` υπάρχει η έννοια της προετοιμασίας (staging) ενός commit. Όσα αρχεία (ή αλλαγές) κρίνεται ότι είναι έτοιμα γίνονται stage για commit με την `git add`, π.χ: ```bash $ git add exercise_a $ git status On branch main No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: exercise_a/parser.sh new file: exercise_a/schedule.txt new file: exercise_a/students.txt ... ``` Για να γίνουν commit οι αλλαγές χρησιμοποιούμε την `git commit`. ```bash $ git commit -m "Committed exercise A" [main (root-commit) d37b3ae] Committed exercise A 3 files changed, 25 insertions(+) create mode 100755 exercise_a/parser.sh create mode 100644 exercise_a/schedule.txt create mode 100644 exercise_a/students.txt ``` Όταν εκτελείται η `git commit` το Git μαζεύει τα αρχεία που κάναμε stage με την `git add` και αποθηκεύει ένα αντίγραφο μέσα στον φάκελο `.git`. Αυτό το αντίγραφο αποτελεί το commit και το `d37b3ae` είναι το αναγνωριστικό του. ```mermaid gitGraph commit id:"d37b3ae" ``` Με την παράμετρο `-m` δώσαμε το commit message (την περιγραφή των αλλαγών). Καλό είναι το μήνυμα αυτό να είναι περιεκτικό και να συμπληρώνει την πρόταση "this commit will/does/is...". Για περαιτέρω διάβασμα: - https://cbea.ms/git-commit/ --- Ας προχωρήσουμε να προσθέσουμε και το 2ο φάκελο σε νέο commit: ``` $ git add exercise_b/ $ git commit -m "Committed exercise B" [main a756907] Committed exercise B 1 file changed, 5 insertions(+) create mode 100755 duckduckgo/ddg.sh ``` :::info :information_source: θα μπορουσαμε να είχαμε προσθέσει και τους δύο φακέλους με ένα commit, αλλά κάναμε δύο commit περισσότερο ως άσκηση.) ::: --- Aν εκτελέσουμε τώρα πλέον `git status` βλέπουμε τα εξής: ```bash $ git status On branch main nothing to commit, working tree clean ``` Επιπλέον με την `git log` μπορούμε να δούμε το ιστορικό των αλλαγώ: ```bash $ git log --oneline a756907 (HEAD -> main) Committed exercise B d37b3ae Committed exercise A ``` ```mermaid gitGraph commit id:"d37b3ae" commit id:"a756907" ``` ## Ας κάνουμε λίγες αλλαγές Π.χ. ας αλλάξουμε το username `zzz` σε `beta` χρησιμοποιώντας έναν editor, π.χ.: ``` $ vim exercise_a/schedule.txt $ vim exercise_a/students.txt ``` Πριν κάνουμε οτιδήποτε μπορούμε να δούμε τι αλλαγές κάναμε ως `diff` με την εντολή `git diff`: ```bash $ git diff ... ``` Αν οι αλλαγές είναι ΟΚ μπορούμε να προχωρήσουμε σε stage (`git add`) και commit (`git commit`): ``` $ git add exercise_a $ git commit -m "Change username zzz to beta" [main 0a828a1] Change username zzz to beta 2 files changed, 9 insertions(+), 9 deletions(-) ``` ```mermaid gitGraph commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" ``` ## Αναζήτηση αλλαγών ```bash $ git diff HEAD~1 exercise_a/students.txt ``` ή ```bash $ git diff a756907 exercise_a/students.txt ``` ## Αναίρεση αλλαγών που δεν έχουν γίνει commit ```bash $ echo -n > exercise_a/students.txt $ cat exercise_a/students.txt $ git checkout exercise_a/students.txt Updated 1 path from the index $ cat exercise_a/students.txt ... ``` ## Αναίρεση αλλαγών που έχουν γίνει commit ```bash $ echo -n > exercise_a/students.txt $ git add exercise_a/students.txt $ git commit -m "The wrong commit" [main a273d51] The wrong commit 1 file changed, 6 deletions(-) ``` ```mermaid gitGraph commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" ``` Ο τρόπος να αναιρέσουμε ένα commit είναι με την `git revert` η οποία δέχεται ως όρισμα ένα commit id και επί της ουσίας εφαρμόζει ένα νέο commit με το "αρνητικό" του commit id. ```bash $ git revert a273d51 [main 53f1c5e] Revert "The wrong commit" 1 file changed, 6 insertions(+) ``` ```mermaid gitGraph commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" ``` --- ## `.gitignore` Αν έχουμε αρχεία που δεν θέλουμε να αποτελέσουν μέρος του repository (π.χ. αρχεία με κωδικούς ή binary αρχεία) τότε χρησιμοποιούμε το αρχείο `.gitignore` ώστε να υποδείξουμε στο git ποιά είναι τα αρχεία αυτά που δεν θέλουμε να γίνονται track. Ας φτιάξουμε μερικά αρχεία για να δούμε πώς δουλεύει: ```bash $ touch {a,b}.bin $ mkdir results $ touch results/c.out $ git status On branch main Untracked files: (use "git add <file>..." to include in what will be committed) a.bin b.bin results/ nothing added to commit but untracked files present (use "git add" to track) ``` Ας χρησιμοποιήσουμε το `.gitignore` ```bash $ vim .gitignore $ cat .gitignore *.bin results/ $ git status On branch main Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore nothing added to commit but untracked files present (use "git add" to track) ``` ```bash $ git add .gitignore $ git commit -m "Ignore binary files and the results folder" [main ebc0636] Ignore binary files and the results folder 1 file changed, 2 insertions(+) create mode 100644 .gitignore $ git status On branch main nothing to commit, working tree clean ``` ```mermaid gitGraph commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" ``` --- ## Git remotes :::success :information_source: Θα χρησιμοποιήσουμε το GitLab instance του ΚΗΔ για το demo μας. Στην περίπτωση του GitHub οι ενέργειες που θα πρέπει να ακολουθήσουμε είναι παρόμοιες. ::: :::warning Αν είναι η πρώτη φορά που χρησιμοποιείτε το GitLab προκειμένου να χρησιμοποιήσετε `ssh` για την μεταφορά των περιεχομένων του τοπικού Git repository θα χρειαστεί να ανεβάσετε το public ssh κλειδί σας στο GitLab. Αυτό το κάνετε επιλέγοντας από το avatar σας Edit Profile -> SSH Keys -> Add new key. Αν δεν έχετε φτιάξει ssh κλειδί μπορείτε να φτιάξετε ένα με την εντολή `ssh-keygen`. ::: Για να φτιάξουμε ένα νέο αποθετήριο επιλέγουμε "New Project" -> "Create Blank Project". Στα πεδία επιλέγουμε το namespace, το όνομα και το visibility του project. Εφόσον θα κάνουμε `git push` κάποιο υφιστάμενο Git repo καλό και σωστό είναι να μην έχει README. Για να κάνουμε `git push` τα περιεχόμενα από το τοπικό Git repository θα χρειαστεί να εκτελέσουμε τις εξής εντολές: ```bash $ git remote add origin gitlab@repo.it.auth.gr:pkoro/git-lesson.git $ git push -u origin main Enumerating objects: 23, done. Counting objects: 100% (23/23), done. Delta compression using up to 10 threads Compressing objects: 100% (19/19), done. Writing objects: 100% (23/23), 2.41 KiB | 2.41 MiB/s, done. Total 23 (delta 4), reused 0 (delta 0), pack-reused 0 To repo.it.auth.gr:pkoro/git-lesson.git * [new branch] main -> main branch 'main' set up to track 'origin/main'. ``` :::info Αν έχουμε ήδη φτιάξει τοπικά και άλλα branches (πέρα από το `main` ή το `master`) μπορούμε να επιλέξουμε να τα κάνουμε push όλα μαζί με την εξής ```bash $ git push -u origin --all ``` ::: Στο γραφικό περιβάλλον του GitLab επιλέγοντας <kbd>F5</kbd> θα πρέπει να βλέπουμε πλέον ότι τα περιεχόμενα του τοπικού μας repository έχουν αντιγραφεί στο remote repository στο GitLab. Από το μενού Code -> Commits στα αριστερά μπορούμε να δούμε και τα commits που έχουμε κάνει. --- :::info # https vs ssh Για να κάνουμε `git push` επιλέξαμε στα παραπάνω ως remote να ορίσουμε το ssh endpoint (gitlab@repo.it.auth.gr:pkoro/git-lesson.git). Θα μπορούσαμε να ρυθμίσουμε εναλλακτικά το https (https://repo.it.auth.gr/pkoro/git-lesson.git). Ένα αρνητικό που έχει το https σε σχέση με το ssh είναι ότι κάθε φορά μας ζητάει το username password. ::: Με την εντολή `git remote -v` βλέπουμε τι remotes έχουμε ορίσει: ```bash $ git remote -v origin gitlab@repo.it.auth.gr:pkoro/git-lesson.git (fetch) origin gitlab@repo.it.auth.gr:pkoro/git-lesson.git (push) ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" ``` </td> </tr> </table> :::danger :::spoiler Τι διαφορά έχει το `git push` από το `git commit`; :::success H `git commit` χρησιμοποιείται για να φτιάξουμε ένα commit (μιά εικόνα ή snapshot του κώδικά μας). H `git push` για να μεταφέρουμε όλο το περιεχόμενο προς ένα remote git repository (για να μοιράσουμε τον κώδικά μας δηλαδή όχι για να κάνουμε αλλαγές σε αυτόν). ::: --- ## Branching και αλλαγές Εφόσον χρησιμοποιούμε ένα remote ως "source of truth" καλό είναι πλέον στο τοπικό μας repository να μην κάνουμε αλλαγές απευθείας στο `main` (ή `master`) branch αλλά να κάνουμε αλλαγές σε νέο branch. Για παράδειγμα αν έρθει ένας νέος φοιτητής και θέλουμε να τον προσθέσουμε στο πρόγραμμα είναι εύλογο να ξεκινήσουμε ανοίγωντας ένα νέο branch (π.χ. `new_student`) και κάνοντας αλλαγές σε αυτό: ```bash $ git checkout -b new_student Switched to a new branch 'new_student' ``` Έπειτα κάνουμε τις αλλαγές μας και όταν είμαστε έτοιμοι: ```bash $ git commit -m "Add new student" [new_student 02c79ab] Add new student 2 files changed, 5 insertions(+), 4 deletions(-) ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" ``` </td> </tr> </table> Για να περαστεί η αλλαγή και στο remote θα πρέπει να κάνουμε `git push` το νέο branch: ```bash $ git push -u origin new_feature Enumerating objects: 9, done. Counting objects: 100% (9/9), done. Delta compression using up to 10 threads Compressing objects: 100% (5/5), done. Writing objects: 100% (5/5), 512 bytes | 512.00 KiB/s, done. Total 5 (delta 3), reused 0 (delta 0), pack-reused 0 remote: remote: To create a merge request for new_student, visit: remote: https://repo.it.auth.gr/pkoro/git-lesson/-/merge_requests/new?merge_request%5Bsource_branch%5D=new_feature remote: To repo.it.auth.gr:pkoro/git-lesson.git * [new branch] new_feature -> new_student branch 'new_feature' set up to track 'origin/new_feature'. ``` <table> <tr> <td>Local (~/Repositores/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" ``` </td> </tr> </table> --- Ανοίγωντας το URL που μας επιστρέφει το GitLab σε ένα browser μας δίνεται η επιλογή να ανοίξουμε ένα "Merge Request". :::info Στο "Merge Request" καλό και χρήσιμο είναι να βάζουμε καλή περιγραφή σε όλα τα πεδία (Subject και Body) ώστε αυτός που θα το διαβάσει (και ενδεχομένως θα χρειαστεί να κάνει review τις αλλαγές) να έχει μιά καλή αντίληψη του τι περιμένει να δει. ::: Εφόσον οι αλλαγές γίνουν approve και merge η εικόνα των δύο repositories είναι η εξής: <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> </tr> </table> Για να φέρουμε τις αλλαγές πίσω στο τοπικό repo θα χρειαστεί να κάνουμε `git fetch` το branch main από το remote repository και `git merge` στο τοπικό main repository. ```bash $ git checkout main Switched to branch 'main' Your branch is up to date with 'origin/main'. $ git fetch origin main remote: Enumerating objects: 1, done. remote: Counting objects: 100% (1/1), done. remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (1/1), 262 bytes | 262.00 KiB/s, done. From repo.it.auth.gr:pkoro/git-lesson * branch main -> FETCH_HEAD ebc0636..ea22195 main -> origin/main $ git merge origin/main Updating ebc0636..ea22195 Fast-forward exercise_a/schedule.txt | 8 ++++---- exercise_a/students.txt | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> </tr> </table> --- ## Συνεργασία Για να επιτρέψουμε σε ένα συνεργάτη μας να κάνει αλλαγές στο repo που φτιάξαμε στο GitLab θα πρέπει να τον προσθέσουμε στα μέλη (members) του project. Για τα επίπεδα πρόσβασης μας δίνονται διάφορες επιλογές (συνήθως -αν δεν είμαστε σίγουροι- επιλέγουμε Developer ρόλο για συνεργάτες μας που πρόκειται να κάνουν αλλαγές στον κώδικα). Ο συνεργάτης μας (έστω ο χρήστης `beta`) έπειτα μπορεί να κάνει **fork** το remote repository στο προσωπικό του workspace και να αναλάβει να κάνει αλλαγές σε αυτό. <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> <td>Remote beta/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> </tr> </table> --- Αφότου κάνει fork μπορεί να κάνει clone το repository στον υπολογιστή του ο χρήστης `beta`. ```bash $ cd ~beta $ git clone gitlab@repo.it.auth.gr:beta/git-lesson.git Cloning into 'git-lesson'... remote: Enumerating objects: 29, done. remote: Counting objects: 100% (29/29), done. remote: Compressing objects: 100% (25/25), done. remote: Total 29 (delta 8), reused 0 (delta 0), pack-reused 0 Receiving objects: 100% (29/29), done. Resolving deltas: 100% (8/8), done. ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> <td>Remote beta/git-lesson.git</td> <td>Local (~beta/git-lesson)</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> </tr> </table> --- Κατά "τα γνωστά" ο χρήστης beta κάνει κάποιες αλλαγές: ```bash $ git checkout -b update_my_schedule $ # edit exercise_a/schedule.txt $ git status On branch update_my_schedule Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: exercise_a/schedule.txt no changes added to commit (use "git add" and/or "git commit -a") $ git add exercise_a/schedule.txt git commit -m "Updated my schedule" [update_my_schedule 3a581f4] Updated my schedule 1 file changed, 2 insertions(+), 2 deletions(-) ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> <td>Remote beta/git-lesson.git</td> <td>Local (~beta/git-lesson)</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" ``` </td> </tr> </table> --- Έπειτα θα κάνει `git push` τις αλλαγές του στο remote του (επίσης "κατά τα γνωστά"): ```bash $ git push -u origin update_my_schedule Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 10 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 431 bytes | 431.00 KiB/s, done. Total 4 (delta 2), reused 0 (delta 0), pack-reused 0 remote: remote: To create a merge request for update_my_schedule, visit: remote: https://repo.it.auth.gr/beta/git-lesson/-/merge_requests/new?merge_request%5Bsource_branch%5D=update_my_schedule remote: To repo.it.auth.gr:beta/git-lesson.git * [new branch] update_my_schedule -> update_my_schedule branch 'update_my_schedule' set up to track 'origin/update_my_schedule'. ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> <td>Remote beta/git-lesson.git</td> <td>Local (~beta/git-lesson)</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" ``` </td> </tr> </table> --- Το GitLab (όπως και το GitHub) δίνει τη δυνατότητα ένα Merge Request να γίνει από ένα remote προς ένα άλλο. Άρα εφόσον το "source of truth" είναι το `pkoro/git-lesson` το Merge Request θα πρέπει να γίνει προς αυτό το remote και συγκεκριμένα προς το `main` branch. Αφότου γίνει merge η εικόνα των repositories είναι αυτή: <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> <td>Remote beta/git-lesson.git</td> <td>Local (~beta/git-lesson)</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" ``` </td> </tr> </table> --- ## Συγχρονισμός Ο συνεργάτης `beta` προκειμένου να κάνει `git fetch` και `git merge` τις αλλαγές από το remote `pkoro/git-lesson` repository θα χρειαστεί να το ορίσει ως νέο remote. Κατά σύμβαση αυτό το remote που έχει το ρόλο "source of truth" το ονομάζουμε `upstream`. :::info :warning: `~beta/git-lesson` ```bash $ git remote add upstream gitlab@repo.it.auth.gr:pkoro/git-lesson.git $ git remote -v origin gitlab@repo.it.auth.gr:beta/git-lesson.git (fetch) origin gitlab@repo.it.auth.gr:beta/git-lesson.git (push) upstream gitlab@repo.it.auth.gr:pkoro/git-lesson.git (fetch) upstream gitlab@repo.it.auth.gr:pkoro/git-lesson.git (push) ``` ::: Προκειμένου να "συγχρονίσει" πλέον τις αλλαγές οι `git fetch` και `git merge` θα συνταχθούν ως εξής: ```bash $ git checkout main $ git fetch upstream main remote: Enumerating objects: 1, done. remote: Counting objects: 100% (1/1), done. remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (1/1), 270 bytes | 270.00 KiB/s, done. From repo.it.auth.gr:pkoro/git-lesson * branch main -> FETCH_HEAD * [new branch] main -> upstream/main $ git merge upstream/main Updating ea22195..cd9dd46 Fast-forward exercise_a/schedule.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> <td>Remote beta/git-lesson.git</td> <td>Local (~beta/git-lesson)</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" ``` </td> </tr> </table> --- ## Git conflicts (and how to resolve them) Έστω ότι παράλληλα με την αλλαγή στο πρόγραμμα του χρήστη `beta` ο χρήστης `pkoro` έκανε επίσης κάποια αλλαγή (π.χ. στις ώρες του χρήστη `testakos`) ```bash $ git checkout -b testakos $ # edit exercise_a/schedule.txt $ git add exercise_a/schedule.txt $ git commit -m "Update schedule for testakos user" [testakos 282dbef] Update schedule for testakos user 1 file changed, 1 insertion(+), 1 deletion(-) ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> <td>Remote beta/git-lesson.git</td> <td>Local (~beta/git-lesson)</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch testakos checkout testakos commit id:"282dbef" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" ``` </td> </tr> </table> --- ```bash $ git push -u origin testakos ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> <td>Remote beta/git-lesson.git</td> <td>Local (~beta/git-lesson)</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch testakos checkout testakos commit id:"282dbef" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" branch testakos checkout testakos commit id:"282dbef" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" ``` </td> </tr> </table> --- Καθώς έχει γίνει αλλαγή στην ίδια γραμμή από το Merge Request και commit που προηγήθηκε το GitLab μας ειδοποιεί ότι η νέα αλλαγή δεν μπορεί να περαστεί διότι υπάρχει conflict. ![image](https://hackmd.io/_uploads/rJWddZGN6.png) Για να δούμε εποπτικά που υπάρχει το πρόβλημα μπορούμε να επιλέξουμε το κουμπί "Resolve conflicts" ![image](https://hackmd.io/_uploads/S1V-tWMVa.png) Βλέπουμε ότι η δική μας αλλαγή (our changes) είναι η αφαίρεση του χρήστη `testakos` από το πρόγραμμα της Τρίτης. Η αλλαγή που έχει κάνει ο άλλος developer (their changes) είναι η προσθήκη του χρήστη `beta` στο πρόγραμμα της Τετάρτης. Από το γραφικό περιβάλλον μας δίνεται η επιλογή να επιλέξουμε μία από τις δύο αλλά εμείς θα θέλαμε και τις δύο να τις συμπεριλάβουμε. Αυτό μπορεί να γίνει είτε επιλέγοντας στο γραφικό περιβάλλον το κουμπί "Edit Inline" είτε Locally στο τοπικό Git repo. Το GitLab μας δίνει οδηγίες για το δεύτερο αν στην προηγούμενη σελίδα επιλέξουμε "Resolve locally". :::info :warning: Resolve locally με `git rebase` ```bash $ git checkout main Switched to branch 'main' Your branch is up to date with 'origin/main'. $ git fetch origin main remote: Enumerating objects: 8, done. remote: Counting objects: 100% (8/8), done. remote: Compressing objects: 100% (5/5), done. remote: Total 5 (delta 3), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (5/5), 544 bytes | 181.00 KiB/s, done. From repo.it.auth.gr:pkoro/git-lesson * branch main -> FETCH_HEAD ea22195..cd9dd46 main -> origin/main $ git merge origin/main Updating ea22195..cd9dd46 Fast-forward exercise_a/schedule.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) ``` ::: <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch testakos order: 3 checkout testakos commit id:"282dbef" checkout main branch update_my_schedule order: 2 checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" branch testakos checkout testakos commit id:"282dbef" ``` </td> </tr> </table> --- ### Διαδικασία rebase ```bash! $ git checkout testakos Switched to branch 'testakos' Your branch is up to date with 'origin/testakos'. $ git rebase main Auto-merging exercise_a/schedule.txt CONFLICT (content): Merge conflict in exercise_a/schedule.txt error: could not apply 282dbef... Update schedule for testakos user hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 282dbef... Update schedule for testakos user $ git status interactive rebase in progress; onto cd9dd46 Last command done (1 command done): pick 282dbef Update schedule for testakos user No commands remaining. You are currently rebasing branch 'testakos' on 'cd9dd46'. (fix conflicts and then run "git rebase --continue") (use "git rebase --skip" to skip this patch) (use "git rebase --abort" to check out the original branch) Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) both modified: exercise_a/schedule.txt no changes added to commit (use "git add" and/or "git commit -a") $ # Edit exercise_a/schedule.txt and fix conflicts $ git status interactive rebase in progress; onto cd9dd46 Last command done (1 command done): pick 282dbef Update schedule for testakos user No commands remaining. You are currently rebasing branch 'testakos' on 'cd9dd46'. (fix conflicts and then run "git rebase --continue") (use "git rebase --skip" to skip this patch) (use "git rebase --abort" to check out the original branch) Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) both modified: exercise_a/schedule.txt no changes added to commit (use "git add" and/or "git commit -a") $ git add exercise_a/schedule.txt $ git rebase --continue # On the EDITOR that pops up change the commit message if you'd like or just exit [detached HEAD 910a2f2] Update schedule for testakos user 1 file changed, 1 insertion(+), 1 deletion(-) Successfully rebased and updated refs/heads/testakos. $ git status On branch testakos Your branch and 'origin/testakos' have diverged, and have 3 and 1 different commits each, respectively. (use "git pull" to merge the remote branch into yours) nothing to commit, working tree clean ``` <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" checkout main branch update_my_schedule order: 2 checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" branch testakos order: 3 checkout testakos commit id:"910a2f2" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" branch testakos checkout testakos commit id:"282dbef" ``` </td> </tr> </table> :::danger :radioactive_sign: Προσοχή στο ότι πλέον έχει αλλάξει το commit id. Αυτό που έχουμε τοπικά δεν είναι το ίδιο με αυτό που υπάρχει από το `git push` που προηγήθηκε στο remote. Για το λόγο αυτό η `git push` πλέον θα αποτύχει: ```bash $ git push -u origin testakos To repo.it.auth.gr:pkoro/git-lesson.git ! [rejected] testakos -> testakos (non-fast-forward) error: failed to push some refs to 'repo.it.auth.gr:pkoro/git-lesson.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. ``` Προκειμένου να κάνουμε push θα χρειαστεί να χρησιμοποιήσουμε το `-f` (ή `--force`): ```bash $ git push -f -u origin testakos Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 10 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 434 bytes | 434.00 KiB/s, done. Total 4 (delta 2), reused 0 (delta 0), pack-reused 0 remote: remote: View merge request for testakos: remote: https://repo.it.auth.gr/pkoro/git-lesson/-/merge_requests/3 remote: To repo.it.auth.gr:pkoro/git-lesson.git + 282dbef...910a2f2 testakos -> testakos (forced update) branch 'testakos' set up to track 'origin/testakos'. ``` ::: <table> <tr> <td>Local (~/Repositories/git-lesson)</td> <td>Remote pkoro/git-lesson.git</td> </tr> <tr> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" checkout main branch update_my_schedule order: 2 checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" branch testakos order: 3 checkout testakos commit id:"910a2f2" ``` </td> <td> ```mermaid gitGraph TB: commit id:"d37b3ae" commit id:"a756907" commit id:"0a828a1" commit id:"a273d51" type: REVERSE commit id:"53f1c5e" commit id:"ebc0636" branch new_student commit id:"02c79ab" checkout main merge new_student id:"ea221955" branch update_my_schedule checkout update_my_schedule commit id:"3a581f4" checkout main merge update_my_schedule id:"cd9dd462" branch testakos checkout testakos commit id:"910a2f2" ``` </td> </tr> </table> --- :::info :100: voilà Το Merge Request μετά το "force push" είναι "mergable". ![image](https://hackmd.io/_uploads/HypozGGV6.png) :::