Rebase un singolo commit Git


116

C'è un modo per rebase un singolo commit da un ramo a un altro ramo?

Ho questa struttura di filiale:

-- -- -- -- -- (Master)
            \
              -- -- -- -- -- XX (Feature-branch)

Tutto quello che voglio fare è rebase l'ultimo commit di Feature-branchsu master e rollback di Feature-branchun commit.

-- -- -- -- -- XX (Master)
            \
              -- -- -- -- -- (Feature-branch)

Come lo faccio?


3
Se puoi ribasare un numero qualsiasi di commit, perché chiedi di ribasare uno solo? Se potessi fare domande in SO, chiederei qual è la differenza tra rebasing (un singolo commit) e cherry-picking.
Val

9
Perché non sapevo che esistesse il cherry-picking, e faccio "Faff about on branch", "Get request for fix on different branch", "fix it", "Commit to wrong branch", "D'OH!" abbastanza che porre la domanda fosse utile.
Kevin Meyer

Risposte:


116

Puoi scegliere XX da padroneggiare.

git checkout master
git cherry-pick <commit ID of XX>

E rimuovi l'ultimo commit dal ramo delle funzionalità con git reset.

git checkout Feature-branch
git reset --hard HEAD^

64
come può una domanda chiamata specificamente 'git rebase ...' avere la risposta accettata che contiene un cherry-pick, che è un concetto completamente diverso e talvolta considerato di per sé impuro?
Bondax

1
Non sono sicuro che sia pertinente, ma il commit che volevo rebase aveva alcuni file che erano stati spostati e cherry-pickli faceva apparire come se fossero stati cancellati dalla vecchia posizione e creati nella nuova posizione. Suppongo che rebase si sarebbe preso cura di quello, ma ormai ho spinto a monte quindi non posso testarlo. In ogni caso, fai attenzione se hai una situazione simile.
waldyrious

Nota: per inviare le modifiche Feature-branchall'origine dovrai farlo git push -f origin Feature-branchpoiché Feature-branchora è considerato 1 commit dietro il file origin/Feature-branch.
jojo

1
Qual è la differenza pratica tra questa soluzione e quella di CharlesB ?
Lii

96
git rebase --onto master branch~1 branch 

Questo dice "rebase l'intervallo di commit tra l'ultimo ramo prima e il ramo (cioè XX commit) sulla punta del ramo principale"

Dopo questa operazione, il branchsuggerimento viene spostato sul commit XX, quindi è necessario reimpostarlo con

git checkout branch
git reset --hard branch@{1}^

Che dice "reimposta la punta del ramo al commit prima del suo stato precedente"

Quindi una scelta di ciliegie è una soluzione più semplice ...


5
Questo non sembra funzionare per me, perdo i commit prima di XX e il ramo viene ribasato per master con un singolo commit, ma non l'ho mai usato --ontoprima, quindi potrei fare qualcosa di sbagliato. A proposito, l'OP ha detto rebase ma sembra che voglia fare una scelta di ciliegie.
tewe

1
errore mio, rebase sposta effettivamente il ramo sul master, deve essere ripristinato
CharlesB

1
Qual è la differenza pratica tra questa soluzione e quella di tewe ?
Lii

1
@Lii l'unico che posso vedere è che utilizza 3 passaggi invece di 4
CharlesB

52

È piuttosto semplice da fare in realtà. La soluzione è fare un rebase interattivo e "eliminare" tutti i commit che non vuoi includere nel rebase.

git rebase -i <target_branch>dov'è target_branchil ramo su cui vuoi ribassare

Quindi modificherai il file che viene aperto e picki commit che desideri e drop(o din breve) tutti i commit che non vuoi portare con te.


6
IMO una soluzione molto migliore, e in realtà affronta la questione.
GabrielOshiro

Questa dovrebbe essere la soluzione accettata dato quanto è generale, intuitiva e breve.
Pablo Arias

1

La risposta di @Charles è corretta. Ad ogni modo ho finito per usarlo così tante volte, soprattutto per rebase specifiche configurazioni su un progetto

  * configurazione di produzione a8f9182 (HEAD -> production)
  | * daa18b7 (pre) configurazione di preproduzione
  | /  
  | * d365f5f (locale) configurazione locale
  | /  
  * 27d2835 (dev) nuova straordinaria funzionalità che salverà il mondo
* | 56d2467 (master) noioso stato dell'arte per il progetto
| /

che creo un nuovo comando per esso:

$ cat ~ / bin / git-rebaseshot 
COMMIT = $ 1
DEST = $ {2: TESTE}
git rebase $ {COMMIT} ^ $ {COMMIT} - a $ DEST

normalmente si desidera completare automaticamente i nomi dei rami per quel comando, quindi aggiungerlo a questa funzione (aggiungendolo a .bashrc o .profile):

_git_rebaseshot () 
{ 
    __gitcomp_nl "$ (__ git_refs)"
}

git autocomplete lo cercherà

puoi usare questo comando in questo modo:

# rebase config on prepro on actual HEAD
$ git rebaseshot prepro 
# rebase config on local onto dev
$ git rebaseshot local dev
# rebase production config on master
$ git rebaseshot pro master

Quando dividi correttamente le caratteristiche, le possibilità sono infinite.

* a8f9182 (HEAD -> postgres) BBDD config
* a8f9182 (locale) configurazione locale
* a8f9182 (debug) configurazione a livello di registro
* Nuova funzionalità a8f9182 (dev)
|

Immagino che questo sia ciò che piace fare alle persone di trapunta .

questo comando funzionerà comunque con qualsiasi sha / ref fornito:

$ git rebaseshot <Feature branch> master
$ git rebaseshot <commit of XX> master

//, Puoi collegarti a qualsiasi progetto in cui possiamo vederlo in azione?
Nathan Basanese

Per sua natura, i rami disponibili per il rebaseshot non sono impegnati al di fuori del repo locale. Basta creare diversi rami sopra il master (livello di registro, connessione al database, configurazione) e utilizzare il comando tra di loro. È normale vedere l'effetto.
albfan

//, ho riscontrato alcuni problemi. Lo riproverò.
Nathan Basanese

0

Ecco un'altra opzione:

  1. Assicurati di avere un telecomando con una copia del feature branch
  2. Elimina il ramo della caratteristica locale
  3. Crea ed esegui il checkout di un nuovo ramo con lo stesso nome del vecchio ramo di funzionalità che hai appena eliminato dal master
  4. scegli l'unico commit dalla copia remota del ramo delle funzionalità che desideri.

I comandi hanno questo aspetto:

git checkout Feature-branch
git push -u origin HEAD
git checkout master
git branch -D Feature-branch
git checkout -b Feature-branch
git cherry-pick HASH-OF-XX

Non è un comando rebase no, ma è un rebase nello spirito.

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.