Dang it, Git!?!

Το git είναι δύσκολο: το να δημιουργήσεις πρόβλημα είναι εύκολο, και το να φτιάξεις τα λάθη σου είναι τελείως αδύνατο. Η βιβλιογραφία του git έχει το πρόβλημα του να ψάχνεις ψύλλο στα άχυρα ώστε να μή μπορείς να βγεις από το χάλι σου, εκτός και αν ξέρεις ήδη το όνομα του πράγματος το οποίο χρειάζεσαι για να φτιάξεις το πρόβλημά σου.

Ορίστε λοιπόν μερικές σκατό-περιπτώσεις στις οποίες βρέθηκα, και πως εν τέλει κατάφερα να ξεμπλέξω από αυτές, στα λαϊκά.

Dang it, κάτι έκανα τελείως λάθος, σε παρακαλώ πες μου ότι το git έχει μια μαγική μηχανή του χρόνου!?!

git reflog
# θα σου εμφανίσει μία λίστα με κάθε πράγμα 
# που έγινε στο git, σε όλα τα branches!
# κάθε ένα έχει ένα index HEAD@{index}
# βρες αυτό το οποίο χάλασε τα πάντα
git reset HEAD@{index}
# μαγική μηχανή του χρόνου

Μπορείς να το χρησιμοποιήσεις αυτό για να γυρίσεις σε πράγματα που καταλάθως διέγραψες, ή να διαγράψεις κάποια τα οποία χαλάσανε το repo, ή να κάνεις rollback μετά από ένα κακό merge, ή να γυρίσεις πίσω το χρόνο έως ότου το σημείο μέχρι το οποίο τα πράγματα δούλευαν. Χρησιμοποιώ το reflog ΠΟΛΥ. Βγάζω επειδικτικά το καπέλο στους πολλούς πολλούς πολλούς πολλούς πολλούς ανθρώπους που πρότειναν να προστεθεί αυτή η λειτουργία!

Dang it, έκανα commit και αμέσως συνειδητοποίησα ότι χρειάζεται να κάνω μια μικρή αλλαγή!

# κάνε την αλλαγή σου
git add . # ή πρόσθεσε ένα-ένα τα αρχεία
git commit --amend --no-edit
# τώρα το τελευταίο σου commit περιέχει την αλλαγή σου!
# ΠΡΟΣΟΧΗ: ποτέ μη κάνεις amend public commits

Αυτό μου συμβαίνει συχνά αν κάνω commit, μετά τρέξω tests/linters... και να πάρει, δεν έβαλα κενό μετά από ένα equals sign. Θα μπορούσες επίσης να κάνεις την αλλαγή ως νέο commit και μετά να κάνεις rebase -i έτσι ώστε να τα ενώσεις και τα δύο μαζί, αλλά το πρώτο είναι πολύ πιο γρήγορο.

Προσοχή: Δεν θα πρέπει να κάνεις ποτέ amend commits τα οποία έχουν γίνει push σε ένα public/shared branch! Κάνε μόνο amend commits τα οποία υπαρχουν σε τοπικό αντίγραφο αλλιώς δεν θα περάσεις καλά.

Dang it, πρέπει να αλλάξω το τελευταίο commit message!

git commit --amend
# ακολούθησε τα prompts για να αλλάξεις το commit message

Εκνευριστικά commit message formatting requirements.

Dang it, καταλάθος έκανα commit κάτι στο master το οποίο θα έπρεπε να είναι σε ξεχωριστό καινούργιο branch!

# δημιούργησε νέο branch από το παρόν state του master
git branch κάποιο-νέο-όνομα-του-branch
# αφαίρεσε το τελευταίο commit από το master branch
git reset HEAD~ --hard
git checkout κάποιο-νέο-όνομα-του-branch
# το commit σου ζει πλέον στο νέο σου branch :)

Σημείωση: αυτό δεν λειτουργεί αν έχεις κάνει ήδη push το commit σε κάποιο δημόσιο/κοινόχρηστο branch, και αν έχεις δοκιμάσει άλλα πράγματα πρώτα, ίσως χρειαστεί να κάνεις git reset HEAD@{number-of-commits-back} έναντι του HEAD~. Άπειρη θλίψης. Επίσης, πολλοί πολλοί πρότειναν έναν υπέροχο τρόπο να το κάνουν αυτό πιο σύντομα τον οποίο ούτε εγώ γνώριζα. Σας ευχαριστώ!

Dang it, έκανα commit σε λάθος branch!

# αναίρεσε το τελευταίο commit, αλλά άφησε τις αλλαγές διαθέσιμες
git reset HEAD~ --soft
git stash
# πήγαινε στο σωστό branch
git checkout όνομα-του-σωστού-branch
git stash pop
git add . # ή πρόσθεσε ένα-ένα τα αρχεία
git commit -m "το μήνυμα σου";
# τώρα οι αλλαγές σου είναι στο σωστό branch

Πολλοί προτείνανε τη χρήση του cherry-pick για αυτή τη περίσταση, οπότε διάλεξε αυτό που σου βγάζει περισσότερο νόημα!

git checkout name-of-the-correct-branch
# πάρε το τελευταίο commit από το master και βάλτο εδώ
git cherry-pick master
# διέγραψέ το από το master
git checkout master
git reset HEAD~ --hard

Dang it, προσπάθησα να τρέξω ένα diff αλλά δεν έγινε τίποτα?!

Αν ξέρεις ότι έκανες αλλαγές σε αρχεία, αλλά το diff είναι άδειο, πιθανώς έκανες add τα αρχεία σου στο staging και χρειάζεται να χρησιμοποιήσεις κάποιο special flag.

git diff --staged

File under ¯\_(ツ)_/¯ (ναι, γνωρίζω ότι είναι feature, όχι bug, αλλά είναι στριφνό και μή-προφανές όταν σου συμβαίνει για πρώτη φορά!)

Dang it, πρέπει να αναιρέσω κάποιο commit από πριν 5 λεπτά!

# βρες το commit που θες να αναιρέσεις
git log
# χρησιμοποίησε τα arrow keys για να σκρολάρεις κάτω στο ιστορικό
# μόλις βρεις το commit σου, σώσε το hash
git revert [το hash που έσωσες]
# το git θα δημιουργήσει ένα νέο commit που αναιρεί το commit σου
# ακολούθησε τα prompts για να κάνεις edit το commit message 
# ή απλά σώσε το commit

Απ' ότι φαίνεται δεν χρειάζεται να εντοπίσεις και να κάνεις copy-paste τα περιεχόμενα ενός παλιού αρχείου σε ένα υπάρχον για να καταφέρεις να αναιρέσεις αλλαγές! Αν έκανες commit κάποιο bug, μπορείς να αναιρέσεις το commit μόνο κάνοντας ένα revert.

Μπορείς επίσης να κάνεις revert ένα αρχείο αντί για ένα ολόκληρο commit! Αλλά φυσικά, επειδή μιλάμε για το git, αυτό θα είναι ένα διαφορετικό σύνολο εντολών...

Dang it, πρέπει να αναιρέσω τις αλλαγές μου σε ένα αρχείο!

# βρες το hash για ένα commit πριν την αλλαγή του αρχείου
git log
# χρησιμοποίησε τα arrow keys για να σκρολλάρεις στο ιστορικό
# μόλις βρεις το commit σου, σώσε το hash
git checkout [σωσμένο hash] -- path/στο/αρχείο
# η παλιά έκδοση του αρχείου σου θα είναι στο index
git commit -m "Wow, you don't have to copy-paste to undo"

Όταν επιτέλους το βρήκα αυτό ήταν ΣΠΟΥΔΑΙΑ. ΣΠΟΥΔΑΙΑ. Σ-Π-Ο-Υ-Δ-Α-Ι-Α ανακάλυψη. Αλλά σοβαρά, σε ποιο παράλληλο σύμπαν το checkout -- βγάζει νόημα να καταλήξεις ότι είναι ο καλύτερος τρόπος να αναιρέσεις κάποιο αρχείο; :κουνάει-τη-γροθιά-προς-τον-linus-torvalds:

Α καλά, παραιτούμαι.

cd ..
sudo rm -r βασανιστικό-git-repo-dir
git clone https://some.github.url/βασανιστικό-git-repo-dir.git
cd βασανιστικό-git-repo-dir

Ευχαριστώ τον Eric V. για αυτό. Όλα τα παράπονα για τη χρήση του sudo σε αυτό το αστείο μπορούν να απονεμηθούν σε αυτόν.

Σοβαρά πάντως, αν το branch σου είναι τόσο σαλατοποιημένο ώστε να πρέπει να κάνεις reset τη κατάσταση του repo σου ώστε να είναι η ίδια με το remote repo σε έναν "εγκεκριμένο-git" τρόπο, δοκίμασε αυτό, αλλά πρόσεξε τις καταστροφικές και μη αναστρέψιμες συνέπειες!

# λάβε τη τελευταία κατάσταση του origin
git fetch origin
git checkout master
git reset --hard origin/master
# διέγραψε untracked files και directories
git clean -d --force
# επανέλαβε checkout/reset/clean για κάθε σαλατοποιημένο branch

*Σημείωση: Αυτή η ιστοσελίδα δεν αποτελεί έργο αυτοτελούς αναφοράς. Και ναι, υπάρχουν άλλοι τρόποι οι οποίοι κάνουν τα ίδια πράγματα με πιο κοψό θεωρητικό τρόπο, αλλά έχω καταλήξει σε αυτά τα βήματα κάνοντας και βλέποντας με πολλά γαλλικά που θα ζήλευε και ο Στέφανος, οπότε είχα αυτή τη τρελή ιδέα να τα μοιραστώ με μία υγιεινή δόση κωμικής ύβρεως. Χαιρετώ και αποχωρώ!

Πολλά ευχαριστώ σε όσους εθελοντικά μετέφρασαν την ιστοσελίδα και σε άλλες γλώσσες, είστε υπέροχοι! Moritz Stückler (de) · Daniil Golubev (ru) · Łukasz Wójcik (pl) · fedemcmac (it) · Michel (fr) · Andriy Sultanov (ua) · Meiko Hori (ja) · Alex Tzimas (gr) · Franco Fantini (es) · Catalina Focsa (ro) · Davi Alexandre (pt_BR) . Με πρόσθετη βοήθεια από την Iain Murray · Frank Taillandier · David Fyffe · Lucas Larson

Αν θες να βοηθήσεις προσθέτοντας μια μετάφραση στη δικιά σου γλώσσα, κάνε submit ένα PR στο GitHub