Ας πούμε ότι βρίσκομαι σε ένα αποθετήριο Git. Διαγράφω ένα αρχείο και δεσμεύω αυτή την αλλαγή. Συνεχίζω να εργάζομαι και κάνω μερικές ακόμα δεσμεύσεις. Στη συνέχεια, ανακαλύπτω ότι πρέπει να επαναφέρω αυτό το αρχείο.
Ξέρω ότι μπορώ να κάνω checkout ένα αρχείο χρησιμοποιώντας git checkout HEAD^ foo.bar
, αλλά δεν ξέρω πραγματικά πότε διαγράφηκε αυτό το αρχείο.
Ελπίζω ότι δεν χρειάζεται να περιηγηθώ χειροκίνητα στα αρχεία καταγραφής μου, να ελέγξω ολόκληρο το έργο για ένα δεδομένο SHA και στη συνέχεια να αντιγράψω χειροκίνητα αυτό το αρχείο στο αρχικό μου checkout του έργου.
Εύρεση της τελευταίας δέσμευσης που επηρέασε τη δεδομένη διαδρομή. Καθώς το αρχείο δεν βρίσκεται στη δέσμευση HEAD, αυτή η δέσμευση πρέπει να το έχει διαγράψει.
git rev-list -n 1 HEAD -- <file_path>
Στη συνέχεια, ελέγξτε την έκδοση στην προηγούμενη δέσμευση, χρησιμοποιώντας το σύμβολο caret (^
):
git checkout <deleting_commit>^ -- <file_path>
Ή με μία εντολή, αν το $file
είναι το εν λόγω αρχείο.
git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"
Αν χρησιμοποιείτε zsh και έχετε ενεργοποιημένη την επιλογή EXTENDED_GLOB, το σύμβολο caret δεν θα λειτουργήσει. Μπορείτε να χρησιμοποιήσετε το ~1
αντί αυτού.
git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"
git log --diff-filter=D --summary
για να λάβετε όλες τις δεσμεύσεις που έχουν διαγράψει αρχεία και τα αρχεία που έχουν διαγραφεί,git checkout $commit~1 path/to/file.ext
για να επαναφέρετε το διαγραμμένο αρχείο.Όπου $commit
είναι η τιμή του commit που βρήκατε στο βήμα 1, π.χ. e4cf499627
.
Αν είστε τρελοί, χρησιμοποιήστε το git-bisect
. Ακούστε τι πρέπει να κάνετε:
git bisect start
git bisect bad
git bisect good <some commit where you know the file existed>
Τώρα ήρθε η ώρα να εκτελέσετε την αυτοματοποιημένη δοκιμή. Η εντολή του κελύφους '[ -e foo.bar ]'
θα επιστρέψει 0 αν το foo.bar
υπάρχει, και 1 διαφορετικά. Η εντολή "run" του git-bisect
θα χρησιμοποιήσει δυαδική αναζήτηση για να βρει αυτόματα την πρώτη δέσμευση όπου η δοκιμή αποτυγχάνει. Ξεκινάει από τη μέση του εύρους που δίνεται (από το καλό στο κακό) και το κόβει στη μέση με βάση το αποτέλεσμα της καθορισμένης δοκιμής.
git bisect run '[ -e foo.bar ]'
Τώρα βρίσκεστε στο commit που το διέγραψε. Από εδώ, μπορείτε να μεταβείτε πίσω στο μέλλον και να χρησιμοποιήσετε το git-revert
για να αναιρέσετε την αλλαγή,
git bisect reset
git revert <the offending commit>
ή μπορείτε να πάτε πίσω ένα commit και να επιθεωρήσετε χειροκίνητα τη ζημιά:
git checkout HEAD^
cp foo.bar /tmp
git bisect reset
cp /tmp/foo.bar .