Nascondere solo le modifiche non programmate in Git


246

Vorrei fare il seguente flusso di lavoro:

  1. Aggiungi modifiche allo stage.
  2. Metti da parte tutte le altre modifiche che non sono state messe in scena.
  3. Fare alcune cose con le cose in fase (cioè costruire, eseguire test, ecc.)
  4. Applica la scorta.

C'è un modo per eseguire il passaggio 2?

Esempio

 echo "123" > foo
 git add foo # Assumes this is a git directory
 echo "456" >> foo
 git stash
 cat foo # Should yield 123

Perché non eseguire il commit delle modifiche dopo averle messe in scena?
Shizzmo

3
IIRC --keepindex fa esattamente questo
vedi il

4
Perché se, diciamo, la build fallisce, non voglio avere un commit di questo. So di poter eliminare il commit ma vorrei farlo senza un commit, se possibile.
Unapiedra

Sehe, grazie. Posso confermare che funziona. Accidenti, ho guardato il manuale su linux.die.net/man/1/git-stash che non è aggiornato. man git stashè molto meglio.
Unapiedra

è --keep-index, fwiw.
jaf0

Risposte:


306

git stash saveha un'opzione --keep-indexche fa esattamente ciò di cui hai bisogno.

Quindi corri git stash save --keep-index.


9
Vero. Continuo a usare savecon git stash. Forse è il programmatore in me che insiste a onorare la simmetria con apply / pop. :)
vhallac

114
Nota: questo conserva ancora tutte le modifiche; l'unica differenza dal normale git stash saveè che lascia anche le modifiche già organizzate nella tua copia di lavoro. Nel flusso di lavoro sopra questo funzionerebbe bene poiché stai solo applicando lo stash sopra una copia locale che ha già la metà delle modifiche dello stash (che git è abbastanza intelligente da ignorare). Ma se modifichi il codice prima di riapplicare lo stash, potresti potenzialmente vedere conflitti di unione quando vai ad applicare. Fyi.
peterflynn

2
@ytpete che mi ha morso così tante volte. Vorrei davvero che ci fosse un modo per git di mettere da parte solo le cose che non conservi ... Spesso metto a posto cose, poi faccio una scorta completa di git, sapendo che posso git commit --ammendse ci sono problemi in quello che ho commesso.
rjmunro

22
Questa soluzione non funziona per me a causa dei problemi descritti da peterflynn. Non è una buona risposta alla domanda poiché nasconde ancora le modifiche in scena. Qualcuno ha una soluzione migliore?
user643011

3
I documenti sembrano dire che stash saveora è deprecato: "Questa opzione è deprecata a favore di git stash push. Si differenzia da" stash push "in quanto non può accettare pathspec e qualsiasi argomento non opzionale forma il messaggio."
jocull

45

Questo può essere fatto in 3 passaggi: salva le modifiche a fasi, stash tutto il resto, ripristina l'indice con modifiche a fasi. Che è fondamentalmente:

git commit -m 'Save index'
git stash push -u -m 'Unstaged changes and untracked files'
git reset --soft HEAD^

Questo farà esattamente quello che vuoi.


3
Nota: -unasconde anche i file non tracciati.
ma11hew28

Questo approccio essenzialmente duplica ciò che git stash save --keep-indexfa con molto più lavoro. Non vedo alcun vantaggio.
Inigo

3
@vas No, l'approccio non lo duplica. Vedi il commento di peterflynn alla risposta accettata.
Alexander Klauer il

27
git stash save --keep-index

Inoltre, Re:

Perché non eseguire il commit delle modifiche dopo averle messe in scena? - Stinco

A: Perché dovresti sempre controllare il codice testato :) Ciò significa che devi eseguire i test con solo le modifiche che stai per eseguire

Tutto questo a parte il fatto che, naturalmente, come programmatore esperto, hai l'urgenza innata di testare e rivedere solo quei cambiamenti - solo in parte scherzando


15

Con git version 2.7.4te puoi fare:

git stash save --patch

Il gitchiederà di aggiungere o meno le modifiche in scorta.
E poi rispondi yon

Puoi ripristinare la directory di lavoro come fai sempre:

git stash pop

oppure, se vuoi mantenere le modifiche salvate nella stash:

git stash apply

Questo e spettacolare. È un po 'laborioso, ma almeno puoi saltare e aggiungere interi file.
Dustin Oprea

10

Nascondere solo l'albero di lavoro (modifiche non programmate) in Git è più difficile di quanto dovrebbe essere. La risposta accettata nasconde le modifiche non in scena, ma anche le modifiche in scena (e le lascia anche in scena), che raramente è ciò che desideri.

Questo alias funziona bene:

stash-working = "!f() { \
  git commit --quiet -m \"temp for stash-working\" && \
  git stash push \"$@\" && \
  git reset --quiet --soft HEAD~1; }; f"

Esegue il commit delle modifiche temporanee, crea uno stash dalle modifiche rimanenti (e consente di passare argomenti aggiuntivi come --include-untrackede --messagecome argomenti alias), quindi reimposta il commit temporaneo per ripristinare le modifiche temporanee.

E 'simile a quella di @Simon Knapp risposta , ma con alcune piccole differenze - si utilizza --quietsulle azioni temporanee indicate, e accetta qualsiasi numero di parametri per la scorta push, piuttosto che hard-codifica la -m, e lo fa aggiungere--soft alla finale reimpostare in modo che l'indice rimanga come è iniziato.

Per il problema opposto di nascondere solo le modifiche graduali (alias stash-index) vedere questa risposta .


5

Per aggiungere i file non archiviati (non aggiunti al commit) allo stash, eseguire il comando seguente:

git stash -k

Se desideri includere i file appena aggiunti (che non sono organizzati in fasi, non in verde) anche nella scorta, procedi come segue:

git stash -k -u

Quindi puoi eseguire il commit dei file staged. Dopodiché puoi recuperare gli ultimi file nascosti usando il comando:

git stash pop

4

Estendendo le risposte precedenti, a volte ho una serie complessa di modifiche organizzate, ma desidero prima eseguire una modifica separata. Ad esempio, potrei aver individuato un bug o un codice altrimenti errato che vorrei correggere prima delle modifiche in fasi. Una possibile strada da prendere è questa:

prima riponi tutto, ma lascia intatte le modifiche messe in scena

$ git stash save --keep-index [--include-untracked]

ora riponi separatamente anche le modifiche messe in scena

$ git stash save

apportare modifiche per la correzione; e prova; impegnali:

$ git add [--interactive] [--patch]

$ git commit -m "aggiusta ..."

ora ripristina le modifiche messe in scena in precedenza:

$ git stash pop

risolvere eventuali conflitti e notare che se c'erano conflitti, git avrà applicato ma non eliminato quella voce di stash superiore.

(... Quindi eseguire il commit delle modifiche in fasi e ripristinare la scorta di tutte le altre modifiche e continuare ...)


4

Git non dispone di un comando che memorizza solo le modifiche non organizzate.

Git, tuttavia, ti consente di specificare quali file vuoi mettere da parte.

git stash push --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

Se desideri archiviare solo modifiche specifiche in quei file, aggiungi l' --patchopzione.

git stash push --patch --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

L' --include-untrackedopzione ti consente di riporre i file non tracciati.

git stash push --include-untracked --message 'Untracked files' -- app/controllers/widgets_controller.rb test/controllers/widgets_controller_test.rb

Esegui git help stash(o man git-stash) per maggiori informazioni.

Nota: se le modifiche non organizzate sono piuttosto disoganizzate, la risposta di @ alesguzik è probabilmente più semplice.


2

Un altro suggerimento, relativo alla domanda:

Quando riponi in modo efficace le modifiche non organizzate utilizzando

$ git stash save --keep-index

potresti voler dare un messaggio alla scorta, in modo che quando fai una git stash listè più ovvio cosa hai nascosto prima, specialmente se segui quell'operazione di scorta con ulteriori salvataggi. Per esempio

$ git stash save --keep-index "modifiche non ancora messe in scena"

(sebbene in realtà contenga tutte le modifiche come indicato in altre risposte).

Ad esempio, quanto sopra potrebbe essere seguito immediatamente da:

$ git stash save "modifiche graduali per la funzione X"

Attenzione, però, che non puoi usare

$ git stash apply "stash @ {1}" ### ✘ non fa proprio quello che potresti desiderare

per ripristinare solo le modifiche non programmate.


2

Uso un alias, che accetta una stringa da utilizzare come messaggio per la voce stash.

mystash = "!f() { git commit -m hold && git stash push -m \"$1\" && git reset HEAD^; }; f"

Quale:

  • esegue il commit di tutto nell'indice,
  • nasconde ciò che è cambiato nell'albero di lavoro (potrebbe ovviamente aggiungere -uo-a ),
  • ripristina l'ultimo commit al tentativo di lavoro (potrebbe essere necessario utilizzarlo --softper mantenerlo nell'indice).

0

La forma moderna di quel comando è git stash push [--] [<pathspec>...], poiché Git 2.16+ ( git stash saveè deprecato )

Puoi combinarlo con un formato jolly, ad esempio:

git stash push --all --keep-index ':(glob)**/*.testextension' 

Ma questo non funziona bene con Git per Windows, fino a Git 2.22 (Q2 2019), vedere il numero 2037 , considerando che git stashè stato reimplementato in C (invece di uno script di shell)

Vedere il commit 7db9302 (11 marzo 2019) di Thomas Gummerer ( tgummerer) .
Vedere commit 1366c78 , commit 7b556aa (07 marzo 2019) di Johannes Schindelin ( dscho) .
(Fuso da Junio ​​C Hamano - gitster- in commit 0ba1ba4 , 22 aprile 2019)

built-in stash: gestisce :(glob)nuovamente pathspecs

Quando si passa un elenco di pathspec, diciamo, git adddobbiamo stare attenti a usare il modulo originale, non il formato analizzato di pathspecs.

Questo fa la differenza, ad esempio, quando si chiama

git stash -- ':(glob)**/*.txt'

dove il modulo originale include il :(glob)prefisso mentre il modulo analizzato no.

Tuttavia, nel built-in git stash, abbiamo passato il modulo analizzato (cioè errato) e git addnon riusciremmo con il messaggio di errore:

fatal: pathspec '**/*.txt' did not match any files

nella fase in cui git stashrilascia le modifiche dall'albero di lavoro, anche se refs/stashè stato effettivamente aggiornato con successo.

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.