rimuovere Stash un solo file di più file modificati con Git?




guida git pdf (22)

Quando git stash -p (o git add -p con stash --keep-index ) sarebbe troppo macchinoso, ho trovato più facile usare diff , checkout e apply :

Per "memorizzare" solo un file / dir particolare:

git diff path/to/dir > stashed.diff
git checkout path/to/dir

Quindi dopo

git apply stashed.diff

Come posso nascondere solo uno dei vari file modificati sul mio ramo?


Salvare il seguente codice in un file, ad esempio, denominato stash . L'utilizzo è stash <filename_regex> . L'argomento è l'espressione regolare per il percorso completo del file. Ad esempio, per riporre un / b / c.txt, stash a/b/c.txt o stash .*/c.txt , ecc.

$ chmod +x stash
$ stash .*.xml
$ stash xyz.xml

Codice da copiare nel file:

#! /usr/bin/expect --
log_user 0
set filename_regexp [lindex $argv 0]

spawn git stash -p

for {} 1 {} {
  expect {
    -re "diff --git a/($filename_regexp) " {
      set filename $expect_out(1,string)
    }
    "diff --git a/" {
      set filename ""
    }
    "Stash this hunk " {
      if {$filename == ""} {
        send "n\n"
      } else {
        send "a\n"
        send_user "$filename\n"
      }
    }
    "Stash deletion " {
      send "n\n"
    }
    eof {
      exit
    }
  }
}

Ogni risposta qui è così complicata ...

Che dire di questo per "riporre":

git diff /dir/to/file/file_to_stash > /tmp/stash.patch
git checkout -- /dir/to/file/file_to_stash

Questo per far saltare il file cambia:

git apply /tmp/stash.patch

Esatto stesso comportamento come la memorizzazione di un file e il suo inserimento di nuovo.


Diciamo che hai 3 file

a.rb
b.rb
c.rb

e vuoi mettere in archivio solo b.rb e c.rb ma non a.rb

puoi fare qualcosa di simile

# commit the files temporarily you don't want to stash
git add a.rb
git commit -m "temp" 

# then stash the other files
git stash save "stash message"

# then undo the previous temp commit
git reset --soft HEAD^
git reset

E hai finito! HTH.


Dato che git è fondamentalmente sulla gestione di un contenuto e di un indice di tutti i repository (e non di uno o più file), non sorprende con la directory di tutti i lavori .

In realtà, da Git 2.13 (2 ° trim. 2017), puoi archiviare singoli file, con git stash push :

git stash push [--] [<pathspec>...]

Quando viene assegnato pathspec a ' git stash push ', la nuova memoria registra gli stati modificati solo per i file che corrispondono al pathspec

Vedi " Stash changes to specifici files " per altro.

Il test case è auto-esplicativo:

test_expect_success 'stash with multiple pathspec arguments' '
    >foo &&
    >bar &&
    >extra &&
    git add foo bar extra &&

    git stash push -- foo bar &&   

    test_path_is_missing bar &&
    test_path_is_missing foo &&
    test_path_is_file extra &&

    git stash pop &&
    test_path_is_file foo &&
    test_path_is_file bar &&
    test_path_is_file extra

La risposta originale (di seguito, giugno 2010) riguardava la selezione manuale di ciò che si desidera memorizzare.

Commenti di Casebash :

Questa (la soluzione originale stash --patch ) è carina, ma spesso ho modificato molti file, quindi usare la patch è fastidioso

La answer bukzor (upvoted, novembre 2011) suggerisce una soluzione più pratica, basata su
git add + git stash --keep-index .
Vai a vedere e invertire la sua risposta, che dovrebbe essere quella ufficiale (invece della mia).

A proposito di questa opzione, chhh indica un flusso di lavoro alternativo nei commenti:

dovresti " git reset --soft " dopo una tale operazione per ottenere il tuo chiaro allestimento:
Per arrivare allo stato originale - che è una chiara area di staging e con solo alcune modifiche non programmate, è possibile ripristinare l'indice per ottenere (senza commettere nulla come te - ha fatto bukzor).

(Risposta originale giugno 2010: scorta manuale)

Eppure, git stash save --patch potrebbe permetterti di ottenere lo stashing parziale che stai git stash save --patch :

Con --patch , è possibile selezionare in modo interattivo gli hunk nella differenza tra HEAD e l'albero di lavoro da nascondere.
La voce stash è costruita in modo tale che lo stato dell'indice sia lo stesso dello stato dell'indice del repository e il suo worktree contenga solo le modifiche selezionate in modo interattivo. Le modifiche selezionate vengono quindi ripristinate dal tuo albero di lavoro.

Comunque questo salverà l'indice completo (che potrebbe non essere quello che vuoi dato che potrebbe includere altri file già indicizzati), e un albero di lavoro parziale (che potrebbe sembrare quello che vuoi mettere da parte).

git stash --patch --no-keep-index

potrebbe essere una misura migliore.

Se --patch non funziona, un processo manuale potrebbe:

Per uno o più file, una soluzione intermedia sarebbe:

  • copialo fuori dal repository Git
    (In realtà, eleotlecram propone un'interessante alternativa )
  • git stash
  • copiarli indietro
  • git stash # questa volta, solo i file che vuoi sono nascosti
  • git stash pop [email protected]{1} # applica nuovamente tutte le modifiche ai file
  • git checkout -- afile # resetta il file al contenuto HEAD, prima di qualsiasi modifica locale

Alla fine di questo processo piuttosto ingombrante, avrai solo uno o più file nascosti.


Quando si tenta di passare tra due rami, si verifica questa situazione.

Prova ad aggiungere i file usando " git add filepath ".

Successivamente esegui questa linea

git stash --keep-index


Situazione simile. Ha commesso e ha capito che non è ok.

git commit -a -m "message"
git log -p

Sulla base delle risposte questo mi ha aiutato.

# revert to previous state, keeping the files changed
git reset HEAD~
#make sure it's ok
git diff
git status
#revert the file we don't want to be within the commit
git checkout specs/nagios/nagios.spec
#make sure it's ok
git status
git diff
#now go ahead with commit
git commit -a -m "same|new message"
#eventually push tu remote
git push

Poiché la creazione di rami in Git è banale, è sufficiente creare un ramo temporaneo e controllare i singoli file in esso contenuti.


In questa situazione git add -p (interattivo), git commit -m blah e poi metto a posto ciò che rimane, se necessario.


Vorrei usare git stash save --patch . Non trovo l'interattività fastidiosa perché ci sono delle opzioni durante l'applicazione per applicare l'operazione desiderata a interi file.


Per memorizzare un singolo file usa git stash --patch [file] .

Questo richiederà: Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ? Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ? . Basta digitare a (riponi questo pezzo e tutti gli hunk successivi nel file) e stai bene.


Non so come farlo sulla riga di comando, usando solo SourceTree. Diciamo che hai cambiato il file A e hai due modifiche nel file B. Se vuoi mettere solo il secondo pezzo nel file B e lasciare tutto il resto intatto, fai questo:

  1. Metti in scena tutto
  2. Esegui le modifiche alla tua copia di lavoro che annullano tutte le modifiche nel file A. (ad esempio, avvia lo strumento di diffusione esterna e converti i file).
  3. Rendi il file B come se fosse applicato solo un secondo cambiamento. (ad esempio, avviare lo strumento di diffusione esterna e annullare la prima modifica.)
  4. Crea una scorta usando "Mantieni modifiche a fasi".
  5. Mettere in scena tutto
  6. Fatto!

Ho esaminato le risposte e i commenti per questo e un numero di thread simili. Tieni presente che nessuno dei seguenti comandi è corretto allo scopo di poter archiviare file specifici tracciati / non tracciati :

  • git stash -p (--patch) : seleziona manualmente hunk, esclusi i file non tracciati
  • git stash -k (--keep-index) : archivia tutti i file tracciati / non tracciati e li tiene nella directory di lavoro
  • git stash -u (--include-untracked) : archivia tutti i file tracciati / non tracciati
  • git stash -p (--patch) -u (--include-untracked) : comando non valido

Attualmente, il metodo più ragionevole per essere in grado di memorizzare qualsiasi file tracciato / non tracciato specifico è:

  • Impegna temporaneamente i file che non desideri memorizzare
  • Aggiungi e conserva
  • Inserisci il commit temporaneo

Ho scritto un semplice script per questa procedura in una risposta ad un'altra domanda , e qui ci sono dei passaggi per eseguire la procedura in SourceTree .


Il problema con la soluzione "intermedia" di VonC di copiare i file all'esterno del repository Git è che si perdono le informazioni sul percorso, il che rende la copia di un gruppo di file in un secondo momento piuttosto complicata.

A trovare più facile usare tar (strumenti simili probabilmente lo faranno) invece di copiare:

  • tar cvf /tmp/stash.tar percorso / a / alcuni / percorso file / a / alcuni / altro / file (... ecc.)
  • git checkout path / to / some / file path / to / some / other / file
  • git stash
  • tar xvf /tmp/stash.tar
  • ecc. (vedi il suggerimento "intermedio" di VonC)

Usa git stash push , come questo:

git stash push [--] [<pathspec>...]

Per esempio:

git stash push -- my/file.sh

Disponibile da Git 2.13, rilasciato nella primavera 2017.


A volte ho apportato una modifica non correlata al ramo prima di eseguirlo e voglio spostarlo su un altro ramo e eseguirlo separatamente (come master). Lo faccio:

git stash
git checkout master
git stash pop
git add <files that you want to commit>
git commit -m 'Minor feature'
git stash
git checkout topic1
git stash pop
...<resume work>...

Nota che il primo stash pop stash & stash pop può essere eliminato, puoi portare tutte le tue modifiche al ramo master quando fai il checkout, ma solo se non ci sono conflitti. Inoltre, se stai creando un nuovo ramo per le modifiche parziali, ti servirà lo stash.

Puoi semplificarlo assumendo conflitti e nessun nuovo ramo:

git checkout master
git add <files that you want to commit>
git commit -m 'Minor feature'
git checkout topic1
...<resume work>...

Stash non aveva nemmeno bisogno ...


Un modo complicato sarebbe di commettere prima tutto:

git add -u
git commit // creates commit with sha-1 A

Ripristina il commit originale ma checkout the_one_file dal nuovo commit:

git reset --hard HEAD^
git checkout A path/to/the_one_file

Ora puoi nascondere the_one_file:

git stash

Pulisci salvando il contenuto impegnato nel tuo file system mentre resetti al commit originale:

git reset --hard A
git reset --soft HEAD^

Sì, un po 'imbarazzante ...


git add .                           //stage all the files
git reset <pathToFileWillBeStashed> //unstage file which will be stashed
git stash                           //stash the file(s)
git reset .                         // unstage all staged files
git stash pop                       // unstash file(s)

avvertimento

Come notato nei commenti, questo mette tutto nella scorta, sia messa in scena che non. --Keep-index lascia solo l'indice dopo che è stato eseguito lo stash. Ciò può causare conflitti di unione quando si apre la scorta.

Questo immagazzinerà tutto ciò che non hai precedentemente aggiunto. Basta git add le cose che vuoi mantenere, quindi eseguirlo.

git stash --keep-index

Ad esempio, se si desidera dividere un vecchio commit in più di un changeset, è possibile utilizzare questa procedura:

  1. git rebase -i <last good commit>
  2. Contrassegna alcune modifiche come edit .
  3. git reset HEAD^
  4. git add <files you want to keep in this change>
  5. git stash --keep-index
  6. Risolvi le cose se necessario. Non dimenticare di git add modifiche.
  7. git commit
  8. git stash pop
  9. Ripeti, dal n. 5, se necessario.
  10. git rebase --continue

Puoi anche usare git stash save -p "my commit message" . In questo modo puoi selezionare quali hunk devono essere aggiunti alla stash, anche interi file possono essere selezionati.

Ti verrà richiesto un paio di azioni per ogni hunk:

   y - stash this hunk
   n - do not stash this hunk
   q - quit; do not stash this hunk or any of the remaining ones
   a - stash this hunk and all later hunks in the file
   d - do not stash this hunk or any of the later hunks in the file
   g - select a hunk to go to
   / - search for a hunk matching the given regex
   j - leave this hunk undecided, see next undecided hunk
   J - leave this hunk undecided, see next hunk
   k - leave this hunk undecided, see previous undecided hunk
   K - leave this hunk undecided, see previous hunk
   s - split the current hunk into smaller hunks
   e - manually edit the current hunk
   ? - print help

Questo può essere fatto facilmente in 3 passaggi utilizzando SourceTree.

  1. Impegna temporaneamente tutto ciò che non vuoi nascosto.
  2. Git aggiungi tutto il resto, quindi nascondilo.
  3. Inserisci il tuo commit temporaneo eseguendo git reset, mirando al commit prima del tuo temporaneo.

Tutto questo può essere fatto in pochi secondi in SourceTree, dove puoi semplicemente fare clic sui file (o anche sulle singole linee) che vuoi aggiungere. Una volta aggiunti, basta impegnarli in un commit temporaneo. Quindi, fai clic sulla casella di controllo per aggiungere tutte le modifiche, quindi fai clic su nascondi per nascondere tutto. Con le modifiche nascoste, getta uno sguardo alla tua lista di commit e annota l'hash per il commit prima del commit temporaneo, quindi esegui 'git reset hash_b4_temp_commit', che è fondamentalmente come "scoppiare" il commit reimpostando il tuo ramo sul impegnarsi proprio prima. Ora, sei rimasto solo con le cose che non volevi nascondere.


Non ho trovato nessuna risposta per essere quello di cui avevo bisogno e questo è facile come:

git add -A
git reset HEAD fileThatYouWantToStash
git commit -m "committing all but one file"
git stash

Questo contiene esattamente un file.





git-stash