2010-12-29 22 views
7

versione semplice:Utilizzando git filter-branch per rimuovere impegna per la loro messaggio di commit

Se ho un ramo "foo-555", con un gruppo di commit con messaggi come:

  • foo 555: bla
  • foo 123: bla bla
  • foo 555: bla bla bla
  • foo 321: blahblah

e voglio rimuovere tutti i commit che non iniziano con "foo 555:", c'è un modo per farlo usando git filter-branch (o qualsiasi altro strumento per quella materia)?

versione originale (più dettagliata):

Nel nostro repository abbiamo una convenzione in cui ogni messaggio di commit inizia con un certo modello:

Redmine # 555: SOME_MESSAGE

Facciamo anche un po 'di rebasing per introdurre le modifiche del ramo di rilascio potenziale al ramo di un problema specifico. In altre parole, potrei avere un ramo "foo-555", ma prima di fonderlo nel ramo "pre-release" ho bisogno di ottenere qualsiasi commit che pre-release abbia che foo-555 no (così che 555 può eseguire l'avanzamento rapido nella pre-release).

Tuttavia, poiché a volte le pre-release cambiano, a volte ci si ritrova in situazioni in cui si inserisce un commit dalla pre-release, ma successivamente tale commit viene rimosso dalla pre-release. È facile identificare i commit provenienti dalla pre-release, perché il numero dal loro messaggio di commit non corrisponde al numero del ramo; per esempio, se vedo "Redmine # 123: ..." nel mio ramo foo-555, so che non è un commit dal mio ramo.

Quindi ora la domanda: mi piacerebbe rimuovere tutti i commit che "non appartengono" a un ramo; in altre parole, ogni commit che:

  • è nel mio ramo foo-555, ma non nel ramo pre-release (pre-release..foo-555)
  • ha un messaggio che doesn' commit t iniziare con "Redmine # 555"

ma ovviamente "555" può variare da un ramo all'altro. C'è un modo per usare filter-branch (o qualsiasi altro strumento) per realizzare questo? Attualmente l'unico modo che posso vedere è di fare un rebase interattivo ("git rebase -i") e rimuovere manualmente tutti i commit "cattivi".

+0

si può non ciliegia scegliere i commit desiderati nel ramo in questione? –

+0

Noi * possiamo *, ma diciamo che ho 10 555 commit e 10 altri commit; Dovrei reimpostare e quindi fare 10 scelte di selezione (rispetto a un comando di filtro-ramo ... se è possibile una cosa simile). – machineghost

risposta

4

scrivere uno script per rimuovere le linee con Redmine #555:

#!/bin/sh 

mv $1 $1.$$ 
grep -v 'Redmine #555' < $1.$$ > $1 
rm -f $1.$$ 

Naturalmente si può fare che tuttavia si desidera (ad esempio echo uno script di comandi per ed).

Poi lanciare il rebase con EDITOR insieme allo script:

EDITOR=/path/to/script git rebase -i REVISION 

Naturalmente ancora non sarà garantita per completare - ci possono essere errori durante il rebase causata da lasciando fuori revisioni. È ancora possibile correggerli e git rebase --continue manualmente.

+0

Sembra che funzioni, ma ... non c'è un modo per usare semplicemente Git (senza script di shell) e rendere il processo automatizzato tramite un "git filter-branch --commit-filter"? – machineghost

+1

L'aiuto per '--commit-filter' indica specificamente che' skip_commit' lascia fuori il commit ma ** non le modifiche ** e dice di usare 'git-rebase'. 'filter-branch' considera le tue revisioni come una sequenza di stati e ti permette di permutare ogni commit, ma le modifiche non si propagano ai bambini. 'rebase' considera le revisioni come una pila di patch e qualsiasi modifica midstream * si * si propaga alle revisioni future. Ma ciò può causare guasti, motivo per cui non può essere completamente automatico. –

+0

Ahhhhhhh. Grazie! – machineghost

8

Ecco una soluzione rapida che utilizza filter-branch anziché rebasing. Non c'è interattività o necessità di risolvere i conflitti.

git filter-branch --commit-filter ' 
    if [ `git rev-list --all --grep "<log-pattern>" | grep -c "$GIT_COMMIT"` -gt 0 ] 
    then 
     skip_commit "[email protected]"; 
    else 
     git commit-tree "[email protected]"; 
    fi' HEAD 

Probabilmente si vorrà poi pulire con:

git reflog expire --expire=now 
git gc --prune=now 
+1

Per repository di grandi dimensioni con molti commit, questo può richiedere un po '(ad esempio, alcuni secondi per filtro di commit su FreeBSD '-CURRENT', che ha centinaia di migliaia di commit). Un'alternativa molto più rapida per la condizione 'git rev-list --all [...]' è 'git show $ GIT_COMMIT | grep -c "" '. – trombonehero

Problemi correlati