Merge και rebase

8 λεπτά

Πίνακας περιεχομένων


1 — Συγκέντρωση δύο κλάδων: η ανάγκη

Εργαστήκατε σε έναν κλάδο feature, ο κώδικας είναι έτοιμος. Τώρα πρέπει να τον επανενσωματώσετε στο main. Το Git προσφέρει δύο μηχανισμούς γι' αυτό: τη συγχώνευση (merge) και την αναβάθμιση βάσης (rebase).

Και τα δύο επιτυγχάνουν τον ίδιο στόχο — να ενώσουν τη δουλειά — αλλά με διαφορετική μορφή ιστορικού. Αυτό είναι όλο το διακύβευμα αυτού του μαθήματος.

ΜηχανισμόςΙδέα σε μία πρόταση
MergeΔημιουργούμε ένα commit που ενώνει τους δύο κλάδους, κρατώντας την ιστορία τους ως έχει.
RebaseΞαναπαίζουμε τα commits ενός κλάδου πάνω από έναν άλλο, σαν να είχαμε ξεκινήσει αργότερα.

Πριν από κάθε ενσωμάτωση, βεβαιωνόμαστε ότι έχουμε την τελευταία έκδοση:

bash
git switch main
git pull origin main

↑ Επιστροφή στην αρχή


2 — Η συγχώνευση (merge)

Η εντολή git merge ενώνει έναν κλάδο σε έναν άλλο. Υπάρχουν δύο περιπτώσεις.

Περίπτωση 1 — Γρήγορη συγχώνευση (fast-forward): αν το main δεν έχει κινηθεί από τη δημιουργία του κλάδου, το Git απλώς προωθεί τον δείκτη. Δεν δημιουργείται commit συγχώνευσης.

Περίπτωση 2 — Συγχώνευση τριών κλάδων (three-way merge): αν το main έχει λάβει νέα commits στο μεταξύ, το Git δημιουργεί ένα commit συγχώνευσης που έχει δύο γονείς.

bash
# Τοποθέτηση στον κλάδο-στόχο, έπειτα συγχώνευση
git switch main
git merge feature/panier

# Επιβολή commit συγχώνευσης ακόμα κι αν είναι δυνατό το fast-forward
git merge --no-ff feature/panier
ΕπιλογήΑποτέλεσμα
git merge featureΣυγχώνευση (fast-forward αν είναι δυνατό)
git merge --no-ff featureΠάντα δημιουργία commit συγχώνευσης (ίχνος του κλάδου)
git merge --abortΑκύρωση συγχώνευσης σε εξέλιξη λόγω σύγκρουσης

Το merge διατηρεί την πραγματική ιστορία: βλέπουμε πότε και πώς ενώθηκαν οι κλάδοι. Είναι ειλικρινές, αλλά το ιστορικό μπορεί να γίνει πυκνό με πολλά commits συγχώνευσης.

🔧 Μίνι-άσκηση — Θέλετε να συγχωνεύσετε το feature/panier στο main επιβάλλοντας τη δημιουργία ενός commit συγχώνευσης, ακόμα κι αν ένα fast-forward θα ήταν δυνατό. Γράψτε την εντολή.

✅ Δείτε μια λύση

git merge --no-ff feature/panier — το --no-ff κρατά ρητό ίχνος του συγχωνευμένου κλάδου.

↑ Επιστροφή στην αρχή


3 — Η αναβάθμιση βάσης (rebase)

Το git rebase μετακινεί τα commits του κλάδου σας για να τα ξαναπαίξει πάνω στην κορυφή ενός άλλου κλάδου. Αποτέλεσμα: ένα γραμμικό ιστορικό, σαν να είχατε ξεκινήσει τη δουλειά σας μετά τα τελευταία commits του main.

Πριν από το rebase:

Μετά το git rebase main (τα commits B και C ξαναπαίζονται μετά το D):

bash
# Στον κλάδο feature, επανάληψη πάνω από το main
git switch feature/panier
git rebase main

# Έπειτα καθαρή συγχώνευση fast-forward στο main
git switch main
git merge feature/panier
Πλεονέκτημα του rebaseΠροφύλαξη
Ιστορικό γραμμικό και ευανάγνωστοΞαναγράφει τα commits (νέα SHA)
Χωρίς παράσιτα commits συγχώνευσηςΠοτέ μην κάνετε rebase σε κλάδο ήδη σταλμένο και κοινόχρηστο
Ιδανικό πριν από ένα pull requestΣυγκρούσεις προς επίλυση commit προς commit

⚠️ Χρυσός κανόνας του rebase: μην κάνετε ποτέ rebase σε commits ήδη δημοσιευμένα και χρησιμοποιούμενα από άλλους. Ξαναγράφετε την ιστορία, κάτι που θα έσπαγε τα αποθετήριά τους. Το rebase είναι για την τοπική, μη κοινόχρηστη εργασία σας.

🔧 Μίνι-άσκηση — Βρίσκεστε στον κλάδο feature/panier. Γράψτε την εντολή για να ξαναπαίξετε τα commits σας πάνω στην κορυφή του main (γραμμικό ιστορικό).

✅ Δείτε μια λύση

git rebase main (όντας στον feature/panier).

↑ Επιστροφή στην αρχή


4 — Επίλυση συγκρούσεων

Μια σύγκρουση εμφανίζεται όταν το Git δεν μπορεί να αποφασίσει αυτόματα: δύο κλάδοι τροποποίησαν την ίδια γραμμή του ίδιου αρχείου. Το Git σταματά και σας ζητά να αποφασίσετε.

Το Git εισάγει δείκτες σύγκρουσης στο αρχείο:

text
<<<<<<< HEAD
prix = 10   # version de main
=======
prix = 12   # version de feature
>>>>>>> feature/panier

Η επίλυση βήμα προς βήμα:

  1. Ανοίξτε το αρχείο και επιλέξτε (ή συνδυάστε) τη σωστή έκδοση.
  2. Διαγράψτε τους δείκτες <<<<<<<, =======, >>>>>>>.
  3. Μαρκάρετε το αρχείο ως επιλυμένο με git add.
  4. Ολοκληρώστε τη λειτουργία.
bash
# Προβολή αρχείων σε σύγκρουση
git status

# Μετά από χειροκίνητη επεξεργασία
git add fichier-en-conflit.py

# Ολοκλήρωση ενός merge
git commit

# Ολοκλήρωση ενός rebase
git rebase --continue

# Σε περίπτωση πανικού: ακύρωση όλων
git merge --abort      # ή: git rebase --abort
Εργαλείο βοήθειαςΧρήση
git statusΛίστα αρχείων σε σύγκρουση
git diffΠροβολή των συγκρουόμενων διαφορών
git mergetoolΕκκίνηση γραφικού εργαλείου επίλυσης
VS CodeΚουμπιά Accept Current / Incoming / Both

Μια σύγκρουση δεν είναι σφάλμα: είναι το Git που, ειλικρινά, σας λέει «δεν ξέρω ποιο να κρατήσω, είναι δική σας απόφαση». Ηρεμία και ανάγνωση των δεικτών αρκούν στο 99 % των περιπτώσεων.

🔧 Μίνι-άσκηση — Επεξεργαστήκατε το αρχείο app.py για να επιλύσετε μια σύγκρουση κατά τη διάρκεια ενός rebase. Ποιες δύο εντολές ολοκληρώνουν τη λειτουργία;

✅ Δείτε μια λύση
bash
git add app.py
git rebase --continue

(Για ένα merge, θα ήταν git add app.py και έπειτα git commit.)

↑ Επιστροφή στην αρχή


5 — Merge ή rebase: τι να επιλέξετε;

Και τα δύο ενώνουν τη δουλειά, αλλά παράγουν διαφορετικό ιστορικό. Η επιλογή είναι συχνά μια σύμβαση ομάδας.

ΠτυχήMergeRebase
ΙστορικόΠιστό, διακλαδισμένοΓραμμικό, καθαρό
Commit συγχώνευσηςΝαι (αν όχι fast-forward)Όχι
Ξαναγράφει την ιστορίαΌχιΝαι (νέα SHA)
Ασφαλές σε κοινόχρηστο κλάδο✅ Ναι❌ Όχι
Αναγνωσιμότητα του logΠιο πυκνήΠιο καθαρή

Η πιο συνηθισμένη συνιστώμενη πρακτική:

  • Κάντε rebase του τοπικού σας κλάδου πάνω στο main πριν ανοίξετε ένα pull request → καθαρό ιστορικό.
  • Κάντε merge του pull request στο main → σαφές ίχνος της ενσωμάτωσης.
bash
# 1. Καθαρισμός του τοπικού κλάδου πριν από το PR
git switch feature/x
git rebase main

# 2. Μόλις εγκριθεί το PR, το GitHub κάνει το merge

Μνημονικός κανόνας: «Rebase ιδιωτικά, merge δημόσια.» Κάνουμε rebase ό,τι είναι δικό μας, merge ό,τι είναι κοινόχρηστο.

↑ Επιστροφή στην αρχή


6 — Κουίζ — Merge και rebase

Question 1 : Τι κάνει το git merge feature από το main όταν το main έχει επίσης νέα commits;

a) Διαγράφει τον κλάδο feature

b) Δημιουργεί ένα commit συγχώνευσης με δύο γονείς

c) Σβήνει το ιστορικό

d) Αρνείται πάντα να συγχωνεύσει

💡 Δείτε τη λύση

Απάντηση: b) — Είναι συγχώνευση τριών κλάδων: το Git δημιουργεί ένα commit συγχώνευσης που ενώνει τις δύο ιστορίες.


Question 2 : Ποιο είναι το κύριο αποτέλεσμα ενός git rebase main;

a) Να ξαναπαίξει τα commits του κλάδου πάνω από το main για γραμμικό ιστορικό

b) Να κλωνοποιήσει το αποθετήριο

c) Να διαγράψει το main

d) Να δημιουργήσει απομακρυσμένο αντίγραφο ασφαλείας

💡 Δείτε τη λύση

Απάντηση: a) — Το rebase μετακινεί και ξαναπαίζει τα commits σας στην κορυφή του main, παράγοντας γραμμική ιστορία.


Question 3 : Γιατί δεν πρέπει να κάνουμε rebase σε κλάδο ήδη σταλμένο και κοινόχρηστο;

a) Επειδή το απαγορεύει το GitHub

b) Επειδή ξαναγράφει τα commits και σπάει τα αποθετήρια των άλλων

c) Επειδή το rebase είναι πιο αργό

d) Επειδή διαγράφει το main

💡 Δείτε τη λύση

Απάντηση: b) — Το rebase δημιουργεί νέα SHA. Αν άλλοι έχουν ήδη αυτά τα commits, το ιστορικό τους γίνεται ασυνεπές.


Question 4 : Τι αντιπροσωπεύουν οι δείκτες <<<<<<<, =======, >>>>>>>;

a) Σχόλια κώδικα

b) Συντακτικό σφάλμα Python

c) Τις ζώνες μιας σύγκρουσης προς χειροκίνητη επίλυση

d) Το τέλος ενός αρχείου

💡 Δείτε τη λύση

Απάντηση: c) — Είναι οι δείκτες σύγκρουσης: πάνω η τρέχουσα έκδοση (HEAD), κάτω η εισερχόμενη έκδοση. Επιλέγουμε και τους διαγράφουμε.


Question 5 : Πώς ακυρώνουμε καθαρά μια συγχώνευση μπλοκαρισμένη από συγκρούσεις;

a) git delete

b) git merge --abort

c) git reset --cloud

d) Διαγραφή του φακέλου .git

💡 Δείτε τη λύση

Απάντηση: b) — Το git merge --abortgit rebase --abort) επαναφέρει το αποθετήριο στην κατάσταση πριν από τη λειτουργία.

↑ Επιστροφή στην αρχή


7 — Πρακτική — Επίλυση σύγκρουσης συγχώνευσης

Οδηγία

Δύο κλάδοι τροποποιούν την ίδια γραμμή ενός αρχείου config.txt. Αναπαραγάγετε τη σύγκρουση, έπειτα επιλύστε την κρατώντας και τις δύο πληροφορίες συνδυασμένες.

  1. Στο main, το αρχείο περιέχει port = 8080.
  2. Ένας κλάδος feature/ssl αλλάζει αυτή τη γραμμή σε port = 443.
  3. Στο μεταξύ, το main αλλάζει την ίδια γραμμή σε port = 9090.
  4. Συγχωνεύστε το feature/ssl στο main, επιλύστε τη σύγκρουση κρατώντας port = 443 (HTTPS), έπειτα ολοκληρώστε.

Διόρθωση

bash
# Προετοιμασία: δημιουργία της σύγκρουσης
echo "port = 8080" > config.txt
git add config.txt
git commit -m "Config initiale"

git switch -c feature/ssl
echo "port = 443" > config.txt
git commit -am "Passage en HTTPS (port 443)"

git switch main
echo "port = 9090" > config.txt
git commit -am "Changement de port en 9090"

# Απόπειρα συγχώνευσης → σύγκρουση
git merge feature/ssl

Το Git εμφανίζει τότε:

text
Auto-merging config.txt
CONFLICT (content): Merge conflict in config.txt
Automatic merge failed; fix conflicts and then commit the result.

Το αρχείο config.txt περιέχει:

text
<<<<<<< HEAD
port = 9090
=======
port = 443
>>>>>>> feature/ssl

Επεξεργαζόμαστε ώστε να κρατήσουμε μόνο τη σωστή τιμή:

bash
echo "port = 443" > config.txt   # απόφαση υπέρ του HTTPS

git add config.txt
git commit -m "Fusion feature/ssl : conservation du port 443"

Αναμενόμενο αποτέλεσμα:

ΕπαλήθευσηΕντολήΈξοδος
Σύγκρουση επιλυμένηgit status« nothing to commit, working tree clean »
Τελικό περιεχόμενοcat config.txtport = 443
Commit συγχώνευσηςgit log --oneline -1« Fusion feature/ssl : conservation du port 443 »

Συμβουλή: αν κάνετε λάθος στη μέση μιας σύγκρουσης, το git merge --abort σας επιστρέφει το αποθετήριο ανέπαφο. Κανένας κίνδυνος να πειραματιστείτε.

↑ Επιστροφή στην αρχή


8 — Σύνοψη

Σημεία που πρέπει να θυμάστε

  1. Merge και rebase ενώνουν δύο κλάδους, αλλά παράγουν διαφορετικό ιστορικό.
  2. Το Merge διατηρεί την πραγματική ιστορία· δημιουργεί commit συγχώνευσης με δύο γονείς (εκτός fast-forward).
  3. Το Rebase ξαναπαίζει τα commits για ιστορικό γραμμικό και καθαρό.
  4. Χρυσός κανόνας: rebase ιδιωτικά, merge δημόσια — ποτέ rebase σε κοινόχρηστο κώδικα.
  5. Μια σύγκρουση εμφανίζεται όταν η ίδια γραμμή τροποποιείται και από τις δύο πλευρές: επεξεργαζόμαστε, κάνουμε add, ολοκληρώνουμε.
  6. Καλή πρακτική: rebase του κλάδου πριν από το PR, έπειτα merge του PR στο main.

Η συνέχεια

Ξέρετε να ενσωματώνετε τεχνικά τον κώδικα. Το μάθημα 03 — Pull requests δείχνει πώς να ζητήσετε αναθεώρηση αυτής της εργασίας πριν την ενσωματώσετε, στον πυρήνα της συνεργασίας στο GitHub.

↑ Επιστροφή στην αρχή


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

Μάθημα δημιουργημένο από τον Dr. Haythem REHOUMA — Ανάπτυξη και ανάπτυξη λύσεων δεδομένων