Come unire le mie modifiche locali senza commit in un altro ramo Git?


621

Come posso fare quanto segue in Git?

La mia filiale attuale è branch1 e ho apportato alcune modifiche locali. Tuttavia, ora mi rendo conto che in realtà intendevo applicare queste modifiche a branch2. C'è un modo per applicare / unire queste modifiche in modo che diventino modifiche locali su branch2 senza impegnarle su branch1?


2
C'è un ottimo tutorial Git proprio qui su SO. È un po 'centrale per tutte le domande git su overflow dello stack.
Decio Lira,

Risposte:


898

Poiché i tuoi file non sono ancora impegnati in branch1:

git stash
git checkout branch2
git stash pop

o

git stash
git checkout branch2
git stash list       # to check the various stash made in different branch
git stash apply x    # to select the right one

Come commentato da benjohn (vedi la git stashpagina man ):

Per nascondere anche i file attualmente non tracciati (aggiunti di recente), aggiungi l'argomento -u, quindi:

git stash -u

2
Prego. Altri esempi di utilizzo degli stash su unethicalblogger.com/posts/2008/11/… .
VonC,

2
Se stai cercando una soluzione allo stesso problema, ma con TFS, la soluzione equivalente è quella di archiviare le modifiche, quindi utilizzare TFS Power Tools per rimuovere dal ramo corretto utilizzando l'opzione / migrate.
xr280xr,

1
Questo ha funzionato per me. Tuttavia, ho anche dovuto creare un ramo locale affinché lo "stash pop" funzionasse. Controlla stackoverflow.com/questions/1783405/git-checkout-remote-branch se ti succede qualcosa di simile.
mimoralea,

21
Per riporre anche i file attualmente non monitorate (appena aggiunti) , aggiungere l'argomento -u, in modo da: git stash -u.
Benjohn,

2
@Benjohn Un buon punto. Ho incluso il tuo commento nella risposta per una maggiore visibilità.
VonC,

84

Lo stashing, i commit temporanei e il rebasing possono essere eccessivi. Se non hai ancora aggiunto i file modificati all'indice, allora potresti essere in grado di controllare solo l'altro ramo.

git checkout branch2

Funzionerà finché nessun file che stai modificando è diverso tra branch1 e branch2. Ti lascerà su branch2 con le modifiche funzionanti conservate. Se sono diversi, è possibile specificare che si desidera unire le modifiche locali con le modifiche introdotte passando da rami a-m opzione per il checkout.

git checkout -m branch2

Se hai aggiunto modifiche all'indice, ti consigliamo di annullare prima queste modifiche. (Ciò manterrà la tua copia di lavoro, rimuoverà solo le modifiche graduali).

git reset

3
Ho pensato che lo stash fosse "più semplice" in qualche modo da capire, ma il tuo approccio è migliore nel prendere in considerazione la directory di lavoro tra i diversi rami. +1
VonC,

6
Un semplice checkout tradizionale sembrava più appropriato al problema in questione. il checkout è più leggero, aggiorna solo i file che devono essere modificati. Forse è più facile capire l'approccio stash, o può essere che non sia abbastanza ovvio che il checkout sia "sicuro" in questo caso d'uso.
CB Bailey,

Se checkout -mnon è "sicuro" in alcune situazioni (forse causerebbe un conflitto di unione), lo stash fornirebbe qualche vantaggio (ad esempio puoi aprire un pop stash)?
Craig McQueen,

1
@craigMcQueen Non puoi sbloccare uno stash spuntato ma lo stash si lamenterebbe dei conflitti quando lo pop. È possibile correggere i conflitti e quindi eseguire il commit, ma in questo caso lo stack originale è ancora nello stack! :)
Shaun F

In caso di conflitto di unione, non è stato eseguito il backup dei file come .orig?
jocull

13

Un'alternativa più breve all'approccio stash precedentemente menzionato sarebbe:

Sposta temporaneamente le modifiche in uno stash.

  1. git stash

Crea e passa a un nuovo ramo e poi pop lo stash ad esso in un solo passaggio.

  1. git stash branch new_branch_name

Quindi solo adde commitle modifiche a questo nuovo ramo.


10

ATTENZIONE: Non per i neofiti di Git.

Questo risulta abbastanza nel mio flusso di lavoro che ho quasi provato a scrivere un nuovo comando git per questo. Il solito git stashflusso è la strada da percorrere ma è un po 'imbarazzante. Di solito eseguo un nuovo commit in primo luogo poiché se ho esaminato le modifiche, tutte le informazioni sono fresche nella mia mente ed è meglio iniziare solo git commitquello che ho trovato (di solito un bugfix appartenente al master che scopro mentre lavoro su un ramo funzione) subito.

È anche utile, se ti imbatti in situazioni come questa, avere un'altra directory di lavoro accanto a quella corrente che ha sempre masterverificato il ramo.

Quindi, come ottengo questo, va così:

  1. git commit le modifiche subito con un buon messaggio di commit.
  2. git reset HEAD~1 per annullare il commit dal ramo corrente.
  3. (facoltativo) continua a lavorare sulla funzione.

A volte più tardi (in modo asincrono) o immediatamente in un'altra finestra del terminale:

  1. cd my-project-master che è un altro WD che condivide lo stesso .git
  2. git reflog per trovare la correzione che ho appena fatto.
  3. git cherry-pick SHA1 del commit.

Facoltativamente (ancora asincrono) è quindi possibile rifare nuovamente (o unire) il ramo della funzione per ottenere la correzione dei bug, di solito quando si sta per inviare un PR e aver già pulito il ramo della funzione e WD:

  1. cd my-project che è il principale WD a cui sto lavorando.
  2. git rebase master per ottenere le correzioni dei bug.

In questo modo posso continuare a lavorare sulla funzione ininterrotta e non git stashdovermi preoccupare di fare nulla o dover ripulire il mio WD prima di un git checkout(e quindi avere di nuovo il controllo del backout del ramo della funzione.) E avere ancora tutti i miei bugfixes masterinvece di nascosto nel mio ramo delle funzionalità.

IMO git stashed git checkoutè una vera PIA quando sei nel bel mezzo di lavorare su alcune grandi funzionalità.


Alternativa interessante e valida alla mia risposta. +1
VonC,

Vieni da Mercurial? La my-project-mastercondivisione dello stesso lo .gitfa sembrare simile. Perché non git checkout -b bugfixABC; git commit -a; git reset HEAD^ --hard, poi più tardi (in modo asincrono) mentre su master, git cherry-pick <SHA1 of the commit(s) in bugfixABC? (o anche, per evitare di dover scoprire lo SHA1, git rebase --onto master feature bugfixABCda qualunque ramo tu sia attualmente. Ciò significa che puoi farlo direttamente dopo quanto git resetsopra, mentre sei attivo feature.)
Gauthier

Tuttavia, OP sembra che non siano pronti a eseguire il commit delle modifiche, in tal caso checkout -mè semplicemente meglio.
Gauthier,

2

Se si tratta di modifiche impegnate, dovresti dare un'occhiata a git-rebase, ma come sottolineato nel commento di VonC, mentre stai parlando di cambiamenti locali, git-stash sarebbe sicuramente il buon modo per farlo.


Non capisco questa soluzione: riscriverebbe la cronologia di commit di branch2 da branch1 ... perché ottenere tutte le modifiche impegnate da branch1 in branch2 quando vogliamo ottenere solo modifiche locali non commit di branch1 in branch2? ...
VonC

@VonC: concordato, in questo caso, il rebase ottiene tutte le modifiche impegnate dall'ultima fusione tra filiali in branch1. All'inizio non ho ricevuto il parametro "non impegnato" di questa domanda. rebase non è la buona risposta.
clap

@claferri: pfew ... Stavo iniziando ad avere mal di testa;) Avrei declassato la tua risposta, ma da quando ne avevo pubblicato uno, c'era un "chiaro conflitto di interessi". Con il tuo post aggiornato, non devo minimizzare affatto adesso. Grazie :)
VonC,

@VonC: la prossima volta, sentiti libero di votare fino a quando la mia risposta è sbagliata come questa;)
claf

1

Le risposte fornite finora non sono ideali perché richiedono molto lavoro inutile per risolvere i conflitti di unione o fanno troppe ipotesi che sono spesso false. Ecco come farlo perfettamente. Il link è al mio sito.

Come impegnarsi in un altro ramo in git

Hai apportato modifiche non impegnate su my_branchcui vuoi impegnarti master, senza eseguire tutte le modifichemy_branch .

Esempio

git merge master
git stash -u
git checkout master
git stash apply
git reset
git add example.js
git commit
git checkout .
git clean -f -d
git checkout my_branch
git merge master
git stash pop

Spiegazione

Inizia unendoti masteral tuo ramo, poiché alla fine dovrai farlo comunque, e ora è il momento migliore per risolvere eventuali conflitti.

L' -uopzione (aka --include-untracked) git stash -uti impedisce di perdere file non tracciati quando successivamente lo fai git clean -f -dall'interno master.

Dopo git checkout masterè importante che NON lo faccia git stash pop, perché in seguito avrai bisogno di questa scorta. Se si pop la scorta creata in my_branche poi fare git stashin master, che riuscirai a causare inutili conflitti di unione quando più tardi si applicare tale scorta a my_branch.

git resetrimuove in scena tutto ciò che risulta da git stash apply. Ad esempio, i file che sono stati modificati nello stash ma in cui non esistonomaster vengono messi in scena come conflitti "eliminati da noi".

git checkout .e git clean -f -dscarta tutto ciò che non è stato eseguito il commit: tutte le modifiche ai file tracciati e tutti i file e le directory non tracciati. Sono già salvati nella scorta e se lasciati masterpotrebbero causare inutili conflitti di unione quando si torna a my_branch.

L'ultimo git stash popsi baserà sull'originale my_branche quindi non causerà conflitti di unione. Tuttavia, se la tua scorta contiene file non tracciati che hai impegnato a master, git si lamenterà che "Impossibile ripristinare i file non tracciati dalla scorta". Per risolvere questo conflitto, eliminare i file dal vostro albero di lavoro, quindi git stash pop, git add .e git reset.


2
La tua risposta non è stata eliminata perché collegata al tuo sito Web, è stata eliminata perché identica a questa altra risposta da un altro account. Vedo che l'altro account ha lo stesso profilo del tuo, stai usando due account? Puoi unire entrambi gli account. Inoltre, contrassegna una mod per spiegare la situazione e puoi ottenere la risposta originale (con il voto positivo) non cancellata.

1
Non puoi tenerli separati se vengono uniti, ma ti è consentito avere più account, purché non li utilizzi per commettere frodi di voto (o farli interagire tra loro in generale). Spiega la tua situazione a un mod. Inoltre, la cancellazione è stata un errore onesto, come puoi aspettarti che qualcuno dica che stai utilizzando due account diversi?

3
Devi contrassegnare il tuo post e utilizzare l'opzione Altro per attirare l'attenzione di una mod, a cui non presteranno attenzione quando modifichi la risposta eliminata. Ho già segnalato i tuoi post per l'attenzione della mod, ma sono piuttosto occupati, quindi sii paziente, alla fine ti raggiungeranno.

1
Non pubblicare contenuti duplicati, in particolare da account diversi. Vota o contrassegna per chiudere come duplicato se due domande sono uguali.
Bill the Lizard,
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.