Come risolvere il conflitto di git stash senza commit?


495

Come richiesto in questa domanda , voglio anche sapere come risolvere un conflitto git stash popsenza aggiungere tutte le modifiche a un commit (proprio come fa "git stash pop" senza un conflitto).

Il mio approccio attuale è molto freddo perché lo faccio in questo modo:

git stash pop -> CONFLICT
git stash drop
[resolve conflict]
[add conflict files]
git reset HEAD <all files that are in commit-mode>

[Aggiornamento] Un modo per riprodurlo:

mkdir foo; cd foo; git init
echo "1" > one
echo "2" > two
git add -A; git commit -m "first"
echo "1.1" > one
echo "2.1" > two
git stash
echo "2.2" > two
git commit -a -m "second"
echo "Only this file would stay in HEAD without the conflict" > third
git add third
git stash pop
git status

27/06/2016: Aggiunto un nuovo file chiamato 'terzo' all'esempio per mostrare che soluzioni alternative come la soluzione di scy funzionano solo per HEAD vuoti ma non risolvono il problema iniziale che HEAD non ha lo stesso contenuto come per un git stash popsenza conflitto.


Quindi i git addtuoi file di conflitto risolti, mettendoli in scena efficacemente nell'indice e vorresti non averli nel nostro indice?
Romain,

Sì, è giusto. Voglio solo il comportamento che git stash popha quando non si verifica alcun conflitto (ma con notifica quali file devono essere uniti).
Sven,

2
Sembra che la risposta sia qui: stackoverflow.com/questions/3945826/git-stash-questions . Nella risposta scelta, al 4 ° commento, Adam spiega perché Git fa questo.
Patrick,

@Patrick Grazie per queste informazioni - quindi sembra che non ci sarà alcuna soluzione disponibile perché è "di progettazione"
Sven

Risposte:


510

Non seguire altre risposte

Bene, puoi seguirli :). Ma non penso che fare un commit e quindi reimpostare il ramo per rimuovere quel commit e soluzioni alternative simili suggerite in altre risposte sia il modo pulito per risolvere questo problema.

Soluzione pulita

La seguente soluzione sembra essere molto più pulita per me ed è anche suggerita dallo stesso Git : prova a eseguire git statusnel repository un conflitto:

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

Quindi facciamo ciò che Git suggerisce (senza fare inutili commit):

  1. Manualmente (o usando alcuni strumenti di unione , vedi sotto) risolvi i conflitti.
  2. Utilizzare git resetper contrassegnare i conflitti come risolti e annullare la messa in scena delle modifiche. Puoi eseguirlo senza parametri e Git rimuoverà tutto dall'indice. Non devi eseguire git addprima.
  3. Infine, rimuovi la scorta con git stash drop, perché Git non lo fa in caso di conflitto.

Tradotto nella riga di comando:

$ git stash pop

# ...resolve conflict(s)

$ git reset

$ git stash drop

Spiegazione del comportamento predefinito

Esistono due modi per contrassegnare i conflitti come risolti: git adde git reset. Mentre git resetcontrassegna i conflitti come risolti e rimuove i file dall'indice, git addcontrassegna anche i conflitti come risolti, ma mantiene i file nell'indice.

L'aggiunta di file all'indice dopo la risoluzione di un conflitto è intenzionale. In questo modo è possibile differenziare le modifiche dalla scorta precedente e le modifiche apportate dopo la risoluzione del conflitto. Se non ti piace, puoi sempre utilizzare git resetper rimuovere tutto dall'indice.

Unisci strumenti

Consiglio vivamente di utilizzare uno qualsiasi degli strumenti di unione a 3 vie per risolvere i conflitti, ad esempio KDiff3 , Meld , ecc., Invece di farlo manualmente. Solitamente risolve automaticamente tutti o la maggior parte dei conflitti. È un enorme risparmio di tempo!


32
@kamalpal sembra essere necessario quando git stash popfallisce con i conflitti.
Emile Bergeron,

21
@kamalpal sì, Git ti avvisa persino che lo stash non è stato lasciato cadere in caso di conflitto. E la domanda riguardava questo caso, quindi è davvero necessario eseguire agit stash drop meno che non si desideri mantenere quella scorta.
David Ferenczy Rogožan,

@ DavidFerenczyRogožan Git non mi ha notificato affatto che non ha lasciato cadere la voce stash. Versione 2.17.1 qui.
Robert Siemer,

298

Supponiamo di avere questo scenario in cui riponi le modifiche per estrarre dall'origine. Forse perché le modifiche locali sono solo debug: truein alcuni file delle impostazioni. Ora tiri e qualcuno ha introdotto una nuova impostazione lì, creando un conflitto.

git status dice:

# On branch master
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#   both modified:      src/js/globals.tpl.js
no changes added to commit (use "git add" and/or "git commit -a")

Va bene. Ho deciso di seguire ciò che Git ha suggerito: ho risolto il conflitto e mi sono impegnato:

vim src/js/globals.tpl.js
# type type type …
git commit -a -m WIP   # (short for "work in progress")

Ora la mia copia di lavoro è nello stato desiderato, ma ho creato un commit che non voglio avere. Come posso eliminare questo commit senza modificare la mia copia di lavoro? Aspetta, c'è un comando popolare per quello!

git reset HEAD^

La mia copia di lavoro non è stata modificata, ma il commit WIP è sparito. Questo è esattamente quello che volevo! (Nota che non sto usando --softqui, perché se ci sono file uniti automaticamente nella tua scorta, vengono messi in scena automaticamente e quindi finiresti con questi file di nuovo in scena dopo reset.)

Ma c'è ancora un'altra cosa: la pagina di git stash popmanuale ci ricorda che "L'applicazione dello stato può fallire con i conflitti; in questo caso, non viene rimosso dall'elenco di stash. È necessario risolvere i conflitti a mano e chiamare git stash dropmanualmente in seguito". Quindi è esattamente quello che facciamo ora:

git stash drop

E fatto.


34
C'è solo molta bruttezza ereditaria nel dover deliberatamente eseguire il reset reset HEAD ^ ... per qualcosa che dovrebbe influenzare solo l'albero di lavoro.

6
Perché non solo risolvere i conflitti e poi git add <resolved conflict files>seguito da git reset HEAD?
BoltzmannBrain,

Grazie per il suggerimento, ma questo non risolve il problema iniziale che questo non è lo stesso comportamento come git stash popsenza un conflitto. Basta aggiungere un altro file a HEAD prima di eseguire il conflitto git stash pope git commit -a -m WIPquindi aggiungerebbe anche il nuovo file al commit. Ma senza un conflitto, solo il nuovo file rimarrebbe in HEAD ma non i git stash popfile.
Sven,

7
Non credo sia necessario prima impegnarsi e poi annullare il commit. La semplice reimpostazione dalla risposta di Dawid Ferenczy farà lo stesso
vladkras il

3
Per gli utenti di Windows, ^viene utilizzato come continuazione di riga speciale e ti lascerà seduto ad un Altro? prompt invece di eseguire il comando. Invece utilizzare: git reset --soft HEAD~1. Vedi how-do-i-delete-unpushed-git-commit?
mrfelis,

87

Invece di aggiungere le modifiche apportate per risolvere il conflitto, è possibile utilizzare git reset HEAD fileper risolvere il conflitto senza mettere in scena le modifiche.

Tuttavia, potrebbe essere necessario eseguire questo comando due volte. Una volta per contrassegnare il conflitto come risolto e una volta per mettere in scena le modifiche messe in scena dalla routine di risoluzione del conflitto.

È possibile che ci sia una modalità di ripristino che fa entrambe queste cose contemporaneamente, sebbene non ce ne sia una adesso.


2
La modalità di ripristino è quella che cerco - altre soluzioni alternative sono come quella che ho descritto e non sono pratiche per più di 5 file.
Sven,

25
E poi usa "git stash drop" per finire "git stash pop".
David Liu,

2
Sebbene la domanda non lo richieda esplicitamente, potrebbe essere utile aggiornare la risposta per includere "git stash drop" poiché lo stash non viene eliminato automaticamente in caso di conflitto.
Abhishek Pathak,

29
git checkout stash -- .

ha funzionato per me.

Nota : questo può essere pericoloso poiché non tenta di unire le modifiche dallo stash alla copia di lavoro, ma invece lo sovrascrive con i file stash . Quindi puoi perdere le modifiche senza commit.


Questo ha aiutato quando "git pull --autostash" introduce commit merge indesiderati e git checkout stash -. sovrascrive incondizionatamente i conflitti dalla scorta
Alec Istomin il

11
git add .
git reset

git add . metterà in scena TUTTI i file dicendo a git che hai risolto il conflitto

git reset annullerà la messa in scena di TUTTI i file in scena senza creare un commit


Questa in realtà non è una cattiva risposta, è praticamente come git add -ualloragit reset
ebob il

4

Sembra che questa potrebbe essere la risposta che stai cercando, non l'ho ancora provata personalmente, ma sembra che potrebbe fare il trucco. Con questo comando GIT proverà ad applicare le modifiche come erano prima, senza provare ad aggiungerle tutte per il commit.

git stash apply --index

ecco la spiegazione completa:

http://git-scm.com/book/en/Git-Tools-Stashing


Grazie per questo suggerimento, ma questo non aiuterà quando l'ho già fatto git stash pop- o c'è un modo per ripristinare questo e da fare git stash apply --indexquando ho scoperto che si git stash popverificherà un conflitto?
Sven

Ho aggiunto un esempio su come produrlo: immagina di modificare più di 10 file, quindi non sai quale di essi hai modificato al di fuori dello stash.
Sven

3
Se guardi in fondo a questo post QUI , dice che se corri git stash pope finisce con dei conflitti, lo stash non viene rimosso ... quindi puoi correre git reset --hardper annullare il pop e quindi provare la soluzione che ho suggerito.
Marco Ponti,

Ho appena provato questo e non funziona dopo che hai un file in stato di conflitto. Anche se risolvi il conflitto manualmente.
Sam3k,

2

git stash branchwill works, che crea un nuovo ramo per te, verifica il commit che hai svolto quando hai nascosto il tuo lavoro, riapplica il tuo lavoro lì e quindi rilascia lo stash se si applica correttamente. controlla questo


2

Il modo più veloce che ho trovato è quello di risolvere il conflitto, quindi fare git add -u, e poi fare git reset HEAD, che non comporta nemmeno un commit.


1

Secondo le domande di git stash , dopo aver risolto il conflitto,git add <file> è la scelta giusta.

È stato dopo aver letto questo commento che ho capito che le modifiche vengono automaticamente aggiunte all'indice (in base alla progettazione). Ecco perché git add <file>completa il processo di risoluzione dei conflitti.


-1

Non è il modo migliore per farlo ma funziona:

$ git stash apply
$ >> resolve your conflict <<
$ >> do what you want to do with your code <<
$ git checkout HEAD -- file/path/to/your/file

questa risposta mi sembra del tutto errata, poiché eliminerebbe tutte le modifiche file/path/to/your/file, il che non è quello che l'OP ha chiesto, AFAIU
oromoiluig,
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.