2012-02-19 13 views
5

Sto provando a fare un'unione complicata in un repository hg complicato. Non sono contento del "nuovo antenato condiviso" che Mercurial sceglie di utilizzare come "base" per eseguire l'unione.Come specificare un merge-base da usare in un 'hg merge'

Vorrei specificare un commit specifico di mia scelta da utilizzare come base.

E 'possibile, e se sì, come?

risposta

14

Mercurial 3.0: È ora possibile selezionare l'antenato da utilizzare come base di unione. Lo fai impostando merge.preferancestor. Mercurial te ne parlerà quando questo ha senso. Con l'esempio di seguito, si dovrebbe vedere:

$ hg merge 
note: using eb49ad46fd72 as ancestor of 333411d2f751 and 7d1f71140c74 
     alternatively, use --config merge.preferancestor=fdf4b78f5292 
merging x 
0 files updated, 1 files merged, 0 files removed, 0 files unresolved 
(branch merge, don't forget to commit) 

Mercurial prima della versione 3.0: pigro Badger è corretto che non è possibile scegliere l'antenato scelto da Mercurial quando lo si utilizza dalla riga di comando. Tuttavia, è possibile farlo internamente e non è troppo difficile da scrivere un'estensione per questo:

from mercurial import extensions, commands, scmutil 
from mercurial import merge as mergemod 

saved_ancestor = None 

def update(orig, repo, node, branchmerge, force, partial, ancestor=None): 
    if saved_ancestor: 
     ancestor = scmutil.revsingle(repo, saved_ancestor).node() 
    return orig(repo, node, branchmerge, force, partial, ancestor) 

def merge(orig, ui, repo, node=None, **opts): 
    global saved_ancestor 
    saved_ancestor = opts.get('ancestor') 
    return orig(ui, repo, node, **opts) 

def extsetup(ui): 
    extensions.wrapfunction(mergemod, 'update', update) 
    entry = extensions.wrapcommand(commands.table, 'merge', merge) 
    entry[1].append(('', 'ancestor', '', 'override ancestor', 'REV')) 

mettere questo in un file e caricare l'estensione. È ora possibile utilizzare

hg merge --ancestor X 

per sovrascrivere il normale antenato. Come hai scoperto, questo fa fa la differenza se ci sono diversi possibili antenati. Questa situazione si presenta se vi sono fusioni incrociate. È possibile creare un caso del genere con questi comandi:

hg init; echo a > x; hg commit -A -m a x 
hg update 0; echo b >> x; hg commit -m b 
hg update 0; echo c >> x; hg commit -m c 
hg update 1; hg merge --tool internal:local 2; echo c >> x; hg commit -m bc 
hg update 2; hg merge --tool internal:local 1; echo b >> x; hg commit -m cb 

Il grafico si presenta così:

@ changeset: 4:333411d2f751 
|\ 
+---o changeset: 3:7d1f71140c74 
| |/ 
| o changeset: 2:fdf4b78f5292 
| | 
o | changeset: 1:eb49ad46fd72 
|/ 
o changeset: 0:e72ddea4d238 

Se si uniscono normalmente si ottiene changeset eb49ad46fd72 come l'antenato e il file x contiene:

a 
c 
b 
c 

Se si utilizza invece hg merge --ancestor 2 si ottiene un risultato diverso:

a 
b 
c 
b 

In entrambi i casi, il mio KDiff3 è stato in grado di gestire l'unione automaticamente senza segnalare alcun conflitto. Se utilizzo la strategia di unione "ricorsiva" e scelgo come antenato lo e72ddea4d238, allora mi viene presentato un conflitto ragionevole. Git utilizza la strategia di unione ricorsiva per impostazione predefinita.

+0

È un WOW! Funziona perfettamente. Grazie mille. In effetti, non capisco perché questa funzione non sia inclusa in Mercurial. Nella maggior parte dei casi non è necessario, ma nei casi in cui è necessario può risparmiare ore di risoluzione dei conflitti o addirittura impedire l'unione automatica errata. Ho appena riscontrato tali problemi dopo modifiche inaccurate al repository. –

-1

Non puoi farlo. Perché più recente antenato comune IS base reale per la stampa

Se si desidera eseguire merge e non si vuole ri-pensare (perché il vostro show logica-base/ME/presupposti sbagliati e soluzione-path) si può andare rotta patch clone-rebase-merge-export-import

+3

ci possono essere antenati condivisi con più candidati che sono "ugualmente bene", ma diversi. vedi http://man.he.net/man1/git-merge-base –

+0

@LucasMeijer - 1. abbiamo detto di Mercurial, non di Git 2. Loro ** non sono ** "ugualmente bene", perché il nuovo antenato è * "migliore" * –

+2

Qual è la tua ragione per sapere che il più recente è sempre il migliore. Imo, non c'è modo di saperlo. (anche se di solito il più recente è il migliore). il link git si limita a illustrare una situazione in cui non esiste il "migliore", una situazione che può accadere in modo mercuriale allo stesso modo. –

1

Base è utilizzato come un altro input per il tuo strumento di unione. Se si disattiva premerge nella configurazione del Merge Tool (premessa fa le "scelte ovvie" per te quando non ci sono conflitti) e invoca manualmente lo strumento di fusione fornendo copie delle 3 revisioni che vuoi come locale, remoto e base, puoi ottenere qualunque cosa tu voglia nel tuo strumento di fusione. Solo il genitore sinistro e il genitore destro vengono effettivamente registrati nell'unione.

+0

sì , Potrei fare il percorso completamente manuale e, per ogni conflitto di combinazioni, copiare manualmente pasta nella base che voglio. Sto guardando oltre 20 conflitti di fusione, e ho pensato che dobbiamo essere in grado di capire qualcosa di automatico. –

Problemi correlati