Git: crea un ramo da modifiche non messe in scena / non salvate sul master


991

Contesto: sto lavorando al master aggiungendo una semplice funzione. Dopo alcuni minuti mi rendo conto che non era così semplice e avrebbe dovuto essere meglio lavorare in una nuova filiale.

Questo succede sempre a me e non ho idea di come passare a un altro ramo e prendere tutte queste modifiche non impegnate con me lasciando pulito il ramo principale. Suppongo che lo git stash && git stash branch new_branchavrei semplicemente realizzato, ma questo è quello che ottengo:

~/test $ git status
# On branch master
nothing to commit (working directory clean)

~/test $ echo "hello!" > testing 

~/test $ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   testing
#
no changes added to commit (use "git add" and/or "git commit -a")

~/test $ git stash
Saved working directory and index state WIP on master: 4402b8c testing
HEAD is now at 4402b8c testing

~/test $ git status
# On branch master
nothing to commit (working directory clean)

~/test $ git stash branch new_branch
Switched to a new branch 'new_branch'
# On branch new_branch
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   testing
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (db1b9a3391a82d86c9fdd26dab095ba9b820e35b)

~/test $ git s
# On branch new_branch
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   testing
#
no changes added to commit (use "git add" and/or "git commit -a")

~/test $ git checkout master
M   testing
Switched to branch 'master'

~/test $ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   testing
#
no changes added to commit (use "git add" and/or "git commit -a")

Sai se esiste un modo per raggiungere questo obiettivo?


1
Anche se esiste una soluzione più semplice al tuo problema, potresti specificare in quale risultato ottieni diverso da quello che volevi?
Gauthier,

2
facendo quanto sopra o le risposte in fondo, le modifiche non impegnate sono sia sul master che sul nuovo ramo. Li voglio solo sul nuovo ramo, quindi posso fare il checkout di master e lavorare su un'altra cosa senza che queste modifiche
fluttuino

1
vedi la mia risposta modificata. È necessario eseguire il commit delle modifiche locali sul nuovo ramo se si desidera effettuare il checkout di un master pulito. Le modifiche locali sono solo le differenze tra HEAD corrente e i tuoi file su disco. Queste modifiche ai file locali non hanno la versione, devi dire a git di salvarle da qualche parte se vuoi recuperarle in seguito.
Gauthier,

Risposte:


1207

Non c'è bisogno di riporre.

git checkout -b new_branch_name

non tocca le modifiche locali. Crea semplicemente il ramo dall'attuale HEAD e imposta lì il HEAD. Quindi immagino sia quello che vuoi.

--- Modifica per spiegare il risultato del checkout master ---

Sei confuso perché checkout masternon ignora le modifiche?

Dato che le modifiche sono solo locali, git non vuole che tu le perda troppo facilmente. Quando si cambia ramo, git non sovrascrive le modifiche locali. Il risultato del tuo checkout masterè:

M   testing

, il che significa che i file di lavoro non sono puliti. git ha modificato HEAD, ma non ha sovrascritto i file locali. Ecco perché il tuo ultimo stato mostra ancora le modifiche locali, anche se sei attivo master.

Se vuoi davvero annullare le modifiche locali, devi forzare il checkout con -f.

git checkout master -f

Dal momento che le modifiche non sono mai state eseguite, le perderesti.

Prova a tornare alla tua filiale, apporta le modifiche, quindi controlla nuovamente il master.

git checkout new_branch
git commit -a -m"edited"
git checkout master
git status

Dovresti ricevere un Mmessaggio dopo il primo checkout, ma non più dopo il checkout master, e non git statusdevi mostrare file modificati.

--- Modifica per chiarire la confusione sulla directory di lavoro (file locali) ---

In risposta al tuo primo commento, le modifiche locali sono solo ... beh, locali. Git non li salva automaticamente, devi dirlo per salvarli per dopo. Se si apportano modifiche e non si esegue il commit o lo stash in modo esplicito, git non le versioni. Se si modifica HEAD ( checkout master), le modifiche locali non vengono sovrascritte poiché non salvate.


32
La cosa confusa qui è che la pagina man di git afferma che git checkout"Aggiorna i file nell'albero di lavoro in modo che corrispondano alla versione nell'indice o all'albero specificato.". Ciò presuppone che in seguito le tue modifiche al tuo file system saranno ANDATE . Senza alcuna possibilità di recuperarli. Anche se dici che non lo faranno, questo lascia comunque una brutta sensazione. Non mi fido di questo a tutti . O la documentazione è davvero pessima o il comportamento predefinito di Git è davvero pericoloso. Non si dovrebbe fidarsi di qualche euristica "automagica" per rilevare che in questo caso non si vuole perdere le modifiche.
Evi1M4chine

16
Se stai verificando un commit che sovrascriverà le tue modifiche locali (se la cronologia tra il commit corrente e il commit target tocca i tuoi file modificati localmente), git rifiuta. Solo se checkoutnon è in conflitto con le modifiche locali, la cassa funziona e lascia da sole le modifiche locali. Capisco la brutta sensazione, però, la pagina man dovrebbe forse dire "Aggiorna i file non modificati nella struttura di lavoro". Git non rende d'altra parte troppo facile perdere le modifiche locali. git checkoutconsente solo le modifiche locali o rifiuta in caso di conflitto.
Gauthier

1
bene, come farei il checkout in un'altra filiale senza apportare lì le modifiche locali?
ア レ ッ ク ス

5
@Alex git checkout <other_branch> -f. Perderai le modifiche locali senza preavviso.
Gauthier,

2
@ Evi1M4chine Il primo. La documentazione è davvero pessima.
Qwertie,

62

Provare:

git stash
git checkout -b new-branch
git stash apply

6
È diverso dal fare semplicemente 'git checkout -b new-branch' da solo?
Adrian Mouat l'

Non penso che fosse quando la risposta era stata originariamente scritta, ma potrei sbagliarmi. Sfortunatamente a causa delle mie circostanze lavorative, ho usato la perforce negli ultimi anni, quindi non posso attestare la sua precisione ora.
Grant Limberg,

6
O invece degli ultimi due passaggi: git stash branch new-branch
rethab

1
git stash non è più necessario
kory

Quando hai un ramo già esistente dove vuoi mettere tutte le tue cose, stash ha senso per me: (Alla fine git fetch --all; per ottenere il ramo remoto sull'origine) git stash; git checkout <esistente-branch>; git stash si applica;
Paolof76,

24

Due cose che puoi fare:

git checkout -b sillyname
git commit -am "silly message"
git checkout - 

o

git stash -u
git branch sillyname stash@{0}

(git checkout - <- il trattino è una scorciatoia per il ramo precedente in cui ti trovavi)

( git stash -u<- -usignifica che accetta anche modifiche non messe in scena)


7

Se stai usando il client GitHub per Windows (come lo sono io) e ti trovi nella situazione di aver apportato modifiche senza impegno che desideri spostare in un nuovo ramo, puoi semplicemente "Creare un nuovo ramo" tramite il client GitHub. Passerà al ramo appena creato e conserverà le modifiche.

inserisci qui la descrizione dell'immagine


che blocca le modifiche prima di creare il nuovo ramo in modo da non tenerle (versione 223 su Mac OS)
Fernando Gallego,

2

Se si desidera che le modifiche correnti non confermate sul ramo corrente vengano spostate su un nuovo ramo, utilizzare il comando seguente per creare un nuovo ramo e copiare automaticamente le modifiche senza commit.

git checkout -b branch_name

Ciò creerà un nuovo ramo dal ramo corrente (supponendo che sia master), copierà le modifiche non impegnate e passerà al nuovo ramo.

Conferma le modifiche nella nuova filiale.

git commit -m "First commit"

Dal momento che viene creato un nuovo ramo, prima di spingerlo in remoto, è necessario impostare l'upstream. Utilizzare il comando seguente per impostare l'upstream e spingerlo in remoto.

git push --set-upstream origin feature/feature/NEWBRANCH

Una volta premuto questo comando, verrà creato un nuovo ramo sul telecomando e il nuovo ramo locale verrà trasferito sul telecomando.

Ora, se si desidera eliminare le modifiche non vincolate dal ramo principale, utilizzare:

git checkout master -f

Ciò eliminerà eventuali modifiche locali non confermate al momento del pagamento.


In che modo questa risposta differisce da quella accettata?
kometen,

Sebbene vi sia una certa sovrapposizione con la risposta accettata, ciò fornisce una semplice guida passo-passo e include anche le operazioni necessarie per inviare un nuovo ramo in remoto. Semplice, chiaro e utile.
Kjartan,

Questa risposta è chiara e mi ha aiutato molto.
Vadim,

0

Nell'ultimo client GitHub per Windows , se hai apportato modifiche senza commit e scegli di creare un nuovo ramo.
Ti chiede come gestire questo scenario esatto:

inserisci qui la descrizione dell'immagine

Lo stesso vale se si cambia semplicemente anche il ramo.

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.