Αρχική
» ΒΑΣΙΚΕΣ ΓΝΩΣΕΙΣ
»
Πώς να διορθώσετε το σφάλμα "Git Push Rejected: Non-Fast-Forward" χωρίς να χάσετε αλλαγές
Πώς να διορθώσετε το σφάλμα "Git Push Rejected: Non-Fast-Forward" χωρίς να χάσετε αλλαγές
Μια απόρριψη χωρίς γρήγορη προώθηση σημαίνει ότι το Git προστατεύει το ιστορικό και όχι ότι διαγράφει την τοπική σας εργασία. Συνήθως σημαίνει ότι ο απομακρυσμένος κλάδος μετακινήθηκε προς τα εμπρός μετά τον τελευταίο συγχρονισμό του τοπικού σας κλάδου, επομένως η ενημέρωση του απομακρυσμένου κλάδου με τον τρέχοντα κλάδο σας θα απορρίψει τις υποβολές που υπάρχουν ήδη εκεί. Η τρέχουσα τεκμηρίωση του GitHub περιγράφει την ίδια κατάσταση: ανακτήστε πρώτα τις αλλαγές upstream, ενσωματώστε τες τοπικά και, στη συνέχεια, προωθήστε ξανά.
Η ασφαλέστερη γενική ροή εργασίας είναι: προστασία οποιασδήποτε μη δεσμευμένης εργασίας, ανάκτηση του απομακρυσμένου κλάδου χωρίς τροποποίηση του τρέχοντος κλάδου σας, έλεγχος του τρόπου με τον οποίο τα ιστορικά αποκλίνουν, επιλογή συγχώνευσης ή αλλαγής βάσης, επίλυση διενέξεων εάν είναι απαραίτητο και επανάληψη της διαδικασίας. Μην ξεκινήσετε με git push --forceή git reset --hardαπλώς για να εξαφανίσετε το σφάλμα.
Τι σημαίνει στην πραγματικότητα η φράση «μη γρήγορη προώθηση»;
Ας υποθέσουμε ότι το τοπικό σας mainυποκατάστημα περιέχει την εντολή commit L, ενώ το απομακρυσμένο υποκατάστημα origin/mainέχει προχωρήσει σε διαφορετική εντολή R. Εάν καμία από τις δύο ενέργειες δεν είναι πρόγονος της άλλης, τα ιστορικά έχουν αποκλίνει. Μια κανονική ώθηση δεν μπορεί απλώς να μετακινήσει τον δείκτη του απομακρυσμένου υποκαταστήματος στο Lχωρίς να τον Rεξαφανίσει από το ορατό ιστορικό αυτού του υποκαταστήματος.
Μια ενημέρωση γρήγορης προώθησης είναι διαφορετική: η νέα συμβουλή του κλάδου είναι απόγονος της παλιάς, επομένως η μετακίνηση του κλάδου προς τα εμπρός διατηρεί όλα όσα είναι ήδη προσβάσιμα από αυτήν. Το επίσημο git pushεγχειρίδιο ορίζει αυτόν τον κανόνα καταγωγής και προειδοποιεί ότι --forceαπενεργοποιεί την κανονική προστασία και μπορεί να προκαλέσει την απώλεια απομακρυσμένων υποβολών.
Μια απόρριψη χωρίς γρήγορη προώθηση σημαίνει ότι το Git αρνείται να αντικαταστήσει το απομακρυσμένο ιστορικό που δεν περιέχει ακόμη το τοπικό σας υποκατάστημα.
Πριν κάνετε οτιδήποτε: καταγράφεται με ασφάλεια η τοπική σας εργασία;
Τρέξιμο:
git status
Εάν το δέντρο εργασίας είναι καθαρό, οι τρέχουσες αλλαγές σας αντιπροσωπεύονται ήδη από υποβολές και μπορείτε να δημιουργήσετε μια επιπλέον αναφορά ασφαλείας πριν από την ενσωμάτωση του απομακρυσμένου συστήματος:
git branch backup-before-sync
Αυτός ο κλάδος δείχνει στην τρέχουσα υποβολή, επομένως έχετε ένα εύκολο όνομα για την κατάσταση πριν από την ενσωμάτωση.
Εάν έχετε τροποποιήσει ή καταργήσει την παρακολούθηση αρχείων που δεν έχουν δεσμευτεί, επιλέξτε μία από αυτές τις προσεγγίσεις πριν από την εξαγωγή ή την αλλαγή βάσης:
Υποβάλετέ τα εάν η εργασία είναι λογικά έτοιμη για υποβολή.
Αποθηκεύστε τα αν η εργασία είναι ημιτελής: git stash push -u -m "before non-fast-forward fix".
Η -uεπιλογή περιλαμβάνει μη παρακολουθούμενα αρχεία. Η επίσημη τεκμηρίωση του git-stash εξηγεί ότι ένα stash καταγράφει τον κατάλογο εργασίας και την κατάσταση του ευρετηρίου και επαναφέρει ένα καθαρό δέντρο εργασίας. Τα αγνοημένα αρχεία δεν περιλαμβάνονται από το -u; -aθα περιλαμβάνει επίσης τα αγνοημένα αρχεία, αλλά αυτό σπάνια είναι απαραίτητο για αυτό το πρόβλημα.
Σημαντικό: εάν git statusεμφανίζει αρχεία που δεν μπορείτε να χάσετε, μην εκτελέσετε την εντολή git reset --hard. Αυτή η εντολή μπορεί να απορρίψει τις μη δεσμευμένες αλλαγές στο δέντρο εργασίας.
Βήμα 1: Πρέπει να το χρησιμοποιήσετε git pullαμέσως;
Μπορείτε, αλλά η επιλογή fetch first είναι πιο εύκολη για να συλλογιστείτε . Τα έγγραφα GitHub git fetchκατεβάζουν απομακρυσμένη εργασία και ενημερώνουν τους κλάδους απομακρυσμένης παρακολούθησης χωρίς να συγχωνεύουν αυτές τις αλλαγές στον τρέχοντα κλάδο σας. Αυτό το καθιστά ένα χρήσιμο διαγνωστικό βήμα, επειδή μπορείτε να ελέγξετε την κατάσταση πριν αλλάξετε το τοπικό ιστορικό.
Μετά την ανάκτηση, ο κλάδος remote-tracking origin/mainαντιπροσωπεύει την απομακρυσμένη κατάσταση που μόλις ανακτήσατε. Η εντολή log σάς επιτρέπει να βλέπετε τις υποβολές που είναι προσβάσιμες μόνο από την τοπική σας πλευρά και μόνο από την απομακρυσμένη πλευρά.
Εάν το τοπικό σας υποκατάστημα δεν έχει μοναδικές υποβολές και απλώς έχει μείνει πίσω, μπορείτε συχνά να το προωθήσετε γρήγορα:
git merge --ff-only origin/main
Τότε δεν υπάρχει τίποτα που να συμβιβάζει· το κλαδί σας απλώς κινείται προς τα εμπρός.
Βήμα 2: Συγχώνευση ή αναδιάταξη—ποιο πρέπει να επιλέξετε;
Και τα δύο μπορούν να διατηρήσουν τις αλλαγές σας. Η διαφορά έγκειται στο σχήμα του ιστορικού που προκύπτει.
Κατάσταση
Συνήθως επιλέγω
Γιατί
Κοινόχρηστο υποκατάστημα, όπως mainεκεί όπου οι τοπικές σας υποβολές μπορεί να είναι ήδη γνωστές σε άλλους
Συγχώνευση
Διατηρεί τις υπάρχουσες ταυτότητες υποβολών και δεν ξαναγράφει τις τοπικές σας υποβολές.
Οι υποβολές σας είναι τοπικές/ιδιωτικές και θέλετε ένα γραμμικό ιστορικό
Αναπροσαρμογή βάσης
Επαναλαμβάνει τις τοπικές υποβολές σας πάνω από τον ενημερωμένο απομακρυσμένο κλάδο.
Δεν είστε σίγουροι και θέλετε την λιγότερη δυνατή επανεγγραφή ιστορικού
Συγχώνευση
Είναι πιο εύκολο να εξηγηθεί και ασφαλέστερο για την κοινή ιστορία.
Συγχώνευση διαδρομής
git fetch origin
git merge origin/main
Εάν δεν υπάρχουν διενέξεις, το Git ολοκληρώνει την ενσωμάτωση. Εάν τα κλαδιά αποκλίνουν πραγματικά, το αποτέλεσμα μπορεί να περιλαμβάνει μια υποβολή συγχώνευσης.
Επαναφορά διαδρομής
git fetch origin
git rebase origin/main
Η επαναφορά δεδομένων (rebase) λαμβάνει τις υποβολές (commits) που είναι μοναδικές για τον τρέχοντα κλάδο σας και τις εφαρμόζει ξανά πάνω από το origin/main. Η τεκμηρίωση της επαναφοράς δεδομένων (rebase) του Git το περιγράφει ως μεταφύτευση μιας σειράς υποβολών (commits) σε διαφορετικό σημείο εκκίνησης. Επειδή αυτές οι υποβολές (commits) λαμβάνουν νέα αναγνωριστικά υποβολών (commit), η επαναφορά δεδομένων (rebase) χρησιμοποιείται καλύτερα για τοπική εργασία που δεν έχει ήδη κοινοποιηθεί ως δημόσιο ιστορικό.
Αν προτιμάτε μια συντόμευση, git pull --rebase origin mainεκτελεί μια ανάκτηση ακολουθούμενη από μια αλλαγή βάσης, ενώ git pull --no-rebase origin mainεπιλέγει ρητά τη συμπεριφορά συγχώνευσης. Για μια κατάσταση ανάκτησης, οι εντολές separate fetchκαι merge/ rebaseείναι συχνά πιο σαφείς επειδή μπορείτε να ελέγξετε πρώτα την απομακρυσμένη κατάσταση.
Αφού ανακτηθούν οι απομακρυσμένες αλλαγές, ενσωματώστε τες σκόπιμα—μέσω συγχώνευσης ή αλλαγής βάσης—αντί να τις αντικαταστήσετε.
Βήμα 3: Τι πρέπει να κάνετε εάν το Git αναφέρει μια διένεξη;
Μια σύγκρουση δεν σημαίνει ότι οι αλλαγές σας έχουν εξαφανιστεί. Σημαίνει ότι το Git δεν μπορεί να αποφασίσει αυτόματα πώς να συνδυάσει αλλαγές στο ίδιο περιεχόμενο.
Αρχικά, ελέγξτε την κατάσταση:
git status
Ανοίξτε κάθε αρχείο σε διένεξη, αποφασίστε ποιο θα πρέπει να είναι το τελικό περιεχόμενο, αφαιρέστε τους δείκτες διένεξης και, στη συνέχεια, τοποθετήστε το επιλυμένο αρχείο σε στάδιο προετοιμασίας:
git add path/to/file
Εάν επιλέξετε συγχώνευση, ολοκληρώστε τη συγχώνευση αφού ολοκληρωθούν όλες οι διενέξεις:
git commit
Αν επιλέξετε rebase, συνεχίστε να αναπαράγετε τις υποβολές σας:
git rebase --continue
Εάν η επαναφορά βάσης δεν πάει καλά και θέλετε να επαναφέρετε τον κλάδο στην κατάσταση πριν από την επαναφορά βάσης, χρησιμοποιήστε:
git rebase --abort
Το τρέχον εγχειρίδιο ανανέωσης βάσης Git καταγράφει ειδικά --continueαυτόν --abortτον σκοπό. Μην το χρησιμοποιείτε git rebase --skipαπλώς για να εξαλείψετε μια διένεξη, εκτός εάν σκοπεύετε πραγματικά να παραλείψετε την επανάληψη της υποβολής.
Επιλύστε πρώτα το περιεχόμενο, τοποθετήστε το διορθωμένο αρχείο σε στάδιο και, στη συνέχεια, ολοκληρώστε τη συγχώνευση ή συνεχίστε την επαναφορά βάσης.
Βήμα 4: Πότε είναι ασφαλές να ξανασπρώξω;
Πριν από την ώθηση, επαληθεύστε το δέντρο εργασίας και το πρόσφατο ιστορικό:
git status
git log --oneline --graph --decorate -n 12
Στη συνέχεια, πατήστε κανονικά:
git push origin main
Εάν συγχωνεύσατε τον απομακρυσμένο κλάδο ή επαναφέρατε μόνο υποβολές που δεν είχαν ωθηθεί ποτέ πριν, μια κανονική ώθηση θα πρέπει συνήθως να είναι η σωστή λειτουργία, επειδή η νέα απομακρυσμένη συμβουλή θα είναι πρόγονος της τοπικής σας συμβουλής.
Μόλις ο κλάδος σας περιέχει τόσο την απομακρυσμένη εργασία όσο και τις τοπικές αλλαγές που επιθυμείτε, μια κανονική ώθηση μπορεί να προωθήσει τον απομακρυσμένο με ασφάλεια.
Πότε πρέπει να χρησιμοποιήσετε --force-with-lease;
Χρησιμοποιήστε το μόνο όταν έχετε ξαναγράψει σκόπιμα ιστορικό που υπάρχει ήδη στο απομακρυσμένο σύστημα — για παράδειγμα, έχετε αλλάξει τη βάση ενός κλάδου χαρακτηριστικών που είχατε ωθήσει προηγουμένως και τώρα πρέπει να αντικαταστήσετε την παλιά ακολουθία υποβολής αυτού του κλάδου.
git push --force-with-lease origin feature-branch
Η επίσημη git pushτεκμηρίωση εξηγεί γιατί αυτό είναι ασφαλέστερο από το απλό --force: η μίσθωση ελέγχει ότι η απομακρυσμένη αναφορά εξακολουθεί να έχει την τιμή που περιμένετε. Εάν κάποιο άλλο άτομο προώθησε νέα εργασία μετά την κατάσταση στην οποία βασίσατε την επανεγγραφή σας, η αναγκαστική ενημέρωση απορρίπτεται αντί να αντικαθιστά τυφλά τις υποβολές του.
Αυτή η προστασία δεν αποτελεί λόγο για να χρησιμοποιείτε συστηματικά την αναγκαστική ώθηση. Αποφύγετε την αναγκαστική ώθηση σε κοινόχρηστους κλάδους, mainεκτός εάν η ομάδα σας επιτρέπει ρητά την επανεγγραφή του ιστορικού. Η προστασία κλάδου από την πλευρά του διακομιστή μπορεί επίσης να απορρίψει την αναγκαστική ώθηση ανεξάρτητα από την τοπική σας εντολή.
Μην το αντικαταστήσετε με αυτό:
git push --force origin main
Η απλή εντολή --forceαπενεργοποιεί τον κανονικό έλεγχο ασφαλείας που δεν είναι γρήγορος-προωθητικός και μπορεί να αντικαταστήσει απομακρυσμένες υποβολές. Η τεκμηρίωση του Git προειδοποιεί ότι μπορεί να προκαλέσει την απώλεια υποβολών από το απομακρυσμένο αποθετήριο.
Τι γίνεται αν έχετε ήδη εκτελέσει λάθος εντολή;
Το Git συχνά έχει ακόμα αρκετό τοπικό ιστορικό για να ανακτήσει μια προηγούμενη θέση κλάδου. Εκτέλεση:
git reflog
Τα reflogs καταγράφουν πρόσφατες ενημερώσεις σε τοπικές αναφορές, συμπεριλαμβανομένων προηγούμενων τιμών HEAD. Εάν βρείτε την υποβολή που αντιπροσώπευε τον κλάδο σας πριν από την εσφαλμένη επαναφορά ή αλλαγή βάσης, δημιουργήστε έναν κλάδο διάσωσης αντί να τον μετακινήσετε αμέσως mainξανά:
git branch rescue-work <commit-id>
Τώρα, ελέγξτε rescue-workκαι ανακτήστε τις υποβολές που χρειάζεστε. Η επίσημη τεκμηρίωση του git-reflog περιγράφει τα reflogs ως εγγραφές όπου οι συμβουλές των κλάδων και άλλες αναφορές είχαν προηγουμένως υποδείξει.
Γιατί git pullμερικές φορές δημιουργείται μια υποβολή συγχώνευσης;
git pullπρώτα ανακτά και στη συνέχεια ενσωματώνει τον επιλεγμένο κλάδο upstream. Ανάλογα με τις επιλογές και τη διαμόρφωση του αποθετηρίου, αυτή η ενσωμάτωση μπορεί να είναι συγχώνευση ή αλλαγή βάσης. Εάν θέλετε προβλέψιμη συμπεριφορά κατά τη διόρθωση μιας απόρριψης που δεν βασίζεται σε γρήγορη προώθηση, δηλώστε ρητά την πρόθεσή σας:
# Preserve branch history with a merge
git pull --no-rebase origin main
# Replay private local commits on top
git pull --rebase origin main
Για μεγαλύτερη ορατότητα, χρησιμοποιήστε git fetch originπρώτα και εκτελέστε git merge origin/mainή git rebase origin/mainξεχωριστά.
Τι γίνεται αν η απομακρυσμένη υποβολή είναι ανεπιθύμητη;
Μην υποθέτετε ότι η ένδειξη «ανεπιθύμητο» σημαίνει ότι είναι ασφαλές να διαγραφεί. Πρώτα ελέγξτε το:
Εάν η υποβολή ανήκει σε άλλον προγραμματιστή, bot, πρόγραμμα ενημέρωσης εξαρτήσεων ή σε κάποια αλλαγή που έγινε στη διεπαφή ιστού, ενσωματώστε την ή επαναφέρετέ την μέσω του κανονικού ιστορικού. Εάν η ομάδα σας έχει συμφωνήσει σκόπιμα να αντικαταστήσει το απομακρυσμένο ιστορικό, τότε μπορεί να είναι κατάλληλη μια προστατευμένη ώθηση με δύναμη (guarded force push)—αλλά αυτή είναι μια απόφαση ιστορικού αποθετηρίου και όχι η τυπική λύση για ένα σφάλμα μη γρήγορης προώθησης.
Μια λίστα ελέγχου ασφαλών αποφάσεων για ασφαλείς αποφάσεις.
Μη δεσμευμένα αρχεία; Υποβάλετέ τα ή αποθηκεύστε τα πριν από την ενσωμάτωση.
Χρειάζεστε ένα σημείο ασφαλείας; Δημιουργήστε ένα αντίγραφο ασφαλείας του κλάδου στην τρέχουσα υποβολή.
Άλλαξε το τηλεχειριστήριο; Εκτελέστε το git fetch originπριν αποφασίσετε τι θα κάνετε.
Κοινόχρηστο ιστορικό; Προτιμήστε τη συγχώνευση αν θέλετε να αποφύγετε την επανεγγραφή υποβολών.
Ιδιωτικές τοπικές υποβολές; Η επαναφορά βάσης μπορεί να διατηρήσει το ιστορικό γραμμικό.
Σύγκρουση; Επιλύστε το αρχείο, τοποθετήστε το σε στάδιο και, στη συνέχεια, ολοκληρώστε τη συγχώνευση ή συνεχίστε την επαναφορά βάσης.
Ολοκληρώθηκε η κανονική ενσωμάτωση; Χρησιμοποιήστε ένα κανονικό git push.
Ήδη δημοσιευμένο ιστορικό με σκόπιμη αναδιαμόρφωση; Σκεφτείτε το --force-with-lease, όχι απλό --force.
Συμπέρασμα
Το μήνυμα μη γρήγορης προώθησης είναι ένα φράγμα ασφαλείας που σας ενημερώνει ότι ο απομακρυσμένος κλάδος περιέχει ιστορικό που η προτεινόμενη ώθηση δεν διατηρεί. Η λύση δεν είναι να υπερνικήσετε αυτό το φράγμα. Προστατέψτε την τοπική σας εργασία, ανακτήστε τον απομακρυσμένο κλάδο, ελέγξτε την απόκλιση, ενσωματώστε την με συγχώνευση ή αναπροσαρμογή βάσης, επιλύστε σκόπιμα τις διενέξεις και ωθήστε ξανά.
Αν θυμάστε έναν κανόνα, ορίστε τον ως εξής: κάντε λήψη και κατανόηση πριν επιβάλετε το . Αυτό διατηρεί τόσο τις αλλαγές σας όσο και την εργασία που έχει ήδη γίνει στο τηλεχειριστήριο—και μετατρέπει μια τρομακτική απόρριψη ώθησης σε ένα συνηθισμένο πρόβλημα συγχρονισμού Git.