Η συγχώνευση ή το merge — είναι η λειτουργία συνδυασμού δύο κλαδιών στο Git που ενώνει τις αλλαγές από το ένα κλαδί στο άλλο. Στη σύγχρονη ανάπτυξη, το merge είναι ο τυπικός τρόπος ενσωμάτωσης ενός feature κλαδιού στο κύριο κλαδί του έργου. Σύμφωνα με το GitHub Octoverse 2024, καθημερινά εκτελούνται περισσότερα από 15 εκατομμύρια merges. Merge — ο βασικός μηχανισμός συνεργατικής εργασίας που επιτρέπει την ένωση της δουλειάς πολλών προγραμματιστών σε ένα ενιαίο προϊόν.
Κύρια σημεία
Το merge στο Git — είναι η λειτουργία συνδυασμού δύο ή περισσότερων ιστοριών ανάπτυξης σε μία. Όταν ένας προγραμματιστής συγχωνεύει ένα κλαδί, το Git βρίσκει αυτόματα τον κοινό πρόγονο (base commit) και δημιουργεί ένα νέο commit συγχώνευσης που περιλαμβάνει αλλαγές και από τα δύο κλαδιά. Three-way merge — ο τυπικός αλγόριθμος που συγκρίνει τρεις καταστάσεις: τον κοινό πρόγονο, το πρώτο κλαδί και το δεύτερο κλαδί.
Η διαδικασία merge ξεκινά με την εντολή git merge. Το Git καθορίζει το σημείο απόκλισης των κλαδιών και εφαρμόζει διαδοχικά τις αλλαγές από το κλαδί πηγή στο κλαδί προορισμού. Αν οι αλλαγές δεν έρχονται σε σύγκρουση, το Git εκτελεί fast-forward ή δημιουργεί merge commit ανάλογα με τις ρυθμίσεις. Fast-forward — το σενάριο όπου το κλαδί προορισμού απλά μετακινείται στα commits του κλαδιού πηγής.
# Μετάβαση στο κλαδί προορισμού και συγχώνευση
git checkout main
git merge feature/payment-module
# Συγχώνευση με ρητό no-fast-forward
git merge --no-ff feature/payment-module
# Ακύρωση συγχώνευσης αν οι συγκρούσεις είναι πολύ περίπλοκες
git merge --abort
Η σημαία --no-ff (no fast-forward) επιβάλλει τη δημιουργία merge commit ακόμα κι όταν το fast-forward είναι δυνατό. Αυτό διατηρεί την πληροφορία ότι οι αλλαγές έγιναν σε ξεχωριστό κλαδί. Πολλές ομάδες προτιμούν αυτήν ακριβώς την προσέγγιση για να διατηρήσουν τη διακλάδωση της ιστορίας σε ρητή μορφή.
Στο Git υπάρχουν τρεις κύριες στρατηγικές συγχώνευσης κλαδιών, κάθε μία κατάλληλη για ένα συγκεκριμένο σενάριο. Η επιλογή στρατηγικής εξαρτάται από την κουλτούρα της ομάδας και τις απαιτήσεις για την καθαρότητα της ιστορίας του έργου.
| Στρατηγική | Αποτέλεσμα | Πότε να εφαρμόζεται |
|---|---|---|
| Standard merge | merge commit + πλήρης ιστορία | ομάδες που εκτιμούν την πλήρη ιστορία |
| Squash merge | ένα commit, ιστορία συμπιεσμένη | feature κλαδιά με πολλά μικρά commits |
| Rebase merge | γραμμική ιστορία, χωρίς merge commit | προσωπικά feature κλαδιά, πριν τη δημιουργία PR |
Το Standard merge δημιουργεί ένα merge commit με δύο γονείς. Η πλήρης ιστορία διατηρείται, αλλά το γράφημα διακλάδωσης γίνεται πιο περίπλοκο. Squash merge συνδυάζει όλα τα commits του feature κλαδιού σε ένα και το εφαρμόζει στο κλαδί προορισμού — η ιστορία γίνεται γραμμική και καθαρή, αλλά χάνεται η πληροφορία για τα ενδιάμεσα στάδια.
Το Rebase, αν και δεν είναι πλήρης συγχώνευση, επιτυγχάνει το ίδιο αποτέλεσμα — οι αλλαγές από το ένα κλαδί μεταφέρονται στο άλλο. Η διαφορά είναι ότι η ιστορία ξαναγράφεται: τα commits του feature κλαδιού δημιουργούνται εκ νέου πάνω από το τελευταίο commit του κλαδιού προορισμού. Αυτό δίνει μια ιδανικά γραμμική ιστορία, αλλά απαιτεί force push κατά την αποστολή.
Σύγκρουση κατά το merge προκύπτει όταν σε δύο κλαδιά έχουν αλλάξει οι ίδιες γραμμές ενός αρχείου. Το Git δεν μπορεί να καθορίσει αυτόματα ποια έκδοση να διατηρήσει και απαιτεί την παρέμβαση του προγραμματιστή. Οι συγκρούσεις εμφανίζονται στα αρχεία ως ειδικοί δείκτες: <<<<<<<, =======, >>>>>>>.
Η διαδικασία επίλυσης σύγκρουσης περιλαμβάνει διάφορα βήματα. Πρώτα, ο προγραμματιστής ανοίγει το αρχείο με τη σύγκρουση και επιλέγει χειροκίνητα τις απαραίτητες αλλαγές. Είναι σημαντικό να μην επιλέγει απλά μία από τις εκδόσεις, αλλά να κατανοεί τη λογική και των δύο αλλαγών και να παίρνει τη σωστή απόφαση. Μετά την επεξεργασία του αρχείου, οι δείκτες σύγκρουσης αφαιρούνται και οι αλλαγές προστίθενται στο staging area μέσω git add.
# Προβολή λίστας αρχείων με συγκρούσεις
git status
# Εκκίνηση mergetool (π.χ. VS Code, IntelliJ)
git mergetool
# Αφού επιλυθούν όλες οι συγκρούσεις
git add .
git merge --continue
# Ή ακύρωση της συγχώνευσης εντελώς
git merge --abort
Η χρήση οπτικών εργαλείων merge επιταχύνει σημαντικά την επίλυση συγκρούσεων. Τα VS Code, IntelliJ IDEA και GitKraken παρέχουν διεπαφές με τρία πάνελ: τρέχον κλαδί, εισερχόμενο κλαδί και αποτέλεσμα. Το εργαλείο git mergetool ανοίγει αυτόματα τον ρυθμισμένο επεξεργαστή για κάθε αρχείο με σύγκρουση.
Ο καλύτερος τρόπος για να αποφύγετε περίπλοκες συγκρούσεις είναι ο τακτικός συγχρονισμός του feature κλαδιού με το κύριο κλαδί. Αν ο προγραμματιστής συγχωνεύει το main στο κλαδί του μία φορά την ημέρα, οι συγκρούσεις θα είναι μικρές και εύκολα επιλύσιμες. Η συσσώρευση αλλαγών για μία εβδομάδα εγγυάται περίπλοκες συγκρούσεις με υψηλό κίνδυνο σφαλμάτων.
Rebase και merge — δύο τρόποι συνδυασμού αλλαγών, και η επιλογή μεταξύ τους συχνά προκαλεί συζητήσεις στις ομάδες. Το Rebase μεταφέρει commits από το ένα κλαδί στο άλλο, ξαναγράφοντας την ιστορία. Το Merge δημιουργεί ένα νέο commit συγχώνευσης, διατηρώντας την ιστορία διακλάδωσης. Κάθε προσέγγιση έχει τα πλεονεκτήματα και τους περιορισμούς της.
Το Rebase είναι κατάλληλο όταν ένας προγραμματιστής εργάζεται στο τοπικό του feature κλαδί και θέλει να αποκτήσει μια καθαρή γραμμική ιστορία πριν από τη δημιουργία Pull Request. Μετά το rebase, όλα τα commits ταξινομούνται σειριακά, χωρίς περιττά merge commits. Ωστόσο, το rebase απαιτεί force push και δεν εφαρμόζεται σε κλαδιά στα οποία εργάζονται πολλά άτομα ταυτόχρονα.
Ο χρυσός κανόνας του Git: μη χρησιμοποιείτε rebase σε commits που έχουν ήδη σταλεί στο κοινό αποθετήριο. Αυτό εγγυάται ότι η ιστορία στο κοινό κλαδί παραμένει αμετάβλητη και άλλοι προγραμματιστές δεν θα συναντήσουν διπλότυπα ή χαμένα commits. Για την ενσωμάτωση του feature κλαδιού στο κύριο κλαδί, χρησιμοποιήστε merge μέσω Pull Request.
Η σωστή διαδικασία merge — η βάση της σταθερής ανάπτυξης. Στη σύγχρονη ομαδική εργασία, το merge εκτελείται όχι μέσω κονσόλας, αλλά μέσω Pull Request στο GitHub ή Merge Request στο GitLab. Το PR περνά από code review, αυτόματους ελέγχους CI και μόνο τότε συγχωνεύεται στο κύριο κλαδί.
Πρώτη πρακτική — κάντε merge μόνο αφού περάσουν όλοι οι έλεγχοι. Το CI pipeline πρέπει να χτίσει το έργο, να εκτελέσει δοκιμές και να ελέγξει την ποιότητα κώδικα. Αν έστω και ένας έλεγχος δεν περάσει, το merge μπλοκάρεται. Οι σύγχρονες πλατφόρμες (GitHub, GitLab) έχουν ενσωματωμένη προστασία: οι branch protection rules μπλοκάρουν αυτόματα το merge σε αποτυχία CI.
Δεύτερη πρακτική — μην κάνετε ποτέ merge σπασμένου κώδικα. Πριν από το merge, ο προγραμματιστής πρέπει να βεβαιωθεί ότι οι αλλαγές του δεν σπάνε το build και δεν προκαλούν παλινδρόμηση στην υπάρχουσα λειτουργικότητα. Γι' αυτό υπάρχουν αυτοματοποιημένες δοκιμές και code review.
Τρίτη πρακτική — καθαρίστε τα feature κλαδιά μετά το merge. Το κλαδί που έχει ήδη συγχωνευθεί πρέπει να διαγραφεί. Αυτό αποτρέπει τη σύγχυση και τη συμφόρηση του αποθετηρίου. Το GitHub προσφέρει αυτόματα διαγραφή του κλαδιού μετά το merge του PR, και οι ρυθμίσεις του αποθετηρίου μπορούν να ρυθμιστούν για αυτόματη διαγραφή.
Συχνές ερωτήσεις
Merge — η συγχώνευση δύο κλαδιών Git σε ένα. Οι αλλαγές από το ένα κλαδί μεταφέρονται στο άλλο μέσω τριμερούς συγχώνευσης (three-way merge). Το αποτέλεσμα καταγράφεται σε ένα νέο merge commit που έχει δύο γονικά commits. Το Merge commit διατηρεί πληροφορίες για το ποια κλαδιά συγχωνεύτηκαν.
Το Merge δημιουργεί ένα νέο merge commit, διατηρώντας την ιστορία διακλάδωσης. Το Rebase ξαναγράφει την ιστορία μεταφέροντας commits πάνω από άλλο κλαδί χωρίς τη δημιουργία merge commit. Το Rebase δίνει γραμμική ιστορία, αλλά απαιτεί force push. Το Merge είναι ασφαλέστερο για κοινά κλαδιά, το rebase καλύτερο για προσωπικά.
Ανοίξτε το αρχείο με τη σύγκρουση, βρείτε τους δείκτες <<<<<<<, ======= και >>>>>>>, επιλέξτε τις επιθυμητές αλλαγές και αφαιρέστε τους δείκτες. Προσθέστε το αρχείο μέσω git add και ολοκληρώστε το merge με git merge --continue. Χρησιμοποιήστε git mergetool για οπτική επίλυση στο VS Code ή το IntelliJ IDEA.
Το Pull Request (ή Merge Request) είναι υποχρεωτικό κατά τη συγχώνευση του feature κλαδιού στο κύριο κλαδί του έργου. Το PR περνά από code review συναδέλφων και αυτόματους ελέγχους CI. Αυτό είναι το πρότυπο της σύγχρονης ανάπτυξης. Το άμεσο push στο main κλαδί απαγορεύεται στα περισσότερα έργα.
Το Squash merge συνδυάζει όλα τα commits του feature κλαδιού σε ένα πριν από τη συγχώνευση. Αυτό δίνει μια καθαρή ιστορία του κύριου κλαδιού χωρίς ενδιάμεσα working commits. Χρησιμοποιήστε squash merge όταν το feature κλαδί περιέχει πολλά βοηθητικά commits (wip, fixes) και δεν χρειάζεται να διατηρηθούν όλα τα ενδιάμεσα βήματα στην ιστορία.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης