Riparare una testa staccata Git?


1455

Stavo facendo un po 'di lavoro nel mio repository e ho notato che un file presentava modifiche locali. Non li volevo più, quindi ho eliminato il file, pensando di poterne fare un checkout. Volevo fare l'equivalente Git di

svn up .

L'uso git pullnon sembra funzionare. Alcune ricerche casuali mi hanno portato a un sito in cui qualcuno mi ha consigliato di fare

git checkout HEAD^ src/

( srcè la directory che contiene il file eliminato).

Ora scopro di avere una testa distaccata. Non ho idea di cosa sia. Come posso annullare?


69
git checkout masterti riporterà sul ramo principale. Se volevi cancellare eventuali modifiche alla copia di lavoro, probabilmente volevi farlo git reset --hard.
Abe Voelker,


se non ti sei impegnato, avresti potuto farlogit checkout -- src/
segno d'estate

Prova questo: link . In brevecreate temp branch - checkout temp branch - checkout master - delete temp branch
fidev,

@AbeVoelker Cosa intendevi dire nei commenti working copy changes? Ti riferisci alle modifiche che hai apportato ai file dopo aver verificato un altro commit (ovvero, le modifiche che hai apportato mentre sei in uno stato head distaccato)?
Minh Tran,

Risposte:


2148

Head distaccato significa che non sei più su un ramo, hai verificato un singolo commit nella cronologia (in questo caso il commit precedente a HEAD, ovvero HEAD ^).

Se si desidera eliminare le modifiche associate a HEAD staccato

Devi solo controllare la filiale in cui ti trovavi, ad es

git checkout master

La prossima volta che hai modificato un file e desideri ripristinarlo allo stato in cui si trova nell'indice, non eliminare prima il file, ma semplicemente

git checkout -- path/to/foo

Ciò ripristinerà il file foo allo stato in cui si trova nell'indice.

Se si desidera mantenere le modifiche associate a HEAD distaccato

  1. Esegui git branch tmp: questo salverà le modifiche in un nuovo ramo chiamato tmp.
  2. Correre git checkout master
  3. Se si desidera incorporare le modifiche apportate master, eseguire git merge tmpdal masterramo. Dovresti essere sul masterramo dopo l'esecuzione git checkout master.

6
"Ciò ripristinerà il file foo allo stato in cui si trovava prima di apportare eventuali modifiche." -> lo ripristinerà allo stato in cui si trova nell'indice - modifica
Mr_and_Mrs_D

88
Perché questo errore si verifica in primo luogo? Questa è una delle cose per cui odio scappare: comportamenti totalmente casuali a volte. Non ho mai avuto problemi del genere con Mercurial.
Violet Giraffe

97
@VioletGiraffe Non è né un errore né qualcosa di casuale - è semplicemente lo stato in cui si trova il tuo repository quando esegui il checkout di un commit precedente. La "testa distaccata" serve come avvertimento che potresti voler creare o puntare a una succursale se hai intenzione di fare qualsiasi lavoro da quel punto. Ma se desideri semplicemente visualizzare quel tag o commit, non c'è niente di sbagliato nell'essere in uno stato head distaccato.
Neil Neyman,

22
Non farlo se ti sei impegnato con la testa distaccata, vedi altre risposte. In tal caso, puoi controllare le menzioni di testa precedenti inPrevious HEAD position was 7426948...
KCD

9
@VioletGiraffe: hai un modello mentale di ciò che sta accadendo basato su Mercurial, ma stai usando Git. Se non sei disposto ad adattare il tuo modello mentale per adattarlo al modello di Git, le cose continueranno ad apparire casuali. È come se stessi camminando fuori con gli occhiali VR e pensi di volare su un aereo ma stai davvero attraversando la strada. Verrai colpito dalle macchine.
iconoclasta,

477

Se hai modificato i file che non vuoi perdere, puoi inviarli. Li ho commessi in modalità distaccata e successivamente puoi spostarti in un ramo temporaneo per integrarlo successivamente in master.

git commit -m "....."
git branch my-temporary-work
git checkout master
git merge my-temporary-work

Estratto da:

Cosa fare con il commit effettuato in una testa distaccata


27
Trovo che questa sia la soluzione preferita, soprattutto se si desidera mantenere le modifiche apportate al momento del checkout della singola versione.
Adswebwork

10
@adswebwork: sono d'accordo. Tutte le altre risposte suggeriscono di tornare a uno stato precedente e di perdere le modifiche apportate localmente nello stato principale distaccato.
Sk8erPeter

6
perchè no git stash? Poiché questa è la prima cosa che mi viene in mente. la creazione di una nuova filiale sarà eccessiva.
giovedì,

2
potresti anche git rebase my-temporary-worke quindi eliminare il ramo in git branch -d my-temporary-workmodo che appaia come se ti fossi impegnata nel ramo giusto in primo luogo.
Zoltán,

@geekay git stashsembra lo strumento perfetto per questo caso. Potresti scrivere una risposta con i passaggi suggeriti per raggiungere questo obiettivo?
Zoltán,

157

Una soluzione senza creare un ramo temporaneo.

Come uscire ("risolvere") lo stato HEAD distaccato quando hai già cambiato qualcosa in questa modalità e, facoltativamente, vuoi salvare le tue modifiche:

  1. Effettua le modifiche che desideri mantenere. Se si desidera rilevare una qualsiasi delle modifiche apportate nello stato HEAD distaccato, eseguirne il commit. Piace:

    git commit -a -m "your commit message"
    
  2. Elimina le modifiche che non desideri conservare. L'hard reset annullerà tutte le modifiche non confermate apportate nello stato HEAD distaccato:

    git reset --hard
    

    (Senza questo, il passaggio 3 fallirebbe, lamentandosi dei file modificati di cui non è stato eseguito il commit nel HEAD distaccato.

  3. Dai un'occhiata alla tua filiale. Esci dallo stato HEAD distaccato controllando il ramo su cui hai lavorato prima, ad esempio:

    git checkout master
    
  4. Assumi i tuoi impegni. Ora puoi assumere i commit effettuati nello stato HEAD distaccato selezionando la ciliegia, come mostrato nella mia risposta a un'altra domanda .

    git reflog
    git cherry-pick <hash1> <hash2> <hash3> …
    

L' git reset --hardera esattamente era avevo bisogno, perché voglio il monte di essere la fonte e le modifiche locali deve essere rimosso.
Markus Zeller,

Ottima risposta, questo ha funzionato per me
MGLondon

130

La testa staccata significa:

  1. Non sei più su un ramo,
  2. Hai verificato un singolo commit nella cronologia

Se non si apportano modifiche: è possibile passare al master applicando il comando seguente

  git checkout master

Se hai delle modifiche che vuoi conservare:

Nel caso di una HEAD staccata, il lavoro viene eseguito normalmente, tranne per il fatto che nessun ramo denominato viene aggiornato. Per ottenere il ramo principale aggiornato con le modifiche impegnate, crea un ramo temporaneo nel punto in cui ti trovi (in questo modo il ramo temporaneo avrà tutte le modifiche impegnate che hai effettuato in HEAD distaccato), quindi passa al ramo principale e unisci il ramo temporaneo con Il capo.

git branch  temp
git checkout master
git merge temp

2
perfetto, quindi dopo aver rimosso la diramazione del ramo
Davi Menezes,

64

Ecco cosa ho fatto solo dopo aver realizzato che ero su una testa distaccata e avevo già apportato alcune modifiche.

Ho commesso le modifiche.

$ git commit -m "..."
[detached HEAD 1fe56ad] ...

Ho ricordato l'hash (1fe56ad) del commit. Poi ho controllato il ramo in cui avrei dovuto essere.

$ git checkout master
Switched to branch 'master'

Alla fine ho applicato le modifiche del commit al ramo.

$ git cherry-pick 1fe56ad
[master 0b05f1e] ...

Penso che sia un po 'più semplice che creare un ramo temporaneo.


2
Questa dovrebbe essere la risposta. Recupera i tuoi file con il dossier.
BlindWanderer,

2
Sì, questa è davvero la cosa più semplice da fare: abbastanza semplice da ricordare senza cercare sul web la prossima volta che succede. Commit, annota l'hash, torna al ramo in cui intendevi impegnarti e git cherry-pick <hash>.
Mason,

Grazie per la soluzione Questo ha aiutato. Posso anche aggiungere che dovevo fare un "master git push origin" in modo che il mio master e origin / master stessero puntando allo stesso commit.
Turnip424,

1
Questa è essenzialmente la risposta di Tanius (pubblicata più di un anno prima).
Peter Mortensen,

Grazie a questa scelta allegra, ripristina gli ultimi cambi di testa del distaccamento
Omega Cube,

55

Se hai apportato alcune modifiche e ti sei reso conto che sei su una testa staccata, c'è una soluzione semplice per questo: stash -> checkout master -> stash pop:

git stash
git checkout master   # Fix the detached head state
git stash pop         # Or for extra safety use 'stash apply' then later 
                      #   after fixing everything do 'stash drop'

Avrai le tue modifiche senza impegno e la TESTA "attaccata" normale, come se niente fosse.


2
Ho aggiunto un segnalibro a questo ragazzaccio - salva facendo un ramo temporaneo. Ha funzionato a meraviglia.
Tim Tyler,

1
Spesso finisco in uno stato HEAD distaccato dopo aver verificato un sottomodulo git, quindi averlo modificato. Trovo che questa sia la soluzione migliore e più semplice per sistemare le cose in modo da poter conservare le mie modifiche.
user5359531

1
Questo non funziona se hai già eseguito modifiche in uno stato distaccato?
Danijel,

40

Quando verifichi un commit specifico, finisci in gituno stato head distaccato ... cioè, la tua copia di lavoro non riflette più lo stato di un riferimento denominato (come "master"). Questo è utile per esaminare lo stato passato del repository, ma non quello che desideri se stai effettivamente cercando di ripristinare le modifiche.

Se hai apportato modifiche a un determinato file e desideri semplicemente scartarle, puoi utilizzare il checkoutcomando in questo modo:

git checkout myfile

Ciò eliminerà qualsiasi modifica non impegnata e ripristinerà il file a qualsiasi stato abbia nella testa del ramo corrente. Se desideri annullare le modifiche che hai già eseguito il commit, puoi utilizzare il resetcomando. Ad esempio, questo reimposterà il repository allo stato del commit precedente, scartando eventuali modifiche successive:

git reset --hard HEAD^

Tuttavia, se si condivide il repository con altre persone, a git resetpuò essere di disturbo (perché cancella una parte della cronologia del repository). Se hai già condiviso le modifiche con altre persone, in genere desideri git revertinvece guardare , che genera un "anticommit", ovvero crea un nuovo commit che "annulla" le modifiche in questione.

Il libro Git ha maggiori dettagli.


1
Come ho detto nella risposta di @ ralphtheninja, git checkout path/to/foopotrebbe essere in conflitto con git checkout some-branch, quindi sarebbe meglio usare git checkout -- path/to/fooper evitare questi conflitti.
Diego Lago,

30

HEAD è in un puntatore e, di conseguenza, punta - direttamente o indirettamente - a un particolare commit:

Attaccato   HEAD significa che è attaccato ad un ramo (cioè punta ad un ramo).
Distaccato mezzi a testa che è non collegato a qualsiasi ramo, cioè punta direttamente a qualche commit.

inserisci qui la descrizione dell'immagine

In altre parole:

  • Se punta direttamente a un commit , HEAD viene rimosso .
  • Se indica indirettamente un commit (ovvero indica un ramo, che a sua volta indica un commit), HEAD viene allegato .

Per comprendere meglio le situazioni con HEAD attaccato / staccato, mostriamo i passaggi che portano al quadruplet delle immagini sopra.

Iniziamo con lo stesso stato del repository (le immagini in tutti i quadranti sono uguali):

inserisci qui la descrizione dell'immagine


Ora vogliamo realizzare git checkout- con diversi target nelle singole immagini (i comandi sulla parte superiore di loro sono in grigio per sottolineare che stiamo solo andando a applicare tali comandi):

inserisci qui la descrizione dell'immagine


Questa è la situazione dopo aver eseguito quei comandi:

inserisci qui la descrizione dell'immagine

Come puoi vedere, HEAD punta al target del git checkoutcomando - a un ramo (prime 3 immagini del quadruplet) o (direttamente) a un commit (l'ultima immagine del quadruplet).

Anche il contenuto della directory di lavoro viene modificato per essere conforme al commit appropriato (istantanea), ovvero al commit indicato (direttamente o indirettamente) da HEAD.


Quindi ora ci troviamo nella stessa situazione all'inizio di questa risposta:

inserisci qui la descrizione dell'immagine


6
Non l'ho letto, ma ho votato per le belle foto che hai fatto;).
Carlo Wood,

@Carlo, grazie!
MarianD

22

Dato che "stato di testa distaccato" ti ha su un ramo temporaneo, basta usare ciò git checkout -che ti mette sull'ultimo ramo in cui ti trovavi.


1
fai attenzione, perderai tutti gli impegni che hai fatto quando eri in stato di testa distaccato.
Ajak6,

@ Ajak6 Non perdi davvero quei commit. Sono ancora disponibili tramite git refloge possono essere trasferiti in una nuova filiale o git cherry-pickin una filiale esistente. Vedere questa domanda .
tanius,

7

Per chiarire ulteriormente la risposta di @Philippe Gerber, eccola:

git cherry-pick

Prima cherry-pick, git checkout masterin questo caso è necessario. Inoltre, è necessario solo con un commitin detached head.


6

appendice

Se la filiale in cui desideri tornare è stata l'ultima cassa che hai effettuato, puoi semplicemente utilizzare checkout @{-1}. Questo ti riporterà al checkout precedente.

Inoltre, puoi alias questo comando con, ad esempio, in git global --config alias.prevmodo tale che devi solo digitare git prevper tornare al checkout precedente.


4

Essere in "testa distaccata" significa che HEAD si riferisce a un commit specifico senza nome (come opposto a un ramo con nome) (cfr: https://git-scm.com/docs/git-checkout sezione Detached head )

Per risolvere il problema, è sufficiente selezionare il ramo che è stato selezionato in precedenza da

git checkout @{-1}


2

Quando ti trovi in ​​una situazione di testa distaccata e hai creato nuovi file, assicurati innanzitutto che questi nuovi file vengano aggiunti all'indice, ad esempio con:

git add .

Ma se hai modificato o eliminato solo i file esistenti, puoi aggiungere (-a) e eseguire il commit con un messaggio (-m) contemporaneamente tramite:

git commit -a -m "my adjustment message"

Quindi puoi semplicemente creare una nuova filiale con il tuo stato attuale con:

git checkout -b new_branch_name

Avrai una nuova filiale e tutte le tue modifiche saranno lì in quella nuova filiale. Puoi quindi continuare a spingere sul telecomando e / o fare il checkout / pull / merge come preferisci.


1

Git mi ha detto come farlo.

se hai digitato:

git checkout <some-commit_number>

Salva lo stato

git add .
git commit -m "some message"

Poi:

 git push origin HEAD:<name-of-remote-branch>

1

Volevo mantenere le mie modifiche, quindi, ho risolto il problema facendo ...

git add .
git commit -m "Title" -m "Description"
(so i have a commit now example: 123abc)
git checkout YOURCURRENTBRANCH
git merge 123abc
git push TOYOURCURRENTBRANCH

quel lavoro per me


1

Normalmente HEADpunta a un ramo. Quando invece non punta a un ramo quando punta a un hash di commit come 69e51se significa che hai un HEAD distaccato. È necessario indicarlo due un ramo per risolvere il problema. Puoi fare due cose per risolverlo.

  1. git checkout other_branch // Non possibile quando è necessario il codice in tale commit hash
  2. crea un nuovo ramo e punta l'hash di commit sul ramo appena creato.

HEAD deve puntare a un ramo, non un hash di commit è la regola d'oro.


ecco perché ho avuto questo errore. Ho fatto il check-out per una revisione e poi ho ricontrollato alla revisione attuale / più recente invece di fare il check-out alla filiale, che avrebbe attaccato correttamente la testa. Grazie per l'aiuto.
Rahul Thakur,

1

Head distaccato significa che non hai estratto correttamente il tuo ramo o hai appena estratto un singolo commit.

Se si riscontra un problema del genere, riporre innanzitutto le modifiche locali in modo da non perderle.

Dopodiché ... controlla il tuo ramo desiderato usando il comando:

Diciamo che vuoi ramo MyOriginalBranch:

git checkout -b someName origin / MyOriginalBranch


1

probabilmente l'hai fatto git reset --hard origin/your-branch.

Prova solo git checkout your-branch


0
git pull origin master

ha funzionato per me. Si trattava solo di dare esplicitamente il nome remoto e di filiale.


0

Nel mio caso, corro git statuse ho visto che avevo alcuni file non tracciati nella mia directory di lavoro.

Ho dovuto solo pulirli (dal momento che non ne avevo bisogno) per eseguire il rebase che volevo eseguire.


0

Questo funziona per me, assegnerà un nuovo ramo per la testa distaccata:

git checkout new_branch_name distaccato_head_garbage_name


0

HEAD distaccato significa che attualmente non sei su alcun ramo. Se vuoi MANTENERE le modifiche attuali e creare semplicemente una nuova filiale, ecco cosa fai:

git commit -m "your commit message"
git checkout -b new_branch

Successivamente, potresti potenzialmente unire questo nuovo ramo con altri rami. Sempre utile è il comando git "a dog" :

git log --all --decorate --oneline --graph
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.