Qual è la differenza tra "git reset" e "git checkout"?


440

Ho sempre pensato git resete git checkoutuguale, nel senso che entrambi riportano il progetto a un impegno specifico. Tuttavia, ritengo che non possano essere esattamente gli stessi, poiché sarebbe ridondante. Qual è la differenza effettiva tra i due? Sono un po 'confuso, poiché lo svn deve solo svn coripristinare il commit.

AGGIUNTO

VonC e Charles hanno spiegato le differenze tra git resete git checkoutdavvero bene. La mia attuale comprensione è che git resetriporta tutte le modifiche a un commit specifico, mentre git checkoutpiù o meno si prepara per un ramo. Ho trovato i seguenti due diagrammi abbastanza utili per giungere a questa comprensione:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

AGGIUNTO 3

Da http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html , checkout e reset possono emulare il rebase.

inserisci qui la descrizione dell'immagine

git checkout bar 
git reset --hard newbar 
git branch -d newbar 

inserisci qui la descrizione dell'immagine



Ri: "È sbagliato o eccessivamente semplificato?" Sì, quel primo diagramma è fuorviante per quanto riguarda la differenza tra checkout e reset. (Potrebbe essere OK per quanto riguarda le -- filesvarianti; non ne sono sicuro.) Questo diagramma fa sembrare che la differenza principale sia se influenzano l'indice o il WD. Vedi la mia risposta al riguardo. Il 2 ° e il 3 ° diagramma sono molto utili per vedere la vera differenza. Il quarto e il quinto diagramma sono utili per verificare se capisci cosa fanno questi comandi, ma non ti aiuteranno davvero ad arrivarci.
LarsH,

Ho trovato la sezione "Check it out" di "Git Tools Reset Demysified" per fornire il riepilogo più utile.
Josiah Yoder

1
prosseek: Se sei d'accordo con @LarsH che il primo diagramma è fuorviante, puoi rimuoverlo, per favore?
Josiah Yoder

Si prega di notare che il checkout e il reset emulano solo la seconda parte di rebase e che think-like-a-git.netsono necessari passaggi aggiuntivi (forniti nell'articolo collegato ) per prevenire la perdita di dati.
cowlinator il

Risposte:


198
  • git resetriguarda in particolare l' aggiornamento dell'indice , lo spostamento di HEAD.
  • git checkoutriguarda l' aggiornamento dell'albero di lavoro (all'indice o all'albero specificato). Aggiornerà HEAD solo se esegui il checkout di un ramo (in caso contrario, finisci con HEAD staccato ).
    (in realtà, con Git 2.23 Q3 2019, questo sarà git restore, non necessariamente git checkout)

In confronto, poiché svn non ha un indice, solo un albero di lavoro, svn checkoutcopierà una data revisione in una directory separata.
L'equivalente più vicino per git checkoutsarebbe:

  • svn update (se ti trovi nello stesso ramo, ovvero lo stesso URL SVN)
  • svn switch (se fai il checkout per esempio lo stesso ramo, ma da un altro URL repository SVN)

Tutti quei tre che lavorano modifiche albero ( svn checkout, update, switch) hanno solo un comando in git: git checkout.
Ma poiché git ha anche la nozione di indice (quella "area di gestione temporanea" tra il repository e l'albero di lavoro), lo hai anche tu git reset.


Thinkeye menziona nei commenti l'articolo " Ripristina demistificato ".

Ad esempio, se abbiamo due rami ' master' e ' develop' che puntano a commit diversi, e attualmente siamo su ' develop' (quindi HEAD punta ad esso) e corriamo git reset master' develop', ora indicherà lo stesso commit che '' master'fa.

D'altra parte, se invece corriamo git checkout master' develop', non si muoverà, lo HEADfarà di per sé. HEADindicherà ora " master".

Quindi, in entrambi i casi ci stiamo muovendo HEADper puntare a impegnarci A, ma il modo in cui lo facciamo è molto diverso. resetsposta i HEADpunti del ramo in, il checkout si sposta HEADper indicare un altro ramo.

http://git-scm.com/images/reset/reset-checkout.png

Su questi punti, però:

LarsH aggiunge nei commenti :

Il primo paragrafo di questa risposta, tuttavia, è fuorviante: " git checkout... aggiornerà HEAD solo se esegui il checkout di un ramo (in caso contrario, finisci con HEAD distaccato)".
Non vero: git checkoutaggiornerà HEAD anche se si effettua il checkout di un commit che non è un ramo (e sì, si finisce con un HEAD staccato, ma è stato comunque aggiornato).

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo concorda nei commenti :

@LarsH è corretto.
Il secondo proiettile ha un'idea sbagliata su cosa sia HEAD aggiornerà HEAD solo se si verifica un ramo.
HEAD va ovunque tu sia, come un'ombra.
Controllando alcuni ref non branch (ad es. Un tag) o un commit direttamente, si sposterà HEAD. La testa staccata non significa che ti sei staccata dalla TESTA, significa che la testa è staccata da un riferimento di ramo, da cui puoi vedere, ad es git log --pretty=format:"%d" -1.

  • Gli stati head allegati inizieranno con (HEAD ->,
  • distaccato mostrerà comunque (HEAD, ma non avrà una freccia verso un ramo ref.

7
Direi che si git resettratta di modificare il ramo "etichetta" e facoltativamente di aggiornare l'indice o l'albero di lavoro come effetto collaterale. git checkoutriguarda l'aggiornamento dell'albero di lavoro e il passaggio al ramo attualmente "selezionato" (il HEAD).
Mikko Rantalainen,

2
@MikkoRantalainen no. git resetè al 100% circa HEAD. Funziona anche in modalità HEAD distaccata ( stackoverflow.com/a/3965714/6309 ), il che significa che non è presente alcun ramo (!). git checkout funziona anche in modalità HEAD staccata, oppure può essere usato per effettuare il checkout di un SHA1 in modalità HEAD staccata: di nuovo nessun ramo coinvolto in quel caso.
VonC

3
Ulteriori letture per tutte le anime perdute inviate qui da un motore di ricerca, penso ne valga la pena: git-scm.com/blog/2011/07/11/reset.html
Thinkeye

2
@Thinkeye buon riferimento. L'ho incluso, insieme a un estratto pertinente, nella risposta per una maggiore visibilità.
VonC

2
La spiegazione da Reset Demystified è eccellente. Il primo paragrafo di questa risposta, tuttavia, è fuorviante: "git checkout ... aggiornerà HEAD solo se esegui il checkout di un ramo (in caso contrario, finisci con un HEAD distaccato)". Non vero ... git checkout aggiornerà HEAD anche se si esegue il checkout di un commit che non è un ramo (e sì, si finisce con un HEAD staccato, ma è ancora aggiornato). Forse sto fraintendendo cosa intendi per "aggiornamento"? git checkout a839e8faggiorna HEAD per indicare l'impegno a839e8f.
LarsH,

67

Nella loro forma più semplice, resetreimposta l'indice senza toccare l'albero di lavoro, mentre checkoutcambia l'albero di lavoro senza toccare l'indice.

Reimposta l'indice in modo che corrisponda HEAD, albero di lavoro lasciato solo:

git reset

Concettualmente, questo verifica l'indice nell'albero di lavoro. Per farlo effettivamente fare qualsiasi cosa dovresti usare -fper forzarlo a sovrascrivere eventuali modifiche locali. Questa è una funzione di sicurezza per assicurarsi che il modulo "nessun argomento" non sia distruttivo:

git checkout

Una volta che inizi ad aggiungere parametri, è vero che c'è qualche sovrapposizione.

checkoutviene solitamente utilizzato con un ramo, tag o commit. In questo caso verrà reimpostato HEADe l'indice sul commit specificato, oltre a eseguire il checkout dell'indice nell'albero di lavoro.

Inoltre, se fornisci --harda resette puoi chiederereset di sovrascrivere l'albero di lavoro, nonché il ripristino dell'indice.

Se attualmente si dispone di una filiale verificata, esiste una differenza cruciale tra resete checkoutquando si fornisce una filiale o un commit alternativi. resetcambierà il ramo corrente in modo che punti al commit selezionato mentre checkoutlascerà solo il ramo corrente ma verificherà invece il ramo o il commit forniti.

Altre forme di resetecommit coinvolgono percorsi di fornitura.

Se fornisci percorsi a resette non puoi fornire --harde resetcambierà solo la versione dell'indice dei percorsi forniti con la versione nel commit fornito (oHEAD se non specifichi un commit).

Se fornisci percorsi a checkout , come resetaggiornerà la versione dell'indice dei percorsi forniti in modo che corrisponda al commit fornito (o HEAD) ma controllerà sempre la versione dell'indice dei percorsi forniti nell'albero di lavoro.


2
Non è vero dire che "checkout" non cambia l'indice: lo cambia quando viene utilizzato per passare da un ramo all'altro.
wiki1000,

Nella loro forma più semplice, reset reimposta l'indice senza toccare l'albero di lavoro, mentre il checkout modifica l'albero di lavoro senza toccare l'indice. : Quanto è confuso questo: |
Aditya Gupta,

41

Un semplice caso d'uso quando si ripristina la modifica:
1. Utilizzare reset se si desidera annullare la gestione temporanea di un file modificato.
2. Utilizzare il checkout se si desidera annullare le modifiche ai file non in scena.


1
Risposta perfetta Grazie.
user358591

11

La differenza chiave in breve è che reset sposta l'attuale riferimento al ramo , mentrecheckout non lo fa (sposta HEAD).

Come spiega il libro Pro Git in Reset Demystified ,

La prima cosa resetda fare è spostare ciò a cui punta HEAD . Questo non è lo stesso che cambiare HEAD stesso (che è ciò che checkoutfa); reset sposta il ramo a cui punta HEAD. Questo significa che se HEAD è impostato sul masterramo (cioè sei attualmente sul masterramo), in esecuzione git reset 9e5e6a4inizierà facendo masterpunto 9e5e6a4. [enfasi aggiunta]

Vedi anche la risposta di VonC per un utile testo e diagramma tratto dallo stesso articolo, che non duplicherò qui.

Naturalmente ci sono molti più dettagli su ciò che effetti checkoute resetpossono avere sull'indice e l'albero di lavoro, a seconda di cosa vengono utilizzati i parametri. Possono esserci molte somiglianze e differenze tra i due comandi. Ma a mio avviso, la differenza più cruciale è se spostano la punta dell'attuale ramo.


2
Un buon feedback, oltre alla mia risposta più vecchia. +1
VonC,

2

I due comandi (reset e checkout) sono completamente diversi.

checkout X NON È reset --hard X

Se X è un nome di ramo, checkout Xcambierà il ramo corrente mentre reset --hard Xnon lo farà.


2
Ma se X è un file o una cartella, allora sono gli stessi.
Ted Bigham,

1

breve mnemonica:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.