git stash blunder: git stash pop e finì con unire conflitti


200

Ho fatto un git stash pope ho finito con i conflitti di unione. Ho rimosso i file dal file system e l'ho fatto git checkoutcome mostrato di seguito, ma pensa che i file non siano ancora uniti. Ho quindi provato a sostituire i file e fare di git checkoutnuovo lo stesso risultato. Ho provato a forzarlo con la -fbandiera. Qualsiasi aiuto sarebbe apprezzato!

chirag-patels-macbook-pro:haloror patelc75$ git status
app/views/layouts/_choose_patient.html.erb: needs merge
app/views/layouts/_links.html.erb: needs merge
# On branch prod-temp
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   db/schema.rb
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       unmerged:   app/views/layouts/_choose_patient.html.erb
#       unmerged:   app/views/layouts/_links.html.erb

chirag-patels-macbook-pro:haloror patelc75$ git checkout app/views/layouts/_choose_patient.html.erb
error: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
chirag-patels-macbook-pro:haloror patelc75$ git checkout -f app/views/layouts/_choose_patient.html.erb
warning: path 'app/views/layouts/_choose_patient.html.erb' is unmerged

Nota: il ripristino dello stato , prima della git stash apply/popdovrebbe essere più facile con Git 2.5 (Q2 2015), dal momento che l'albero di lavoro deve ora essere pulito: vedi la mia risposta qui sotto
VonC

Risposte:


219

Vedi man git merge ( COME RISOLVERE I CONFLITTI ):

Dopo aver visto un conflitto, puoi fare due cose:

  • Decidi di non unirti. Le uniche pulizie necessarie sono reimpostare il file indice sul commit HEAD per invertire 2. e ripulire le modifiche dell'albero di lavoro apportate da 2. e 3 .; git-reset --hard può essere usato per questo.

  • Risolvi i conflitti. Git segnerà i conflitti nell'albero di lavoro. Modifica i file in forma e git aggiungili all'indice. Usa git commit per sigillare l'affare.

E sotto TRUE MERGE (per vedere a cosa si riferiscono 2. e 3.):

Quando non è ovvio come conciliare le modifiche, si verifica quanto segue:

  1. Il puntatore HEAD rimane lo stesso.

  2. Il riferimento MERGE_HEAD è impostato per puntare sull'altra testa del ramo.

  3. I percorsi uniti in modo pulito vengono aggiornati sia nel file indice che nell'albero di lavoro.

  4. ...

Quindi: utilizzare git reset --hardse si desidera rimuovere le modifiche dello stash dall'albero di lavoro o git resetse si desidera semplicemente ripulire l'indice e lasciare che i conflitti nell'albero di lavoro vengano uniti manualmente.

Sotto man git stash ( OPZIONI, pop ) puoi leggere inoltre:

L'applicazione dello stato può fallire con i conflitti; in questo caso, non viene rimosso dall'elenco di stash. È necessario risolvere manualmente i conflitti e chiamare manualmente git stash drop in seguito.


9
In effetti, anche dopo aver lasciato cadere uno stash, è ancora possibile (anche se più difficile) recuperarlo di nuovo, perché il changeset esiste ancora nel repository. stackoverflow.com/search?q=git+recover+dropped+stash
Phils

3
@nalply: è buono o cattivo? Sei il benvenuto per migliorare la mia risposta, in cui non l'hai capita in primo luogo ...
tanascius,

1
Penso che la revisione del codice sorgente sia un dominio problematico complesso. È facile confondersi. Continuo a pensare che la tua risposta sia buona perché ha riconfermato il mio approccio.
nalply,

1
Non solo mi ha aiutato molto a capire che la scorta non è stata rimossa come avevo immaginato, ma questo spiega perché la mia scorta continuava a crescere anche quando ero certo di non aver dimenticato di recuperarla.
Thor84no,

11
"L'applicazione dello stato può fallire con i conflitti; in questo caso, non viene rimosso dall'elenco di stash." Questa è la parte più importante del post, secondo me. Considera di modificare la tua risposta per metterla in primo piano insieme alle parole NON FARE IL PANICO in lettere grandi e amichevoli. (+1 già però.) Grazie.
Patrick M,

42

Mi è successa una cosa simile. Non volevo ancora mettere in scena i file, quindi li ho aggiunti git adde poi ho fatto git reset. Fondamentalmente questo ha appena aggiunto e quindi messo in scena i miei cambiamenti, ma ha cancellato i percorsi non uniti.


4
Questo sembra essere meglio dell'uso reset --hardperché non sovrascrive i tuoi file (tranne quelli con problemi di unione). Grazie!
sinelaw,

Non volevo ancora mettere in scena i file, quindi li ho aggiunti - non mette in addscena il contenuto dall'albero di lavoro all'indice? Non credo di capire perché la tua risposta funzioni dalla descrizione.
Drew Noakes,

2
git addli mette in scena ma git reset, cosa che faccio subito dopo, li mette in scena. Essenzialmente cancella i percorsi non uniti e mi riporta al mio normale albero di lavoro falsificando git.
Aaron,

3
Non è necessario git addse hai intenzione di farlo git reset. L' git resetefficace "annulla" il git add. git reset( --mixed<- default) in effetti non tocca la directory di lavoro, quindi esattamente ciò che era nella directory di lavoro, unisci i conflitti e tutto, viene lasciato solo. L'indice (e tecnicamente la diramazione del ramo) viene reimpostato (senza un riferimento a cui vengono ripristinati HEAD, il che probabilmente significa nessuna modifica per la diramazione e annulla effettivamente qualsiasi git addoperazione sull'indice, oltre a cancellare lo stato dei percorsi non uniti) .
bambams,

3
La sequenza , modificare / risolutezza , git resete git stash dropfunziona bene. Fa quello che git stash popavrebbe fatto senza conflitti. Sembra che non git addsia necessario; anche se forse è utile, hai molti file con conflitti. Una volta risolti , possono essere aggiunti e ne git statustiene traccia.
rumore senza arti

13

Se, come me, quello che di solito vuoi è sovrascrivere il contenuto della directory di lavoro con quello dei file stash e hai ancora un conflitto, allora quello che vuoi è risolvere il conflitto usando git checkout --theirs -- .dalla radice.

Successivamente, è possibile git resetportare tutte le modifiche dall'indice alla directory di lavoro, poiché apparentemente in caso di conflitto le modifiche ai file non in conflitto rimangono nell'indice.

Potresti anche voler correre in git stash drop [<stash name>]seguito, per sbarazzarti dello stash, perché git stash popnon lo elimina in caso di conflitti.


2

Nota che Git 2.5 (2 ° trimestre 2015) un futuro Git potrebbe provare a rendere impossibile quello scenario.

Vedi commit ed178ef di Jeff King ( peff), 22 apr 2015.
(Unito da Junio ​​C Hamano - gitster- in commit 05c3967 , 19 maggio 2015)

Nota: questo è stato ripristinato. Vedi sotto .

stash: richiede un indice pulito da applicare / pop

Problema

Se hai messo in scena contenuti nel tuo indice ed eseguito " stash apply/pop", potremmo riscontrare un conflitto e inserire nuove voci nell'indice.
Ripristinare il tuo stato originale è difficile a quel punto, perché strumenti come "git reset --keep" spazzano via qualsiasi cosa messa in scena .

In altre parole:

" git stash pop/apply" dimenticato di assicurarsi che non solo l'albero di lavoro sia pulito, ma anche l'indice sia pulito.
Quest'ultimo è importante poiché un'applicazione stash può essere in conflitto e l'indice verrà utilizzato per la risoluzione dei conflitti.

Soluzione

Possiamo renderlo più sicuro rifiutandoci di applicare in caso di modifiche graduali.

Ciò significa che se vi fossero stati in precedenza fusioni a causa dell'applicazione di uno stash su file modificati (aggiunti ma non sottoposti a commit), ora non si verificherebbero alcun tipo di unione poiché lo stash apply / pop si fermerebbe immediatamente con:

Cannot apply stash: Your index contains uncommitted changes.

Obbligarti a eseguire il commit delle modifiche significa che, in caso di fusioni, puoi facilmente ripristinare lo stato iniziale (prima git stash apply/pop) con a git reset --hard.


Vedi commit 1937610 (15 giugno 2015) e commit ed178ef (22 aprile 2015) di Jeff King ( peff) .
(Unita da Junio ​​C Hamano - gitster- in commit bfb539b , 24 giu 2015)

Tale commit è stato un tentativo di migliorare la sicurezza dell'applicazione di uno stash, poiché il processo dell'applicazione potrebbe creare voci di indice in conflitto, dopodiché è difficile ripristinare lo stato dell'indice originale.

Sfortunatamente, ciò danneggia alcuni flussi di lavoro comuni " git stash -k", come:

git add -p       ;# (1) stage set of proposed changes
git stash -k     ;# (2) get rid of everything else
make test        ;# (3) make sure proposal is reasonable
git stash apply  ;# (4) restore original working tree

Se si "git commit" tra i passaggi (3) e (4), allora funziona. Tuttavia, se questi passaggi fanno parte di un hook pre-commit, non si ha questa opportunità (è necessario ripristinare lo stato originale indipendentemente dal fatto che i test siano stati superati o meno).

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.