hgbook

annotate it/ch03-tour-merge.xml @ 735:4f2e323221a3

First literal translation of Ch.3.
author Giulio@puck
date Mon Jun 29 17:39:32 2009 +0200 (2009-06-29)
parents
children 79e43e425111
rev   line source
Giulio@735 1 <chapter id="chap:tour-merge">
Giulio@735 2 <?dbhtml filename="una-panoramica-di-mercurial-unire-il-lavoro.html"?>
Giulio@735 3 <title>Una panoramica di Mercurial: unire il lavoro</title>
Giulio@735 4
Giulio@735 5 <para id="x_338">Abbiamo ora coperto il clonare un repository, effettuare cambiamenti in un repository, e estrarre o trasmettere cambiamenti da un repository a un altro. Il nostro prossimo passo sarà <emphasis>unire</emphasis> i cambiamenti da repository separati.</para>
Giulio@735 6
Giulio@735 7 <sect1>
Giulio@735 8 <title>Unire flussi di lavoro</title>
Giulio@735 9
Giulio@735 10 <para id="x_339">Le unioni sono una parte fondamentale del lavoro con uno strumento per il controllo di revisione distribuito. Ecco alcuni casi in cui il bisogno di unire il lavoro si solleva.</para>
Giulio@735 11 <itemizedlist>
Giulio@735 12 <listitem>
Giulio@735 13 <para id="x_33a">Alice e Bruno hanno ognuno una copia personale di un repository per un progetto su cui stanno collaborando. Mentre Alice corregge un bug nel suo repository, Bruno aggiunge una nuova caratteristica nel proprio. Entrambi vogliono che il repository condiviso contenga sia la correzione del bug sia la nuova caratteristica.</para>
Giulio@735 14 </listitem>
Giulio@735 15 <listitem>
Giulio@735 16 <para id="x_33b">Cinzia lavora frequentemente su numerose attività differenti alla volta per un singolo progretto, ognuna isolata al sicuro nel proprio repository. Lavorando in questo modo, Cinzia ha spesso bisogno di unire un fremmento del proprio lavoro con un altro.</para>
Giulio@735 17 </listitem>
Giulio@735 18 </itemizedlist>
Giulio@735 19
Giulio@735 20 <para id="x_33c">Dato che abbiamo bisogno di effettuare spesso delle unioni, Mercurial facilita il processo. Camminiamo attraverso una unione. Cominceremo clonando ancora un altro repository (vedete quanto spesso spuntano fuori?) e effettuando un cambiamento in esso.</para>
Giulio@735 21
Giulio@735 22 &interaction.tour.merge.clone;
Giulio@735 23
Giulio@735 24 <para id="x_33d">Ora dovremmo avere due copie di <filename>hello.c</filename> con contenuti differenti. Le cronologie dei due repository ora divergono l'una dall'altra, come illustrato nella <xref linkend="fig:tour-merge:sep-repos"/>. Ecco la copia del nostro file da un repository.</para>
Giulio@735 25
Giulio@735 26 &interaction.tour.merge.cat1;
Giulio@735 27
Giulio@735 28 <para id="x_722">Ed ecco la nostra versione leggermente differente dall'altro.</para>
Giulio@735 29
Giulio@735 30 &interaction.tour.merge.cat2;
Giulio@735 31
Giulio@735 32 <figure id="fig:tour-merge:sep-repos">
Giulio@735 33 <title>Le recenti cronologie divergenti dei repository <filename class="directory">my-hello</filename> e <filename class="directory">my-new-hello</filename></title>
Giulio@735 34 <mediaobject>
Giulio@735 35 <imageobject><imagedata fileref="figs/tour-merge-sep-repos.png"/></imageobject>
Giulio@735 36 <textobject><phrase>XXX add text</phrase></textobject>
Giulio@735 37 </mediaobject>
Giulio@735 38 </figure>
Giulio@735 39
Giulio@735 40 <para id="x_33f">Sappiamo già che estrarre i cambiamenti dal nostro repository <filename class="directory">my-hello</filename> non avrà alcun effetto sulla directory di lavoro.</para>
Giulio@735 41
Giulio@735 42 &interaction.tour.merge.pull;
Giulio@735 43
Giulio@735 44 <para id="x_340">Tuttavia, il comando <command role="hg-cmd">hg pull</command> dice qualcosa a proposito di <quote>teste</quote>.</para>
Giulio@735 45
Giulio@735 46 <sect2>
Giulio@735 47 <title>I changeset di testa</title>
Giulio@735 48
Giulio@735 49 <para id="x_341">Ricordate che Mercurial registra qual è il genitore di ogni cambiamento. Se un cambiamento ha un genitore, chiamiamo quel cambiamento un figlio o discendente del genitore. Una testa è un cambiamento che non ha figli. La revisione di punta è quindi una testa, perché la revisione più recente in un repository non ha alcun figlio. Ci sono occasioni in cui un repository può contenere più di una testa.</para>
Giulio@735 50
Giulio@735 51 <figure id="fig:tour-merge:pull">
Giulio@735 52 <title>I contenuti del repository dopo aver propagato i cambiamenti da <filename class="directory">my-hello</filename> a <filename class="directory">my-new-hello</filename></title>
Giulio@735 53 <mediaobject>
Giulio@735 54 <imageobject>
Giulio@735 55 <imagedata fileref="figs/tour-merge-pull.png"/>
Giulio@735 56 </imageobject>
Giulio@735 57 <textobject><phrase>XXX add text</phrase></textobject>
Giulio@735 58 </mediaobject>
Giulio@735 59 </figure>
Giulio@735 60
Giulio@735 61 <para id="x_343">Dalla figura <xref linkend="fig:tour-merge:pull"/>, potete vedere l'effetto della propagazione dei cambiamenti dal repository <filename class="directory">my-hello</filename> al repository <filename class="directory">my-new-hello</filename>. La cronologia che era già presente in <filename class="directory">my-new-hello</filename> non viene toccata, ma una nuova revisione è stata aggiunta. Riferendoci alla <xref linkend="fig:tour-merge:sep-repos"/>, possiamo vedere che l'<emphasis>identificatore di changeset</emphasis> rimane lo stesso nel nuovo repository, ma che il <emphasis>numero di revisione</emphasis> è cambiato. (Questo, incidentalmente, è un buon esempio del perché non è sicuro usare i numeri di revisione per discutere i changeset.) Possiamo vedere le teste di un repository utilizzando il comando <command role="hg-cmd">hg heads</command>.</para>
Giulio@735 62
Giulio@735 63 &interaction.tour.merge.heads;
Giulio@735 64 </sect2>
Giulio@735 65
Giulio@735 66 <sect2>
Giulio@735 67 <title>Effettuare l'unione</title>
Giulio@735 68
Giulio@735 69 <para id="x_344">Cosa succede se proviamo a usare il normale comando <command role="hg-cmd">hg update</command> per aggiornare alla nuova punta?</para>
Giulio@735 70
Giulio@735 71 &interaction.tour.merge.update;
Giulio@735 72
Giulio@735 73 <para id="x_345">Mercurial ci sta dicendo che il comando <command role="hg-cmd">hg update</command> non farà una unione; non aggiornerà la directory di lavoro quando pensa che potremmo voler fare una unione, a meno che non lo forziamo a farlo. (Incidentalmente, forzare l'aggiornamento con <command>hg update -C</command> would revert any uncommitted changes in the working directory.)</para>
Giulio@735 74
Giulio@735 75 <para id="x_723">Per cominciare una unione tra le due teste, usiamo il comando <command role="hg-cmd">hg merge</command>.</para>
Giulio@735 76
Giulio@735 77 &interaction.tour.merge.merge;
Giulio@735 78
Giulio@735 79 <para id="x_347">We resolve il contenuto del file <filename>hello.c</filename>. Questo aggiorna la directory di lavoro in modo che contenga i cambiamenti da <emphasis>entrambe</emphasis> le teste, cosa che si riflette sia nel risultato del comando <command role="hg-cmd">hg parents</command> sia nei contenuti del file <filename>hello.c</filename>.</para>
Giulio@735 80
Giulio@735 81 &interaction.tour.merge.parents;
Giulio@735 82 </sect2>
Giulio@735 83
Giulio@735 84 <sect2>
Giulio@735 85 <title>Inserire i risultati dell'unione</title>
Giulio@735 86
Giulio@735 87 <para id="x_348">Ogni volta che eseguiamo un'unione, il comando <command role="hg-cmd">hg parents</command> mostrerà due genitori fino a quando non invocheremo <command role="hg-cmd">hg commit</command> per inserire nel repository i risultati dell'unione.</para>
Giulio@735 88
Giulio@735 89 &interaction.tour.merge.commit;
Giulio@735 90
Giulio@735 91 <para id="x_349">Ora abbiamo una nuova revisione di punta; notate che ha <emphasis>entrambe</emphasis> le nostre vecchie teste come suoi genitori. Queste sono le stesse revisioni che erano state precedentemente mostrate da <command role="hg-cmd">hg parents</command>.</para>
Giulio@735 92
Giulio@735 93 &interaction.tour.merge.tip;
Giulio@735 94
Giulio@735 95 <para id="x_34a">Nella <xref linkend="fig:tour-merge:merge"/>, potete vedere una rappresentazione di quanto accade alla directory di lavoro durante l'unione, e di come questo abbia effetto sul repository quando avviene l'inserimento. Durante l'unione, la directory di lavoro ha due changeset genitori e questi diventano i genitori del nuovo changeset.</para>
Giulio@735 96
Giulio@735 97 <figure id="fig:tour-merge:merge">
Giulio@735 98 <title>Lo stato della directory di lavoro e del repository durante l'unione e dopo l'inserimento</title>
Giulio@735 99 <mediaobject>
Giulio@735 100 <imageobject>
Giulio@735 101 <imagedata fileref="figs/tour-merge-merge.png"/>
Giulio@735 102 </imageobject>
Giulio@735 103 <textobject><phrase>XXX add text</phrase></textobject>
Giulio@735 104 </mediaobject>
Giulio@735 105 </figure>
Giulio@735 106
Giulio@735 107 <para id="x_69c">Talvolta si dice che un'unione è composta da due <emphasis>parti</emphasis>: la parte sinistra è il primo genitore nell'uscita di <command role="hg-cmd">hg parents</command>, e la parte destra è il secondo. Se per esempio la directory di lavoro si trovava alla revisione 5 prima che cominciassimo l'unione, quella revisione diventerà la parte sinistra dell'unione.</para>
Giulio@735 108 </sect2>
Giulio@735 109 </sect1>
Giulio@735 110
Giulio@735 111 <sect1>
Giulio@735 112 <title>Unire cambiamenti conflittuali</title>
Giulio@735 113
Giulio@735 114 <para id="x_34b">La maggior parte delle unioni sono faccende semplici, ma talvolta vi troverete a unire cambiamenti dove ognuna delle due parti modifica le stesse porzioni degli stessi file. A meno che entrambe le modifiche siano identiche, questo risulterà in un <emphasis>conflitto</emphasis>, dove voi dovete decidere come riconciliare i diversi cambiamenti in un risultato coerente.</para>
Giulio@735 115
Giulio@735 116 <figure id="fig:tour-merge:conflict">
Giulio@735 117 <title>Cambiamenti in conflitto a un documento</title>
Giulio@735 118 <mediaobject>
Giulio@735 119 <imageobject><imagedata fileref="figs/tour-merge-conflict.png"/></imageobject>
Giulio@735 120 <textobject><phrase>XXX add text</phrase></textobject>
Giulio@735 121 </mediaobject>
Giulio@735 122 </figure>
Giulio@735 123
Giulio@735 124 <para id="x_34d">La <xref linkend="fig:tour-merge:conflict"/> illustra un esempio di due cambiamenti in conflitto a un documento. Abbiamo cominciato con una singola versione del file; poi abbiamo fatto alcuni cambiamenti; mentre qualcun altro ha fatto cambiamenti differenti allo stesso testo. Il nostro compito nella risoluzione del conflitto tra i cambiamenti è quello di decidere che cosa dovrebbe contenere il file.</para>
Giulio@735 125
Giulio@735 126 <para id="x_34e">Mercurial non è dotato di uno strumento predefinito per gestire i conflitti. Invece, esegue un programma esterno, di solito uno che mostra un qualche tipo di interfaccia grafica per la risoluzione dei conflitti. Di default, Mercurial prova a trovare uno tra i vari strumenti di unione differenti che è probabile siano installati sul vostro sistema. Prima prova a cercare alcuni strumenti di unione completamente automatici; se non riesce a trovarli (perché il processo di risoluzione richiede una guida umana) o non sono presenti, prova vari altri strumenti grafici per le unioni.</para>
Giulio@735 127
Giulio@735 128 <para id="x_34f">&Egrave; anche possibile far eseguire a Mercurial uno specifico programma, impostando la variable di ambiente <envar>HGMERGE</envar> al nome del vostro programma preferito.</para>
Giulio@735 129
Giulio@735 130 <sect2>
Giulio@735 131 <title>Usare uno strumento grafico per le unioni</title>
Giulio@735 132
Giulio@735 133 <para id="x_350">Il mio strumento grafico per le unioni preferito è <command>kdiff3</command>, che userà per descrivere le caratteristiche che sono comuni agli strumenti grafici per l'unione di file. Potete vedere uno screenshot di <command>kdiff3</command> in azione nella <xref linkend="fig:tour-merge:kdiff3"/>. Il tipo di unione che sta eseguendo si chiama <emphasis>unione a tre vie</emphasis>, perché ci sono tre differenti versioni di un file che ci interessano. Lo strumento dunque divide la porzione superiore della finestra in tre pannelli:</para>
Giulio@735 134 <itemizedlist>
Giulio@735 135 <listitem><para id="x_351">A sinistra si trova la versione <emphasis>base</emphasis> del file, i.e. la versione più recente da cui le due versioni che stiamo cercando di unire discendono.</para>
Giulio@735 136 </listitem>
Giulio@735 137 <listitem><para id="x_352">Nel mezzo si trova la <quote>nostra</quote> versione del file, con i contenuti che abbiamo modificato.</para>
Giulio@735 138 </listitem>
Giulio@735 139 <listitem><para id="x_353">A destra troviamo la <quote>loro</quote> versione del file, quella che proviene dal changeset che stiamo cercando di incorporare.</para>
Giulio@735 140 </listitem></itemizedlist>
Giulio@735 141 <para id="x_354">Nel pannello sotto a questi si trova il <emphasis>risultato</emphasis> corrente dell'unione. Il nostro compito è quello di sostituire tutto il testo in rosso, che indica conflitti irrisolti, con una qualche unione ragionevole della <quote>nostra</quote> e della <quote>loro</quote> versione del file.</para>
Giulio@735 142
Giulio@735 143 <para id="x_355">Tutti e quattro questi pannelli sono <emphasis>collegati tra loro</emphasis>; se scrolliamo in verticale o in orizzontale in ognuo di essi, gli altri vengono aggiornati per mostrare le sezioni corrispondenti dei rispettivi file.</para>
Giulio@735 144
Giulio@735 145 <figure id="fig:tour-merge:kdiff3">
Giulio@735 146 <title>Usare <command>kdiff3</command> per unire versioni di un file</title>
Giulio@735 147 <mediaobject>
Giulio@735 148 <imageobject>
Giulio@735 149 <imagedata width="100%" fileref="figs/kdiff3.png"/></imageobject>
Giulio@735 150 <textobject>
Giulio@735 151 <phrase>XXX add text</phrase>
Giulio@735 152 </textobject>
Giulio@735 153 </mediaobject>
Giulio@735 154 </figure>
Giulio@735 155
Giulio@735 156 <para id="x_357">Per ogni porzione conflittuale del file, possiamo scegliere di risolvere il conflitto usando una qualche combinazione di testo dalla versione base, dalla nostra, o dalla loro. Possiamo anche modificare manualmente il file unito in ogni momento, nel caso abbiamo bisogno di effettuare cambiamenti ulteriori.</para>
Giulio@735 157
Giulio@735 158 <para id="x_358">Esistono <emphasis>molti</emphasis> strumenti per l'unione di file, davvero troppi per elencarli qui. Essi variano a seconda della piattaforma per la quale sono disponibili, e nelle loro particolari forze e debolezze. La maggior parte è tuned per unire file contenenti testo semplice, mentre alcuni sono indirizzati a particolari formati di file (generalmente XML).</para>
Giulio@735 159 </sect2>
Giulio@735 160
Giulio@735 161 <sect2>
Giulio@735 162 <title>Un esempio lavorato</title>
Giulio@735 163
Giulio@735 164 <para id="x_359">In questo esempio, riprodurremo le cronologia delle modifiche ai file della <xref linkend="fig:tour-merge:conflict"/> precedente. Per cominciare, creiamo un repository con una versione base del nostro documento.</para>
Giulio@735 165
Giulio@735 166 &interaction.tour-merge-conflict.wife;
Giulio@735 167
Giulio@735 168 <para id="x_35a">Cloniamo il repository e apportiamo un cambiamento al file.</para>
Giulio@735 169
Giulio@735 170 &interaction.tour-merge-conflict.cousin;
Giulio@735 171
Giulio@735 172 <para id="x_35b">E ora aggiungiamo un altro clone, per simulare qualcun altro che effettui un cambiamento al file. (Questo suggerisce l'idea che non è affatto inusuale unire con sé stessi quando isolate le vostre attività in repository separati, e in effetti trovate e risolvete conflitti mentre fate così.)</para>
Giulio@735 173
Giulio@735 174 &interaction.tour-merge-conflict.son;
Giulio@735 175
Giulio@735 176 <para id="x_35c">Avendo creato due versioni differenti del file, impostiamo un ambiente adeguato a eseguire la nostra unione.</para>
Giulio@735 177
Giulio@735 178 &interaction.tour-merge-conflict.pull;
Giulio@735 179
Giulio@735 180 <para id="x_35d">In questo esempio, imposterò la variabile d'ambiente <envar>HGMERGE</envar> per dire a Mercurial di usare il comando non interattivo <command>merge</command>. Questo comando è incluso in molti sistemi Unix-like. (Se state seguento questo esempio sul vostro computer, non preoccupatevi di impostare <envar>HGMERGE</envar>. Verrete depositati in uno strumento grafico per l'unione dei file, che è di molto preferibile.)</para>
Giulio@735 181
Giulio@735 182 &interaction.tour-merge-conflict.merge;
Giulio@735 183
Giulio@735 184 <para id="x_35f">Dato che <command>merge</command> non riesce a risolvere il conflitto tra i cambiamenti, lascia <emphasis>marcatori di unione</emphasis> dentro al file che ha i conflitti, indicando quali righe sono in conflitto e se vengono dalla nostra versione del file o dalla loro.</para>
Giulio@735 185
Giulio@735 186 <para id="x_360">Mercurial può dire dal modo in cui <command>merge</command> esce che non è stato in grado di unire con successo, quindi ci dice quali comandi abbiamo bisogno di eseguire se vogliamo rifare l'operazione di unione. Questo potrebbe essere utile se, per esempio, stessimo eseguendo uno strumento di unione grafico e uscissimo perché siamo confusi o realizziamo di aver fatto un errore.</para>
Giulio@735 187
Giulio@735 188 <para id="x_361">Se l'unione automatica o manuale fallisce, non c'è nulla che ci impedisce di <quote>correggere</quote> i file interessati per conto nostro, per inserire poi nel repository i risultati della nostra unione:</para>
Giulio@735 189
Giulio@735 190 &interaction.tour-merge-conflict.commit;
Giulio@735 191
Giulio@735 192 <note>
Giulio@735 193 <title>Dov'è il comando <command>hg resolve</command>?</title>
Giulio@735 194
Giulio@735 195 <para id="x_724">Il comando <command>hg resolve</command> è stato introdotto nella verisone 1.1 di Mercurial, che è stata rilasciata nel dicembre 2008. Se state usando una versione più vecchia (eseguite <command>hg version</command> per controllare) questo comando non sarà presente. Se la vostra versione di Mercurial è più vecchia della 1.1, vi consiglio vivamente di installare una versione più nuova prima di affrontare unioni complicate.</para>
Giulio@735 196 </note>
Giulio@735 197 </sect2>
Giulio@735 198 </sect1>
Giulio@735 199
Giulio@735 200 <sect1 id="sec:tour-merge:fetch">
Giulio@735 201 <title>Semplificare la sequenza di estrazione-unione-inserimento</title>
Giulio@735 202
Giulio@735 203 <para id="x_362">Il processo di unione dei cambiamenti come delineato in precedenza è molto semplice, ma richiede di eseguire tre comandi in sequenza.</para>
Giulio@735 204 <programlisting>hg pull -u
Giulio@735 205 hg merge
Giulio@735 206 hg commit -m 'Incorporati i cambiamenti remoti'</programlisting>
Giulio@735 207 <para id="x_363">Nel caso dell'inserimento conclusivo, avete anche bisogno di inserire un messaggio di commit, che sarà quasi sempre un frammento di testo <quote>boilerplate</quote> non interessante.</para>
Giulio@735 208
Giulio@735 209 <para id="x_364">Sarebbe carino ridurre il numero di passi necessari, se questo fosse possibile. In effetti, Mercurial viene distribuito con una estensione chiamata <literal role="hg-ext">fetch</literal> che fa proprio questo.</para>
Giulio@735 210
Giulio@735 211 <para id="x_365">Mercurial fornisce un meccanismo flessibile di estensione che permette alle persone di estendere le sue funzionalità mantenendo il cuore di Mercurial piccolo e facile da trattare. Alcune estensioni aggiungono nuovi comandi che potete usare dalla linea di comando, mentre altri lavorano <quote>dietro le quinte</quote>, per esempio aggiungendo funzionalità alla modalità server predefinita di Mercurial.</para>
Giulio@735 212
Giulio@735 213 <para id="x_366">L'estensione <literal role="hg-ext">fetch</literal> aggiunge un nuovo comando chiamato, ovviamente, <command role="hg-cmd">hg fetch</command>. Questa estensione agisce come una combinazione di <command role="hg-cmd">hg pull -u</command>, <command role="hg-cmd">hg merge</command> e <command role="hg-cmd">hg commit</command>. Comincia propagando i cambiamenti da un altro repository verso il repository corrente. Se trova che i cambiamenti aggiungono una nuova testa al repository, lo aggiorna alla nuova testa, comincia una unione, poi (se l'unione ha successo) inserisce il risultato dell'unione nel repository con un messaggio di commit generato automaticamente. Se non sono state aggiunte nuove teste, il comando aggiorna la directory di lavoro alla nuova revisione di punta.</para>
Giulio@735 214
Giulio@735 215 <para id="x_367">Abilitare l'estensione <literal role="hg-ext">fetch</literal> è facile. Aprite il file <filename role="special">.hgrc</filename> nella vostra directory personale e andate alla sezione <literal role="rc-extensions">extensions</literal> oppure create una sezione <literal role="rc-extensions">extensions</literal> se non esiste già. Poi aggiungete una riga che contenga semplicemente <quote><literal>fetch=</literal></quote>.</para>
Giulio@735 216
Giulio@735 217 <programlisting>[extensions]
Giulio@735 218 fetch =</programlisting>
Giulio@735 219
Giulio@735 220 <para id="x_368">(Normalmente, il lato destro del simbolo <quote><literal>=</literal></quote> indicherebbe dove trovare l'estensione, ma dato che l'estensione <literal role="hg-ext">fetch</literal> è nella distribuzione standard, Mercurial sa già dove andarla a cercare.)</para>
Giulio@735 221 </sect1>
Giulio@735 222
Giulio@735 223 <sect1>
Giulio@735 224 <title>Rinominare, copiare e unire</title>
Giulio@735 225
Giulio@735 226 <para id="x_729">Durante la vita di un progetto, vorremo spesso cambiare la disposizione dei suoi file e delle sue directory. Questo può essere tanto semplice quanto rinominare un singolo file, o tanto complesso quanto ristrutturare l'intera gerarchia dei file nell'ambito del progetto.</para>
Giulio@735 227
Giulio@735 228 <para id="x_72a">Mercurial supporta questi tipi di cambiamenti complessi in maniera fluida, a patto che gli diciamo quello stiamo facendo. Se vogliamo rinominare un file, dovremmo usare il comando <command>hg rename</command><footnote>
Giulio@735 229 <para id="x_72b">Se siete utenti Unix, sarete contenti di sapere che il comando <command>hg rename</command> si può abbreviare in <command>hg mv</command>.</para>
Giulio@735 230 </footnote> per cambiarne il nome, in modo che Mercurial possa fare la cosa giusta più tardi quando effettueremo un'unione.</para>
Giulio@735 231
Giulio@735 232 <para id="x_72c">Tratteremo l'uso di questi comandi in maniera più estesa nel FIXME<!--<xref linkend="chap:daily.copy"/>-->.</para>
Giulio@735 233 </sect1>
Giulio@735 234 </chapter>