spostare le modifiche impegnate (ma non spinte) in un nuovo ramo dopo il pull


460

Ho fatto un bel po 'di lavoro ("Il tuo ramo è davanti a' origine / padrone 'di 37 commit") che avrebbe dovuto andare nel suo ramo piuttosto che in master. Questi commit esistono solo sulla mia macchina locale e non sono stati spinti a origin, ma la situazione è alquanto complicata in quanto altri sviluppatori hanno spinto verso origin/mastere ho apportato quei cambiamenti.

Come posso spostare retroattivamente i miei 37 commit locali in una nuova filiale? Sulla base dei documenti, sembra che dovrebbe git rebase --onto my-new-branch mastero ...origin/masterdebba farlo, ma entrambi mi danno solo l'errore "fatale: necessaria una sola revisione". man git-rebasenon dice nulla sulla fornitura di una revisione rebasee i suoi esempi non lo fanno, quindi non ho idea di come risolvere questo errore.

(Si noti che questo non è un duplicato di Sposta lavoro esistente e non sottoposto a commit in un nuovo ramo in Git o Come unire le mie modifiche locali senza commit in un altro ramo Git? Poiché tali domande riguardano le modifiche non confermate nell'albero di lavoro locale, non le modifiche che hanno stato commesso localmente.)


Dai un'occhiata a questa soluzione . Sembra essere facile e pulito.
Tony,

Dai un'occhiata a questa soluzione . Sembra essere facile e pulito.
Tony,

Risposte:


518

Questo dovrebbe andare bene, dal momento che non hai ancora trasferito i tuoi impegni da nessun'altra parte e sei libero di riscrivere la storia della tua filiale dopo origin/master. Prima di tutto vorrei eseguire un git fetch originper assicurarsi che origin/mastersia aggiornato. Supponendo che tu sia attualmente attivo master, dovresti essere in grado di fare:

git rebase origin/master

... che riprodurre tutti i commit che non sono in origin/mastersu origin/master. L'azione predefinita di rebase è ignorare i commit di merge (ad esempio quelli che git pullprobabilmente sono stati introdotti) e proverà semplicemente ad applicare la patch introdotta da ciascuno dei tuoi commit origin/master. (Potrebbe essere necessario risolvere alcuni conflitti lungo il percorso.) Quindi è possibile creare il nuovo ramo in base al risultato:

git branch new-work

... e poi resetta le masterspalle a origin/master:

# Use with care - make sure "git status" is clean and you're still on master:
git reset --hard origin/master

Quando faccio questo tipo di manipolazione di rami con git branch, git resetecc. Trovo utile guardare frequentemente il grafico di commit con gitk --allo uno strumento simile, solo per verificare che capisca dove puntano tutti i diversi ref.

In alternativa, potresti aver appena creato un ramo di argomento in base a dove si trova il tuo master in primo luogo ( git branch new-work-including-merges) e quindi ripristinare mastercome sopra. Tuttavia, dal momento che la sezione del tuo argomento includerà le fusioni origin/mastere che non hai ancora apportato le modifiche, ti suggerirei di fare un rebase in modo che la cronologia sia più ordinata. (Inoltre, quando alla fine unirai il ramo del tuo argomento al master, le modifiche saranno più evidenti.)


8
@Olie: No, la risposta è corretta sotto i presupposti della domanda e quelli che ho esposto all'inizio della risposta. Gli commit che dovrebbero essere in una nuova filiale separata sono già in master; il rebase riscrive il masterramo in modo che i nuovi commit siano linearmente in cima origin/master, quindi git branch new-workcrea un new-workramo che punta sulla punta del master(ramo corrente) senza cambiare il ramo corrente su new-work. Quindi ora new-workcontiene tutti i nuovi commit. Quindi il reset sposta il ramo corrente (ancora master) su origin/master.
Mark Longair,

1
@Quintesse: mi dispiace molto se hai perso il lavoro, ma sono sicuro che questa risposta sia corretta per la situazione descritta dall'interrogatore originale. (Ho appena risposto alle osservazioni di Olie, si spera chiarendo.) Comunque, nel caso in cui ti aiuti a recuperare il tuo lavoro, dovrei dire che se il tuo lavoro è stato commesso negli ultimi giorni (uno dei presupposti di questa domanda e risposta ) dovresti essere in grado di recuperarlo facilmente tramite il reflog di git.
Mark Longair,

5
@Olie: forse un modo migliore per spiegare: i rami in git sono proprio come etichette che indicano un particolare commit; vengono automaticamente spostati in nuovi commit se li crei mentre sei su quel ramo o puoi spostarli con git resetvari altri modi. Il git branch new-workè solo dicendo "che punta a creare un ramo a questo commit, mentre io rimango sul mio ramo corrente (che è maestro in questo caso)". Quindi non è necessario disporre di un comando che sposta i commit dal master al nuovo ramo: basta creare un nuovo ramo lì e quando si reimposta il master, il nuovo ramo viene lasciato dov'era il master
Mark Longair,

1
un po 'in ritardo alla festa ma @Olie, solo perché lo stato git quando sul nuovo ramo non mostra i commit prima del master non significa che non siano effettivamente lì (supponendo che tu sia preoccupato). Prova a spingere la nuova filiale verso l'origine: vedrai che ci sono impegni
Félix Gagnon-Grenier,

2
@ FélixGagnon-Grenier, non preoccuparti del "ritardo": ci sono sempre persone che cercano vecchie domande e ogni chiarimento aiuta. Grazie! :)
Olie,

148

Se hai un numero basso di commit e non ti importa se questi sono combinati in un mega-commit, questo funziona bene e non è spaventoso come fare git rebase:

decomprimere i file (sostituire 1 con # di commit)

git reset --soft HEAD~1

creare una nuova filiale

git checkout -b NewBranchName

aggiungi le modifiche

git add -A

impegnarsi

git commit -m "Whatever"

5
Per mostrare un grafico di facile comprensione, si prega di utilizzare git log --all --decorate --oneline --graph.
EliuX

Ehi @EliuX - Mi manca la rilevanza qui. Puoi espandermi?
Stachu,

Questo è utile per verificare se hai ottenuto il risultato desiderato in quello che hai fatto
EliuX

4
Grazie!! questa è una soluzione molto semplice e ha funzionato perfettamente !!
Chris Sim,

91

Ho bloccato con lo stesso problema. Ho trovato la soluzione più semplice che mi piace condividere.

1) Crea una nuova filiale con le tue modifiche.

git checkout -b mybranch

2) (Opzionale) Inserire il nuovo codice di filiale sul server remoto.

git push origin mybranch

3) Torna alla sezione principale.

git checkout master

4) Ripristinare il codice filiale principale con il server remoto e rimuovere il commit locale.

git reset --hard origin/master

10
Questo è davvero il modo più semplice
dhilt

4
Puoi tralasciare il passaggio 2. Presumo che nel tempo dalla risposta in alto, git sia cambiato e questa strategia non era consentita prima.
Sebastian,

Questa è la migliore risposta secondo me.
Macindows,

1
Questa risposta deve spostarsi verso l'alto. Grazie.
Amit

27

Un altro modo per assumere branch1 - è branch con modifiche commesse branch2 - è branch desiderabile

git fetch && git checkout branch1
git log

seleziona gli ID di commit che devi spostare

git fetch && git checkout branch2
git cherry-pick commit_id_first..commit_id_last
git push

Ora ripristina i commit non compressi dal ramo iniziale

git fetch && git checkout branch1
git reset --soft HEAD~1

5
Cherry-pick è davvero il miglior comando "copia / sposta un singolo commit", esp. quando la storia è bagaglio per i tuoi scopi.
John Neuhaus,

Questa è finora la risposta più conveniente alla domanda. Grazie per il comando!
Farah,

puoi aggiornare il tuo ultimo commento dove 1 o n è il numero di commit non compressi? Questa è ancora un'ottima soluzione per questa domanda.
chAlexey,

9

In alternativa, subito dopo aver eseguito il commit nel ramo sbagliato, attenersi alla seguente procedura:

  1. git log
  2. git diff {previous to last commit} {latest commit} > your_changes.patch
  3. git reset --hard origin/{your current branch}
  4. git checkout -b {new branch}
  5. git apply your_changes.patch

Posso immaginare che esiste un approccio più semplice per i passaggi uno e due.


6

Che dire:

  1. Diramazione dall'attuale TESTA.
  2. Assicurati di essere padrone , non il tuo nuovo ramo.
  3. git reset tornare all'ultimo commit prima di iniziare a apportare modifiche.
  4. git pull per ritirare solo le modifiche remote che hai eliminato con il ripristino.

O esploderà quando proverai a ricongiungere il ramo?


2
Ah, questa è sostanzialmente l'opzione B descritta da @ Mark-Longair sopra
Tim Keating del

2

Ecco un modo molto più semplice:

  1. Crea una nuova filiale

  2. Nel tuo nuovo ramo fai un git merge master- questo unirà le tue modifiche impegnate (non spinte) al tuo nuovo ramo

  3. Elimina il ramo principale locale git branch -D masterUtilizzare -Dinvece di -dperché si desidera forzare l'eliminazione del ramo.

  4. Basta fare un git fetchramo principale e fare un git pullramo principale per assicurarsi di disporre del codice più recente per i team.


1

Un approccio più semplice, che ho usato (supponendo che tu voglia spostare 4 commit):

git format-patch HEAD~4

(Cerca nella directory da cui hai eseguito l'ultimo comando per i 4 .patchfile)

git reset HEAD~4 --hard

git checkout -b tmp/my-new-branch

Poi:

git apply /path/to/patch.patch

Nell'ordine che volevi.


0
  1. Acquista una nuova copia delle tue fonti

    git clone ........

  2. Crea ramo dalla posizione desiderata

    git checkout {position} git checkout -b {branch-name}

  3. Aggiungi repository remoto

    git remote add shared ../{original sources location}.git

  4. Ottieni fonti remote

    git fetch shared

  5. Acquista la filiale desiderata

    git checkout {branch-name}

  6. Unisci fonti

    git merge shared/{original branch from shared repository}


0

Per me questo è stato il modo migliore:

  1. Controlla le modifiche e unisci i conflitti git fetch
  2. Crea un nuovo ramo git branch my-changese passa al telecomando
  3. Passa a monte al nuovo ramo creato git master -u upstream-branch remotes/origin/my-changes
  4. Spingi i tuoi commit nella nuova filiale a monte.
  5. Torna al precedente upstream git branch master --set-upstream-to remotes/origin/master
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.