hgbook

annotate it/ch13-mq-collab.xml @ 769:459ea1807ef8

Literal translation of Ch.13.
author Giulio@puck
date Thu Jul 30 10:21:50 2009 +0200 (2009-07-30)
parents
children 4ce173218096
rev   line source
Giulio@769 1 <chapter id="chap:mq-collab">
Giulio@769 2 <?dbhtml filename="usi-avanzati-di-mercurial-queues.html"?>
Giulio@769 3 <title>Usi avanzati di Mercurial Queues</title>
Giulio@769 4
Giulio@769 5 <para id="x_15d">Mentre è facile imparare gli usi più semplici di Mercurial Queues, l'uso di un po' di disciplina e di alcune delle capacità di MQ usate meno frequentemente rende possibile lavorare in ambienti di sviluppo complicati.</para>
Giulio@769 6
Giulio@769 7 <para id="x_15e">In questo capitolo, userò come esempio una tecnica che ho usato per gestire lo sviluppo di un driver del kernel di Linux per un dispositivo Infiniband. Il driver in questione è grande (almeno per le dimensioni dei driver), con 25.000 righe di codice sparse su 35 file sorgente. Viene mantenuto da un piccolo gruppo di sviluppatori.</para>
Giulio@769 8
Giulio@769 9 <para id="x_15f">Sebbene la maggior parte del materiale in questo capitolo sia specifica per Linux, gli stessi principi si applicano per qualsiasi base di codice di cui non siate i proprietari principali e su cui dobbiate fare un bel po' di lavoro.</para>
Giulio@769 10
Giulio@769 11 <sect1>
Giulio@769 12 <title>Il problema dei molti obiettivi</title>
Giulio@769 13
Giulio@769 14 <para id="x_160">Il kernel di Linux cambia rapidamente e non è mai stato stabile internamente, in quanto gli sviluppatori effettuano frequentemente modifiche drastiche tra una release e l'altra. Questo significia che una versione del driver che funziona bene con una particolare release del kernel non sarà nemmeno in grado di <emphasis>compilare</emphasis> correttamente su, tipicamente, qualsiasi altra versione.</para>
Giulio@769 15
Giulio@769 16 <para id="x_161">Per mantenere un driver, dobbiamo tenere a mente un certo numero di versioni di Linux differenti.</para>
Giulio@769 17 <itemizedlist>
Giulio@769 18 <listitem><para id="x_162">Un obiettivo è l'albero di sviluppo principale del kernel di Linux. In questo caso, il mantenimento del codice è parzialmente condiviso con altri sviluppatori della comunità del kernel, che effettuano modifiche <quote>#drive-by#</quote> al driver man mano che sviluppano e rifiniscono i sottosistemi del kernel.</para>
Giulio@769 19 </listitem>
Giulio@769 20 <listitem><para id="x_163">Manteniamo anche un certo numero di <quote>#backports#</quote> verso vecchie versioni del kernel di Linux, per supportare le necessità di cienti che stanno utilizzando distribuzioni di Linux più vechie che non incorporano i nostri driver. (Effetuare il <emphasis>#backport#</emphasis> del codice significa modificarlo per farlo funzionare in una versione del suo ambiente obiettivo più vecchia di quella per la quale era stato sviluppato.)</para>
Giulio@769 21 </listitem>
Giulio@769 22 <listitem><para id="x_164">Infine, rilasciamo il software seguendo un'agenda che non è necessariamente allineata con quella usata dagli sviluppatori del kernel e dai distributori di Linux, in modo che possiamo consegnare nuove funzionalità ai cienti senza obbligarli ad aggiornare il loro kernel o la loro intera distribuzione.</para>
Giulio@769 23 </listitem>
Giulio@769 24 </itemizedlist>
Giulio@769 25
Giulio@769 26 <sect2>
Giulio@769 27 <title>Approcci seducenti che non funzionano bene</title>
Giulio@769 28
Giulio@769 29 <para id="x_165">Ci sono due modi <quote>standard</quote> per mantenere un software che ha come obiettivo molti ambienti diversi.</para>
Giulio@769 30
Giulio@769 31 <para id="x_166">Il primo è mantenere un certo numero di rami, ognuno designato per un singolo obiettivo. Il problema di questo approccio è che dovete mantenere una ferrea disciplina nel flusso dei cambiamenti tra i repository. Una nuova funzione o correzione di bug deve prendere vita in un repository <quote>intatto</quote>, poi passare a tutti i repository #backport#. Le modifiche di #backport# sono più limitate nei rami in cui dovrebbero propagarsi; una modifica di #backport# che viene applicata a un ramo a cui non appartiene probabilmente impedirebbe al driver di compilare.</para>
Giulio@769 32
Giulio@769 33 <para id="x_167">Il secondo è quello di mantenere un singolo albero di sorgenti pieno di istruzioni condizionali che attivano o disattivano pezzi di codice a seconda dell'obiettivo designato. Dato che queste istruzioni <quote>ifdefs</quote> non sono permesse nell'albero del kernel di Linux, un processo manuale o automatico deve essere seguito per eliminarli e produrre un albero pulito. Una base di codice mantenuta in questo modo diventa rapidamente un macello di blocchi condizionali che sono difficili da capire e mantenere.</para>
Giulio@769 34
Giulio@769 35 <para id="x_168">Nessuno di questi approcci è particolarmente adatto a situaizoni in cui non <quote>possedete</quote> la copia canonica di un albero di sorgenti. Nel caso di un driver Linux che viene distribuito insieme al kernel stadard, l'albero di Linus contiene la copia del codice che il mondo tratterà come canonica. La versione a monte del <quote>mio</quote> driver può essere modificata da persone che non conosco, senza che io nemmeno lo scopra fino a quando i cambiamenti non appaiono nell'albero di Linus.</para>
Giulio@769 36
Giulio@769 37 <para id="x_169">Questi approcci hanno la debolezza aggiunta di rendere difficile generare patch ben formate da sottoporre a monte.</para>
Giulio@769 38
Giulio@769 39 <para id="x_16a">In linea di principio, Mercurial Queues sembra un buon candidato per gestire uno scenario di sviluppo come quello qui delineato. Sebbene questo sia indubbiamente il caso, MQ contiene anche alcune funzioni aggiuntive che rendono il lavoro più piacevole.</para>
Giulio@769 40
Giulio@769 41 </sect2>
Giulio@769 42 </sect1>
Giulio@769 43 <sect1>
Giulio@769 44 <title>Applicare patch in maniera condizionata con le guardie</title>
Giulio@769 45
Giulio@769 46 <para id="x_16b">Forse il miglior modo per mantenere la sanità con così tanti obiettivi è quello di essere in grado di scegliere patch specifiche da applicare a una data situazione. MQ fornisce una funzione chiamata <quote>guardie</quote> (originata dal comando <literal>guards</literal> di quilt) che fa proprio questo. Per cominciare, creiamo un semplice repository per fare qualche esperimento.</para>
Giulio@769 47
Giulio@769 48 &interaction.mq.guards.init;
Giulio@769 49
Giulio@769 50 <para id="x_16c">Questo ci dà un piccolo repository che contiene due patch che non hanno alcuna dipendenza reciproca, perché toccano file differenti.</para>
Giulio@769 51
Giulio@769 52 <para id="x_16d">L'idea dietro all'applicazione condizionale è che potete <quote>etichettare</quote> una patch con una <emphasis>guardia</emphasis>, che è semplicemente una stringa di testo di vostra scelta, poi dire a MQ di selezionare le guardie specifiche da usare al momento di applicare le patch. MQ applicherà, o salterà, una patch con guardia, a seconda delle guardie che avete selezionato.</para>
Giulio@769 53
Giulio@769 54 <para id="x_16e">Una patch può avere un numero arbitrario di guardie, ognuna delle quali è <emphasis>positiva</emphasis> (<quote>applica questa patch se questa guardia è selezionata</quote>) o <emphasis>negativa</emphasis> (<quote>salta questa patch se questa guardia è selezionata</quote>). Una patch senza alcuna guardia viene sempre applicata.</para>
Giulio@769 55
Giulio@769 56 </sect1>
Giulio@769 57 <sect1>
Giulio@769 58 <title>Controllare le guardie su una patch</title>
Giulio@769 59
Giulio@769 60 <para id="x_16f">Il comando <command role="hg-ext-mq">qguard</command> vi permette di determinare quali guardie dovrebbero applicarsi a una patch, o di visualizzare le guardie che sono già in effetto. Senza alcun argomento, il comando mosra le guardie della patch correntemente in cima alla pila.</para>
Giulio@769 61
Giulio@769 62 &interaction.mq.guards.qguard;
Giulio@769 63
Giulio@769 64 <para id="x_170">Per impostare una guardia positiva su una patch, fate precedere il nome della guardia da un <quote><literal>+</literal></quote>.</para>
Giulio@769 65
Giulio@769 66 &interaction.mq.guards.qguard.pos;
Giulio@769 67
Giulio@769 68 <para id="x_171">Per impostare una guardia negativa, fate precedere il nome della guardia da un <quote><literal>-</literal></quote>.</para>
Giulio@769 69
Giulio@769 70 &interaction.mq.guards.qguard.neg;
Giulio@769 71
Giulio@769 72 <para id="x_74a">Notate che in questo caso gli argomenti del comando <command>hg qguard</command> sono introdotti con il prefisso <literal>--</literal>, così Mercurial non interpreterà il testo <literal>-quux</literal> come un'opzione.</para>
Giulio@769 73
Giulio@769 74 <note>
Giulio@769 75 <title>Impostare e modificare</title>
Giulio@769 76
Giulio@769 77 <para id="x_172">Il comando <command role="hg-ext-mq">qguard</command> <emphasis>imposta</emphasis> le guardie su una patch, ma non le <emphasis>modifica</emphasis>. Questo significa che se invocate <command role="hg-cmd">hg qguard +a +b</command> su una patch, quindi invocate <command role="hg-cmd">hg qguard +c</command> sulla stessa patch, l'<emphasis>unica</emphasis> guardia che verrà impostata successivamente sarà <literal>+c</literal>.</para>
Giulio@769 78 </note>
Giulio@769 79
Giulio@769 80 <para id="x_173">Mercurial memorizza le guardie nel file <filename role="special">series</filename>, in una forma facile sia da capire che da modificare a mano. (In altre parole, non dovete usare il comando <command role="hg-ext-mq">qguard</command> se non volete, perché potete tranquillamente modificare direttamente il file <filename role="special">series</filename> file.)</para>
Giulio@769 81
Giulio@769 82 &interaction.mq.guards.series;
Giulio@769 83
Giulio@769 84 </sect1>
Giulio@769 85 <sect1>
Giulio@769 86 <title>Selezionare le guardie da usare</title>
Giulio@769 87
Giulio@769 88 <para id="x_174">Il comando <command role="hg-ext-mq">qselect</command> determina quali guardie sono attive in un dato momento. Il suo effetto è quello di determinare quali patch verranno applicate da MQ la prossima volta che invocherete <command role="hg-ext-mq">qpush</command>. Non ha alcun altro effetto, in particolare non agisce in alcun modo sulle patch che sono già applicate.</para>
Giulio@769 89
Giulio@769 90 <para id="x_175">Invocato senza argomenti, il comando <command role="hg-ext-mq">qselect</command> elenca le guardie attualmente in effetto, una per ogni riga di output. Ogni argomento viene trattato come il nome di una guardia da applicare.</para>
Giulio@769 91
Giulio@769 92 &interaction.mq.guards.qselect.foo;
Giulio@769 93
Giulio@769 94 <para id="x_176">Nel caso siate interessati, le guardie attualmente selezionate vengono memorizzate nel file <filename role="special">guards</filename>.</para>
Giulio@769 95
Giulio@769 96 &interaction.mq.guards.qselect.cat;
Giulio@769 97
Giulio@769 98 <para id="x_177">Possiamo vedere gli effetti delle guardie selezionate quando invochiamo <command role="hg-ext-mq">qpush</command>.</para>
Giulio@769 99
Giulio@769 100 &interaction.mq.guards.qselect.qpush;
Giulio@769 101
Giulio@769 102 <para id="x_178">Una guardia non può cominciare con un carattere <quote><literal>+</literal></quote> o un carattere <quote><literal>-</literal></quote>. Il nome di una guardia non deve contenere spazio bianco, ma la maggior parte degli altri caratteri sono accettabili. Se provate a usare una guardia con un nome non valido, MQ se ne lamenterà.</para>
Giulio@769 103
Giulio@769 104 &interaction.mq.guards.qselect.error;
Giulio@769 105
Giulio@769 106 <para id="x_179">Cambiare le guardie selezionate cambia le patch che vengono applicate.</para>
Giulio@769 107
Giulio@769 108 &interaction.mq.guards.qselect.quux;
Giulio@769 109
Giulio@769 110 <para id="x_17a">Potete vedere nell'esempio seguente che le guardie negative hanno la precedenza sulle guardie positive.</para>
Giulio@769 111
Giulio@769 112 &interaction.mq.guards.qselect.foobar;
Giulio@769 113
Giulio@769 114 </sect1>
Giulio@769 115 <sect1>
Giulio@769 116 <title>Le regole di MQ per applicare le patch</title>
Giulio@769 117
Giulio@769 118 <para id="x_17b">Le regole usate da MQ per decidere se applicare una patch sono le seguenti.</para>
Giulio@769 119 <itemizedlist>
Giulio@769 120 <listitem><para id="x_17c">Una patch che non ha guardie è sempre applicata.</para>
Giulio@769 121 </listitem>
Giulio@769 122 <listitem><para id="x_17d">Se la patch ha una qualsiasi guardia negativa che corrisponde a una qualsiasi guardia correntemente selezionata, la patch viene saltata.</para>
Giulio@769 123 </listitem>
Giulio@769 124 <listitem><para id="x_17e">Se la patch ha una qualsiasi guardia positiva che corrisponde a una qualsiasi guardia correntemente selezionata, la patch viene applicata.</para>
Giulio@769 125 </listitem>
Giulio@769 126 <listitem><para id="x_17f">Se la patch ha guardie positive o negative, ma nessuna corrisponde a qualsiasi guardia correntemente selezionata, la patch viene saltata.</para>
Giulio@769 127 </listitem>
Giulio@769 128 </itemizedlist>
Giulio@769 129
Giulio@769 130 </sect1>
Giulio@769 131 <sect1>
Giulio@769 132 <title>Riordinare l'ambiente di lavoro</title>
Giulio@769 133
Giulio@769 134 <para id="x_180">Lavorando sul driver di dispositivo menzionato in precedenza, non applico le patch a un normale albero del kernel di Linux. invece, uso un repository che contiene solo una fotografia dei file sorgente che sono rilevanti per lo sviluppo del dispositivo Infiniband. Le dimensioni di questo repository sono l'1% delle dimensioni di un repository del kernel, quindi è più facile lavorare con esso.</para>
Giulio@769 135
Giulio@769 136 <para id="x_181">Quindi scelgo una versione <quote>di base</quote> sulla quale le patch vengono applicate. Questa è la fotografia dell'albero del kernel di Linux a una revisione di mia scelta. Quando scatto la fotografia, registro l'identificatore di changeset dal repository del kernel nel messaggio di commit. Dato che la fotografia mantiene la <quote>forma</quote> e il contenuto delle parti rilevanti dell'albero del kernel, posso applicare le mie patch sul mio repository ridotto o sul un normale albero del kernel.</para>
Giulio@769 137
Giulio@769 138 <para id="x_182">Normalmente, l'albero di base a cui applicare le patch dovrebbe essere una fotografia di un albero a monte molto recente. Questo facilita al meglio lo sviluppo di patch che possono essere facilmente sottoposte a monte con poche o addirittura nessuna modifica.</para>
Giulio@769 139
Giulio@769 140 </sect1>
Giulio@769 141 <sect1>
Giulio@769 142 <title>Suddividere il file <filename role="special">series</filename></title>
Giulio@769 143
Giulio@769 144 <para id="x_183">Categorizzo le patch nel file <filename role="special">series</filename> in un certo numero di gruppi logici. Ogni sezione di patch simili comincia con un blocco di commenti che descrive lo scopo delle patch che seguono.</para>
Giulio@769 145
Giulio@769 146 <para id="x_184">La sequenza dei gruppi di patch che mantengo è la seguente. L'ordine di questi gruppi è importante per i motivi che verranno descritti dopo aver introdotto i gruppi.</para>
Giulio@769 147 <itemizedlist>
Giulio@769 148 <listitem><para id="x_185">Il gruppo delle patch <quote>accettate</quote>. Sono le patch che il gruppo di sviluppo ha sottoposto al mantenitore del sottosistema Infiniband e che sono state accettate, ma che non sono presenti nella fotografia su cui il repository ridotto è basato. Queste sono patch <quote>a sola lettura</quote>, presenti solo allo scopo di trasformare l'albero in uno stato simile a quello in cui si trova nel repository del mantenitore a monte.</para>
Giulio@769 149 </listitem>
Giulio@769 150 <listitem><para id="x_186">Il gruppo delle patch da <quote>rielaborare</quote>. Sono le patch che ho sottoposto ma per le quali il mantenitore a monte ha richiesto alcune modifiche prima di poterle accettare.</para>
Giulio@769 151 </listitem>
Giulio@769 152 <listitem><para id="x_187">Il gruppo delle patch <quote>in sospeso</quote>. Sono le patch che non ho ancora sottoposto al mantenitore a monte, ma su cui dobbiamo finire di lavorare. Queste patch saranno <quote>a sola lettura</quote> per un po'. Se il mantenitore a monte le accetta al momento di sottoporle, le sposterò alla fine del gruppo <quote>accettate</quote>. Se ne richiede la modifica, le sposterò all'inizio del gruppo da <quote>rielaborare</quote>.</para>
Giulio@769 153 </listitem>
Giulio@769 154 <listitem><para id="x_188">Il gruppo delle patch <quote>in corso</quote>. Sonon le patch che vengono attivamente sviluppate e che non dovrebbero essere ancora sottoposte a nessuno.</para>
Giulio@769 155 </listitem>
Giulio@769 156 <listitem><para id="x_189">Il gruppo delle patch <quote>#backport#</quote>. Sono le patch che riadattano l'albero dei sorgenti a una vecchia versione dell'albero del kernel.</para>
Giulio@769 157 </listitem>
Giulio@769 158 <listitem><para id="x_18a">Il gruppo delle patch da <quote>non rilasciare</quote>. Sono le patch che per qualche ragione non dovrebbero mai essere sottoposte a monte. Per esempio, una patch di questo tipo potrebbe modificare le stringhe di identificazione incluse nei driver per rendere più facile distinguere, nel campo, tra una versione del driver presa dall'albero e una versione consegnata a un venditore di distribuzioni.</para>
Giulio@769 159 </listitem>
Giulio@769 160 </itemizedlist>
Giulio@769 161
Giulio@769 162 <para id="x_18b">Tornando alle ragioni per cui i gruppi di patch sono ordinati in questo modo, ci piacerebbe che le patch più in basso nella pila siano stabili il più possibile, in modo da non aver bisogno di rielaborare le patch più in alto a causa di modifiche a loro contesto. Mettere le patch che non verranno mai cambiate all'inizio del file <filename role="special">series</filename> serve proprio a questo scopo.</para>
Giulio@769 163
Giulio@769 164 <para id="x_18c">Ci piacerebbe anche applicare le patch che sappiamo di aver bisogno di modificare in cima a un albero di sorgenti che somiglia il più possibile all'albero a monte. Questo è il motivo per cui teniamo le patch accettate in giro per un po'.</para>
Giulio@769 165
Giulio@769 166 <para id="x_18d">Le patch dei gruppi <quote>#backport#</quote> e <quote>non rilasciare</quote> si trovano alla fine del file <filename role="special">series</filename>. Le patch #backport# devono essere applicate su tutte le altre patch e anche le patch da <quote>non rilasciare</quote> potrebbero starsene al sicuro.</para>
Giulio@769 167
Giulio@769 168 </sect1>
Giulio@769 169 <sect1>
Giulio@769 170 <title>Mantenere le serie di patch</title>
Giulio@769 171
Giulio@769 172 <para id="x_18e">Nel mio lavoro, uso un certo numero di guardie per controllare quali patch devono essere applicate.</para>
Giulio@769 173
Giulio@769 174 <itemizedlist>
Giulio@769 175 <listitem><para id="x_18f">Le patch <quote>accettate</quote> sono sorvegliate da <literal>accepted</literal>. Questa guardia è abilitata per la maggior parte del tempo. Quando sto applicando le patch su un albero dove le patch sono già presenti, posso disabilitare questa patch così le patch che la seguono verranno applicate in maniera pulita.</para>
Giulio@769 176 </listitem>
Giulio@769 177 <listitem><para id="x_190">Le patch che sono <quote>terminate</quote>, ma non ancora sottoposte, non hanno guardie. Se sto applicando la pila delle patch a una copia dell'albero a monte, non ho bisogno di abilitare alcuna guardia per ottenere un albero di sorgenti ragionevolmente sicuro.</para>
Giulio@769 178 </listitem>
Giulio@769 179 <listitem><para id="x_191">Le patch che hanno bisogno di essere rielaborate prima di venire nuovamente sottoposte sono sorvegliate da <literal>rework</literal>.</para>
Giulio@769 180 </listitem>
Giulio@769 181 <listitem><para id="x_192">Per quelle patch che sono ancora sotto sviluppo, uso <literal>devel</literal>.</para>
Giulio@769 182 </listitem>
Giulio@769 183 <listitem><para id="x_193">Una patch #backport# potrebbe avere diverse guardie, una per ogni versione del kernel a cui si applica. Per esempio, una patch che #backports# una parte del codice alla versione 2.6.9 del kernel avrà una guardia <literal>2.6.9</literal> guard.</para>
Giulio@769 184 </listitem>
Giulio@769 185 </itemizedlist>
Giulio@769 186 <para id="x_194">Questa varietà di guardie mi concede una flessibilità considerevole nel determinare quale tipo di albero dei sorgenti creare. Per la maggior parte delle situazioni, la selezione delle guardie appropriate viene automatizzata durante il processo di assemblaggio, ma posso regolare manualmente le guardie da usare nelle circostanze meno comuni.</para>
Giulio@769 187
Giulio@769 188 <sect2>
Giulio@769 189 <title>L'arte di scrivere patch #backport#</title>
Giulio@769 190
Giulio@769 191 <para id="x_195">Usando MQ, scrivere una patch #backport# è un processo semplice. Tutto quello che una patch di questo tipo deve fare è modificare una parte di codice che usa una funzione del kernel non presente in una vecchia versione del kernel, in modo che il driver continui a funzionare correttamente con la vecchia versione.</para>
Giulio@769 192
Giulio@769 193 <para id="x_196">Un obiettivo utile da raggiungere nella scrittura di una buona patch #backport# è far sembrare il codice come se fosse stato scritto per la vecchia versione del kernel che state considerando. Meno intrusiva è la patch, più facile sarà da capire e mantenere. Se state scrivendo una collezione di patch #backport# per evitare l'effetto <quote>macello</quote> causato da molti <literal>#ifdef</literal> (blocchi di codice che vengono usati solo in maniera condizionata) nel vostro codice, evitate di introdurre nelle patch <literal>#ifdef</literal> dipendenti dalle versioni del kernel. Piuttosto, scrivete diverse patch, ognuna delle quali provoca cambiamenti incondizionati, e controllate la loro applicazione usando le guardie.</para>
Giulio@769 194
Giulio@769 195 <para id="x_197">Ci sono due ragioni per separare le patch #backport# in un gruppo distinto dalle patch <quote>normali</quote> i cui effetti vengono modificati da quelle. Il primo è che mescolarle insieme rende più difficile usare uno strumento come l'estensione <literal role="hg-ext">patchbomb</literal> per automatizzare il processo di sottoposizione delle patch a un mantenitore a monte. Il secondo è che le patch #backport# potrebbero perturbare il contesto in cui una successiva patch normale viene applicata, rendendo impossibile applicare la patch normale in maniera pulita <emphasis>senza</emphasis> che la patch #backport# precedente sia già stata applicata.</para>
Giulio@769 196
Giulio@769 197 </sect2>
Giulio@769 198 </sect1>
Giulio@769 199 <sect1>
Giulio@769 200 <title>Suggerimenti utili per sviluppare con MQ</title>
Giulio@769 201
Giulio@769 202 <sect2>
Giulio@769 203 <title>Organizzare le patch in directory</title>
Giulio@769 204
Giulio@769 205 <para id="x_198">Se state lavorando su un progetto sostanzioso con MQ, non è difficile accumulare un grande numero di patch. Per esempio, mi è capitato di avere un repository di patch contenente più di 250 patch.</para>
Giulio@769 206
Giulio@769 207 <para id="x_199">Se potete raggruppare queste patch in categorie logiche separate, potete memorizzarle in directory differenti, in quanto MQ non ha problemi a usare nomi di patch che contengono separatori di percorso.</para>
Giulio@769 208
Giulio@769 209 </sect2>
Giulio@769 210 <sect2 id="mq-collab:tips:interdiff">
Giulio@769 211 <title>Visualizzare la cronologia di una patch</title>
Giulio@769 212
Giulio@769 213 <para id="x_19a">Se sviluppate un insieme di patch per un lungo periodo, è una buona idea mantenerle in un repository, come discusso nella <xref linkend="sec:mq:repo"/>. Se fate in questo modo, scoprirete velocemente che è impraticabile usare il comando <command role="hg-cmd">hg diff</command> per guardare la cronolgia dei cambiamenti di una patch. In parte, questo succede perché state guardando la derivata seconda del codice reale (un diff di un diff), ma anche perché MQ aggiunge rumore al processo modificando le marcature temporali e i nomi di directory quando aggiorna una patch.</para>
Giulio@769 214
Giulio@769 215 <para id="x_19b">Tuttavia, potete usare l'estensione <literal role="hg-ext">extdiff</literal> inclusa in Mercurial per trasformare il diff didue versioni di una patch in qualcosa di leggibile. Per fare questo, avrete bisogno di un pacchetto di terze parti chiamato <literal role="package">patchutils</literal> <citation>web:patchutils</citation>. Questo fornisce un comando chiamato <command>interdiff</command> che mostra le differenze tra due diff di un diff. Usato su due versioni dello stesso diff, genra un diff che rappresenta le differenze tra la prima e la seconda versione.</para>
Giulio@769 216
Giulio@769 217 <para id="x_19c">Potete abilitare l'estensione <literal role="hg-ext">extdiff</literal> nel solito modo, aggiungendo una riga alla sezione <literal role="rc-extensions">extensions</literal> del vostro file <filename role="special">~/.hgrc</filename>.</para>
Giulio@769 218 <programlisting>[extensions]
Giulio@769 219 extdiff =</programlisting>
Giulio@769 220 <para id="x_19d">Il comando <command>interdiff</command> si aspetta che gli vengano passati i nomi di due file, ma l'estensione <literal role="hg-ext">extdiff</literal> passa una coppia di directory al programma che segue, ognuna delle quali può contenere un numero arbitrario di file. Quindi abbiamo bisogno di un piccolo programma che invochi <command>interdiff</command> su ogni coppia di file in quelle due directory. Questo programma è disponibile sotto il nome di <filename role="special">hg-interdiff</filename> nella directory <filename class="directory">examples</filename> del repository di codice sorgente che accompagna questo libro.</para>
Giulio@769 221
Giulio@769 222 <para id="x_19e">Con il programma <filename role="special">hg-interdiff</filename> nel percorso di ricerca della vostra shell, potete eseguilo come segue, dall'interno di una directory di patch gestita da MQ:</para>
Giulio@769 223 <programlisting>hg extdiff -p hg-interdiff -r A:B my-change.patch</programlisting>
Giulio@769 224 <para id="x_19f">Dato che vorrete usare questo comando prolisso molto spesso, potete fare in modo che <literal role="hg-ext">hgext</literal> lo renda disponibile come un normale comando Mercurial, modificando ancora una volta il vostro file <filename role="special">~/.hgrc</filename>.</para>
Giulio@769 225 <programlisting>[extdiff]
Giulio@769 226 cmd.interdiff = hg-interdiff</programlisting>
Giulio@769 227 <para id="x_1a0">Questo istruisce <literal role="hg-ext">hgext</literal> a rendere disponibile il comando <literal>interdiff</literal>, in modo che possiate accorciare l'invocazione precedente di <command role="hg-ext-extdiff">extdiff</command> a qualcosa di un po' più maneggevole.</para>
Giulio@769 228 <programlisting>hg interdiff -r A:B my-change.patch</programlisting>
Giulio@769 229
Giulio@769 230 <note>
Giulio@769 231 <para id="x_1a1">Il comando <command>interdiff</command> funziona bene solo se i file sottostanti dai quali vengono generate le versioni di una patch rimangono gli stessi. Se create una patch, modificate i file sottostanti e poi rigenerate la patch, <command>interdiff</command> potrebbe non produrre alcun risultato utile.</para>
Giulio@769 232 </note>
Giulio@769 233
Giulio@769 234 <para id="x_1a2">L'utilità dell'estensione <literal role="hg-ext">extdiff</literal> va oltre il semplice miglioramento della presentazione delle patch gestite da MQ. Per avere ulteiori informazioni, leggete la <xref linkend="sec:hgext:extdiff"/>.</para>
Giulio@769 235
Giulio@769 236 </sect2>
Giulio@769 237 </sect1>
Giulio@769 238 </chapter>