Dangit, Git!?!

Git è difficile: fare danni è facile, e riuscire a trovare il modo per risolvere i propri errori è impossibile. La documentazione su Git ha il difetto dell'uovo e della gallina, dove è impossibile trovare il modo di uscire da un pasticcio, a meno che tu non sappia già il nome della cosa che ti serve sapere per riuscire a risolvere il problema.

Qui troverete alcune brutte situazioni in cui mi sono ritrovata, e come alla fine sono riuscita a uscirne, in parole povere.

Dangit, ho fatto una cosa sbagliatissima, ti prego dimmi che git ha una macchina del tempo!?!

git reflog
# qui apparirà una lista di ogni cosa che
# hai fatto su git, in ogni branch!
# ognuna di queste ha un indice HEAD@{index}
# trova quella subito precedente a quando hai rotto tutto
git reset HEAD@{index}
# macchina del tempo

Puoi utilizzare questa tecnica per riavere cose che hai cancellato per sbaglio, per rimuovere cose che hai fatto che hanno rotto la repository, per aggiustare dopo un merge andato male, o semplicemente per tornare a un punto in cui le cose funzionavano. Personalmente uso reflog MOLTO SPESSO. Un mega chapeau alle tante tante tante tante tante persone che lo hanno suggerito!

Dangit, ho fatto una commit e mi sono subito reso accorto di dover cambiare una cosa!

# cambia ció che vuoi
git add . # o aggiungi i file individualmente 
git commit --amend --no-edit
# adesso la tua ultima commit contiene la modifica!
# ATTENZIONE: non modificare mai una commit pubblica

Questo mi succede spesso se faccio una commit e faccio test/uso linter... e mi accorgo di aver dimenticato uno spazio dopo un simbolo uguale. Potresti anche fare la modifica come una nuova commit e poi rebase -i per accorparle insieme, ma in questo modo è mille volte piú veloce.

Attenzione: Non si dovrebbe mai correggere una commit che è stata pushed a una branch pubblica o condivisa! Correggi soltanto le commits che esistono nella tua copia locale oppure ti ritroverai in una brutta situazione.

Dangit, devo cambiare il messaggio dell'ultima commit!

git commit --amend
# segui le istruzioni per cambiare il messaggio della commit

Stupidi requisiti per i messaggi delle commits.

Dangit, ho accidentalmente fatto una commit su master che sarebbe dovuta essere su una branch nuova!

# crea una branch nuova dallo stato attuale di master
git branch nome-qualsiasi-branch-nuova
# rimuovi l'ultima commit dalla branch master
git reset HEAD~ --hard
git checkout nome-branch-appena-creata
# adesso la tua commit vive in questa branch :)

Nota: questo metodo non funzionerà se hai già pushed la commit verso una branch pubblica/condivisa; inoltre se hai già provato a risolvere in altri modi, puó darsi che tu debba git reset HEAD@{number-of-commits-back} invece di HEAD~. Tristezza infinita. Inoltre, tante tante tante persone mi hanno suggerito un modo per rendere questo metodo piú corto di com'era, di cui non avevo idea. Grazie a tutti!

Dangit, ho accidentalmento fatto una commit sulla branch sbagliata!

# annulla l'ultima commit, ma mantieni i cambiamenti in modo che siano accedibili
git reset HEAD~ --soft
git stash
# spostati sulla branch giusta 
git checkout nome-della-branch-giusta
git stash pop
git add . # o aggiungi i file uno alla volta
git commit -m "il tuo messaggio va qui"
# ora i tuoi cambiamenti sono sulla branch giusta

Un sacco di persone hanno suggerito l'uso di cherry-pick anche per questa situazione, scegli te quale dei due ha piú senso nel tuo caso!

git checkout nome-della-branch-giusta
# prendi l'ultima commit fatto su master
git cherry-pick master
# cancellala da master
git checkout master
git reset HEAD~ --hard

Dangit, ho provato a usare diff ma non è successo niente?!

Se sai di aver fatto modifiche ad alcuni file, ma diff non ti da risultati, probabilmente hai già add i tuoi files e devi usare diff usando una flag apposita.

git diff --staged

File che appartengono a questa categoria ¯\(ツ)/¯ (si, lo so che è una caratteristica voluta, non un bug, ma la prima volta che succede ti confonde!)

Dangit, devo annullare una commit tipo da 5 commit fa!

# trova la commit che devi annullare
git log
# usa la freccia per andare su e giú nella storia
# quando hai trovato la commit, salva la hash corrispondente
git revert [hash salvata]
# git creerà una nuova commit che annulla la commit che corrisponde a quella hash
# segui le istruzioni per modificare il messaggio della commit
# o salva la commit e basta

Ho scoperto che non devi trovare e fare copia-incolla del contenuto del vecchio file dentro al file esistente per annullare i cambiamenti! Se hai fatto una commit con un bug, puoi annullarla tutto insieme usando revert.

Puoi anche annullare un file singolo invece di tutta la commit! Ma ovviamente, nello stile di git, serve un set di input completamente diverso...

Dangit, devo annullare le mie modifiche di un file!

# trova la hash della commit prima che il file fosse modificato
git log
# usa le frecce per andare su e giú nella storia
# quando hai trovato il commit, salva la hash
git checkout [hash salvata] -- path/del/file/in/questione
# la versione precedente del file sarà nel tuo index
git commit -m "Wow, non devi fare copia-incolla per annullare modifiche"

Quando ho finalmente scoperto questa cosa è stato il STUPENDO. STUPENDO. S-T-U-P-E-N-D-O. Ma sul serio peró, su che pianeta checkout -- ha senso come metodo migliore per annullare le modifiche su un file? :shakes-fist-at-linus-torvalds:

Che casino, mi arrendo.

cd ..
sudo rm -r stupida-git-repo
git clone https://some.github.url/stupida-git-repo.git
cd stupida-git-repo-dir

Grazie a Eric V. per questa dritta. Tutti le lamentele riguardo l'uso di sudo possono essere rivolte a lui.

Davvero peró, se la tua branch è così rovinata che hai bisogno di resettare lo stato della tua repository così che sia lo stesso della repo remota, in un modo che sia 'in stile git', prova il seguente metodo, ma fai attenzione perchè le seguenti azioni sono distruttive e non si puó tornare indietro!

# guarda lo stato di git piú recente
git fetch origin
git checkout master
git reset --hard origin/master
# elimina files e cartelle non tracciate
git clean -d --force
# ripeti checkout/reset/clean per ogni branch rovinata

*Disclaimer: Lo scopo di questo sito non è essere una fonte esauriente. E certamente, ci sono altri modi per fare le stesse cose con una maggiore purezza dal punto di vista teorico, ma sono arrivata a queste soluzioni sperimentando, imprecando e rovesciando tavoli, e ho avuto quest'idea di condividerle con una sana dose di leggerezza e volgarità. Prendere o lasciare!

Tante grazie a tutti coloro che hanno tradotto il sito in altre lingue, sei grande! Moritz Stückler (de) · Daniil Golubev (ru) · Łukasz Wójcik (pl) · fedemcmac (it) · Michel (fr)

Se desideri aiutare ad aggiungere una traduzione nella tua lingua, invia un PR su GitHub