2012-03-20 9 views
19

Ho uno script che esegue alcuni comandi Mercurial in modalità non interattiva su un server di build. Uno dei comandi unisce due rami e c'è sempre un conflitto nel file .hgtags durante l'unione a causa del modo in cui gli script di compilazione sono impostati.Come unire automaticamente .hgtags in Mercurial?

Come posso forzare Mercurial a unire sempre il file .hgtags utilizzando le modifiche da entrambi i file, prima da uno, poi dall'altro?

Per esempio, se ho i file da unire erano

A 
B 
C 

e

A 
B 
D 

vorrei che il risultato sia

A 
B 
C 
D 

Sono indovinando avrò bisogno di un strumento di fusione personalizzato. Quale strumento fornisce questa funzionalità?

risposta

31

Vedere il answer below di Magras de La Mancha per una soluzione migliore con Mercurial 3.1. Il seguente è una soluzione più semplice e ingenua per le versioni precedenti di Mercurial.


Sì, è necessario configurare un costume merge tool per il file .hgtags. Mercurial non fornisce alcun strumento di unione speciale per .hgtags, è necessario fonderlo manualmente utilizzando il normale strumento di unione a tre vie.

conflitti nel file .hgtags può avere due tipi:

  • conflitti stupidi: Questa è la situazione che hai e non c'è davvero un conflitto qui.Quello che succede è che un ramo ha

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A 
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B 
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C 
    

    e l'altro ramo ha

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A 
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B 
    979c049974485125e1f9357f6bbe9c1b548a64c3 D 
    

    Ogni tag si riferisce ad esattamente un changeset, quindi non c'è alcun conflitto qui. La fusione dovrebbe naturalmente essere la unione una delle due file:

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A 
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B 
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C 
    979c049974485125e1f9357f6bbe9c1b548a64c3 D 
    
  • conflitti reali: C'è un ramo ha

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A 
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B 
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C 
    

    e l'altro ramo ha

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A 
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B 
    979c049974485125e1f9357f6bbe9c1b548a64c3 C 
    

    C'è un vero conflitto qui: hg tag C è stato fatto su entrambi i rami, ma il t ags si riferiscono a diversi changeset. Risolvere questo è un compito manuale.

Se si può garantire che avrete solo conflitti stupide e che hai solo un tag per ogni changeset, quindi è possibile utilizzare

hg log -r "tagged()" --template "{node} {tags}\n" > .hgtags 

per generare un nuovo file di .hgtags. L'intuizione chiave è che Mercurial sa come unire internamente i tag! Lo fa sempre quando hai due teste con diversi file .hgtags. Il modello sopra riportato genera semplicemente un nuovo file .hgtags basato su questa unione interna.

Se si potrebbe avere più di un tag per ogni changeset, quindi quanto sopra non funzionerà - tutti i tag sono stampati su una riga in modo da ottenere un tag foo bar invece di due tag foo e bar. È quindi possibile utilizzare invece questo style file:

changeset = "{tags}" 
tag = "{node} {tag}\n" 

Produce una linea per tag, non changeset. Si salva questo stile da qualche parte e configurare uno strumento di unione:

[merge-tools] 
hgtags.executable = hg 
hgtags.args = log -r "tagged()" --style ~/tmp/tags-style > $output 
hgtags.premerge = False 
hgtags.priority = -1000 

[merge-patterns] 
.hgtags = hgtags 

Si dispone ora di tag automatico si fonde. Ci sono alcune avvertenze:

  1. tre o più teste: La tecnica funziona solo se si dispone di due teste al momento della fusione. Se hai tre teste o più, è possibile che un tag cancellato riappaia. Se hai le teste X, Y e Z, e il tag A viene cancellato in X, Mercurial è normalmente in grado di capire che A viene eliminato nel suo complesso. Lo fa in base a una riga 000...0 A nel file .hgtags in X. Tuttavia, se si uniscono X e Y per ottenere W, l'approccio suggerito non conterrà alcuna riga di tipo 000...0 A. La definizione di A da Z diventerà improvvisamente effettiva e reintrodurrà A.

  2. conflitti reali: Se si dispone di veri e propri conflitti in .hgtags, allora il metodo di cui sopra sarà silenziosamente scegliere il tag dal più recente testa per voi. Lo strumento di unione salva fondamentalmente hg tags in .hgtags e il comportamento di hg tags con più teste è explained in the wiki. Poiché hg tags legge incondizionatamente e unisce in modo invisibile il file .hgtags da tutte le teste, non c'è nulla che possiamo fare al riguardo con questo semplice approccio. Affrontare questo richiede uno script più grande che legge i due file .hgtags e rileva il conflitto.

+0

Vedi https://bitbucket.org/xrstf/tagsmerger/wiki/Home per uno strumento di unione che risolve i conflitti sciocchi. :) – xrstf

+0

@xrstf: l'ho visto l'altro giorno. Non l'ho raccomandato perché non penso che funzioni correttamente quando ci sono più di due teste. Semplicemente cancellando le righe '000 ... 0' si reintroducono i tag come spiego nella mia risposta. –

+0

Eccellente, mi congratulo! Posso chiederti, quando questo notrs apparirà sul sito di Aragost? Lo perderemo qui –

-2

Si dovrebbe provare diffmerge, è fantastico!

+2

Credo che il PO sta cercando un modo per ** automaticamente ** unire questi file. – krtek

+0

Per un * modo *, puoi semplicemente modificare il file in conflitto come preferisci, ma sarà un mal di testa se ci sono molti conflitti coinvolti, ed è per questo che ho consigliato un bel tool come * diffmerge * per l'OP. E non esiste uno strumento che ti aiuti a risolvere automaticamente un conflitto, uno strumento ti assisterà nel farlo. – neevek

1

Non è possibile risolvere automaticamente conflitti di unione eseguendo un'unione automatica. Senza unione (vale a dire selezionando "solo il mio" o "solo altro") funzionerà.

Ho paura, hai un flusso di lavoro pianificato male - build-server non deve eseguire alcuna azione, che modifica le fonti. È un compito per la scelta umana e umana.

Ma suppongo che i dati esatti all'interno di .hgtags debbano valere per build-server (utilizza il proprio clone, non popolato da nessuno, spero ?!), quindi è possibile definire qualsiasi criterio di unione in comando e avere (cattivi, .hgtags con perdita di dati) fuse

BTW, "prima da uno, poi dall'altro" in qualsiasi lingua, utilizzando solo la logica formale, per la coppia di

A 
B 
C 

e

A 
B 
D 

significa ABCABD risultato

+1

"prima da una, poi dall'altra" nel contesto della risoluzione di un conflitto di solito si riferisce all'utilizzo delle righe _conflicted da entrambi i file nel file dei risultati: prima da un file, poi dall'altra. È una caratteristica standard di qualsiasi strumento di unione grafica, quindi ho pensato che tutti quelli che ne avevano già usato uno capissero cosa intendo. –

+1

Questo è giusto "nella maggior parte dei casi", ma, come suggerito da @MartinGeisler, in questo caso particolare esiste una soluzione. Inoltre, non dovresti criticare il flusso di lavoro dell'OP senza saperne di più. – krtek

+2

@krtek - Il server di compilazione NON DEVE modificare il codice, solo la compilazione. Mi riservo il diritto di dire la verità a tutti –

1

In realtà non è necessario unire il file .hgtags. Può essere diverso su diversi rami e Mercurial elencherà correttamente tutti i tag su tutti i rami.

Utilizziamo merge-patterns configuration option per comunicare a Mercurial di utilizzare il ramo locale quando si esegue l'unione di .hgtags. Aggiungere il seguente nel file hgrc del vostro repository:

[merge-patterns] 
.hgtags = internal:local 

Quando si effettua una fusione che coinvolge il file .hgtags, .hgtags mostrerà come modificato, ma non può essere modificato.

+1

Non è una buona idea, potresti perdere i tag dall'altro capo. – Jesse

10

Mercurial 3.1 (2014-08-01) ha introdotto interno: etichetta. È contrassegnato come sperimentale, quindi fai attenzione. Ecco preambolo da changeset (potete trovare maggiori dettagli su algoritmo se seguite il link):

Aggiungi un nuovo interno: strumento di unione tagmerge che implementa un algoritmo automatico di unione per i file tag di Mercurial

Il L'algoritmo di tagmerge è in grado di risolvere la maggior parte dei conflitti di merge che attualmente causerebbero un conflitto di unione .hgtags. L'unico caso in cui non gestisce (e non può) è quello in cui due tag indicano revisioni diverse su ciascun genitore di unione e le rispettive cronologie di tag hanno lo stesso rango (cioè la stessa lunghezza). In tutti gli altri casi, l'algoritmo di fusione sceglierà la revisione appartenente al genitore con la cronologia dei tag più alta classificata. La cronologia dei tag uniti è la combinazione di entrambe le cronologie di tag (si presta particolare attenzione a cercare di combinare le cronologie di tag comuni laddove possibile).

L'algoritmo gestisce anche i casi in cui i tag sono stati rimossi manualmente dal file .hgtags e da altri casi angolari simili.

Oltre a unire effettivamente i tag di due genitori, tenendo conto della base, l'algoritmo tenta anche di ridurre al minimo la differenza tra il file di tag unito e il file di tag del primo genitore (cioè tenta di creare l'ordine dei tag uniti il più simile possibile all'ordine del file di tag del primo genitore).

tagmerge funziona solo con file di tag, in modo da usarlo è necessario impostare unione-patterns.Per fare questo su ogni comando di utilizzo base --config opzione:

hg merge -r REV --config merge-patterns..hgtags=internal:tagmerge

O per fare questo su per la base di repository aggiungere al vostro repo config .hg/hgrc questo:

[merge-patterns] 
.hgtags=internal:tagmerge 
+0

Le versioni più recenti di default di Mercurial per l'utilizzo di questo algoritmo quando le unioni implicano i file '.hgtags'? – binki

+0

@binki, non sto guardando mercurial mappe stradali o mailing list. Ho appena avuto questo problema un anno fa e ho trovato una soluzione condivisa. – magras