Giulio@748: Giulio@749: Giulio@748: Migrare verso Mercurial Giulio@748: Giulio@752: Un modo comune di esplorare un nuovo strumento di controllo di revisione è quello di sperimentarlo trasferendo un progetto esistente piuttosto che cominciare un nuovo progetto da zero. Giulio@752: Giulio@752: In questa appendice, parleremo di come importare la cronologia di un progetto in Mercurial e di quello a cui dovete essere preparati se siete abituati a un sistema di controllo di revisione differente. Giulio@748: Giulio@748: Giulio@748: Importare la cronologia da un altro sistema Giulio@748: Giulio@748: Mercurial include un'estensione chiamata convert che può importare la cronologia di un progetto dalla maggior parte dei sistemi di controllo di revisione più popolari. Al momento in cui il libro è stato scritto, l'estensione può importare la cronologia dai seguenti sistemi: Giulio@748: Giulio@748: Giulio@748: Subversion Giulio@748: Giulio@748: Giulio@748: CVS Giulio@748: Giulio@748: Giulio@748: git Giulio@748: Giulio@748: Giulio@748: Darcs Giulio@748: Giulio@748: Giulio@748: Bazaar Giulio@748: Giulio@748: Giulio@748: Monotone Giulio@748: Giulio@748: Giulio@748: GNU Arch Giulio@748: Giulio@748: Giulio@748: Mercurial Giulio@748: Giulio@748: Giulio@748: Giulio@752: (Per verificare perché lo stesso Mercurial sia supportato come sorgente da cui importare la cronologia, si veda la .) Giulio@752: Giulio@752: Potete attivare l'estensione nel solito modo, modificando il vostro file ~/.hgrc. Giulio@748: Giulio@748: [extensions] Giulio@748: convert = Giulio@748: Giulio@752: Questo renderà disponibile il comando hg convert. Il comando è facile da usare. Per esempio, l'invocazione seguente importerà in Mercurial la cronologia di Subversion per Nose, un framework per il collaudo di unità. Giulio@748: Giulio@748: $ hg convert http://python-nose.googlecode.com/svn/trunk Giulio@748: Giulio@806: L'estensione convert opera in maniera incrementale. In altre parole, dopo che avete invocato hg convert una prima volta, invocandolo nuovamente importerete tutte le nuove revisioni che sono state inserite dopo la vostra prima esecuzione del comando. La conversione incrementale funzionerà solo se invocate hg convert nello stesso repository Mercurial che avete usato in origine, perché l'estensione convert salva alcuni metadati privati all'interno del repository in un file chiamato .hg/shamap non soggetto al controllo di revisione. Giulio@806: Giulio@806: Quando volete cominciare a effettuare modifiche usando Mercurial, è preferibile clonare l'albero in cui state facendo le vostre conversioni e tenere da parte l'albero originale per dedicarlo a future conversioni incrementali. Questo è il modo più sicuro per estrarre i futuri commit dal sistema di controllo di revisione sorgente e incorporarli nel progetto Mercurial che avete appena creato. Giulio@752: Giulio@752: Giulio@752: Convertire molti rami Giulio@752: Giulio@813: Il comando hg convert eseguito in precedenza converte solo la cronologia del trunk del repository Subversion. Se invece usiamo l'URL http://python-nose.googlecode.com/svn, Mercurial individuerà automaticamente le directory trunk, tags e branches che compongono la struttura usata di solito dai progetti Subversion e le importerà come rami separati. Giulio@752: Giulio@752: Per default, a ogni ramo Subversion importato in Mercurial viene assegnato un nome. Dopo che la conversione si è conclusa, potete ottenere una lista dei nomi dei rami attivi nel repository Mercurial usando hg branches -a. Se preferite importare i rami Subversion senza nomi, passate l'opzione al comando hg convert. Giulio@752: Giulio@806: Una volta che avete convertito il vostro albero, se volete seguire la consuetudine tipica per Mercurial di lavorare in un albero che contiene un singolo ramo, potete clonare quel singolo ramo usando hg clone -r nomedelramo. Giulio@748: Giulio@748: Giulio@748: Giulio@748: Correlare i nomi utente Giulio@748: Giulio@806: Alcuni strumenti di controllo di revisione salvano con ogni inserimento solo nomi utenti brevi che possono essere difficili da interpretare. Con Mercurial, la norma è quella di salvare il nome e l'indirizzo email di chi effettua il commit, due informazioni molto più utili se in seguito volessimo contattare quella persona. Giulio@752: Giulio@752: Se state convertendo un albero da un sistema di controllo di revisione che usa nomi brevi, potete correlare quei nomi a equivalenti più lunghi passando l'opzione al comando hg convert. Questa opzione accetta un nome di file che dovrebbe contenere voci nel seguente formato. Giulio@752: Giulio@752: arist = Aristotele <aristotele@filo.example.gr> Giulio@752: soc = Socrate <socrate@filo.example.gr> Giulio@752: Giulio@806: Ogni volta che convert incontra un commit associato al nome utente arist nel repository sorgente, userà il nome Aristotele <aristotele@filo.example.gr> nella revisione convertita in Mercurial. Se non viene trovata alcuna corrispondenza per un certo nome, quel nome viene usato alla lettera. Giulio@748: Giulio@748: Giulio@748: Giulio@752: Riordinare l'albero Giulio@752: Giulio@752: Non tutti i progetti hanno una cronologia pulita. Potrebbe esserci una directory che non avrebbe mai dovuto essere inserita, un file che è troppo grande, o un'intera gerarchia che ha bisogno di essere riorganizzata. Giulio@752: Giulio@752: L'estensione convert supporta l'idea di una mappa di file che può essere impiegata per riorganizzare i file e le directory di un progetto nel momento in cui se ne importa la cronologia. Questo è utile non solo quando si importa la cronologia da altri sistemi di controllo di revisione, ma anche per potare o riorganizzare un albero Mercurial. Giulio@748: Giulio@748: Per specificare una mappa di file, usate l'opzione e fornitele un nome di file. Una mappa di file contiene righe nei seguenti formati. Giulio@748: Giulio@748: # Questo è un commento Giulio@748: # Le righe vuote vengono ignorate Giulio@748: Giulio@752: include percorso/del/file Giulio@752: Giulio@752: exclude percorso/del/file Giulio@752: Giulio@752: rename da/qualche/percorso a/qualche/altra/posizione Giulio@748: Giulio@748: Giulio@752: La direttiva include provoca l'inclusione di un file, o di tutti i file contenuti in una directory, nel repository destinazione. Questa direttiva provoca anche l'esclusione di tutti gli altri file o directory che non sono stati esplicitamente inclusi. La direttiva exclude provoca l'esclusione dei file e delle directory indicate e di tutti quegli altri percorsi che non sono stati esplicitamente menzionati per essere inclusi. Giulio@748: Giulio@748: Per spostare un file o una directory da una posizione a un'altra, usate la direttiva rename. Se dovete spostare un file o una directory da una sottodirectory alla radice del repository, usate . come secondo argomento della direttiva rename. Giulio@748: Giulio@748: Giulio@748: Giulio@748: Migliorare le prestazioni della conversione da Subversion Giulio@748: Giulio@806: Avrete spesso bisogno di fare diversi tentativi prima di trovare la combinazione perfetta tra mappa di utenti, mappa di file e altri parametri di conversione. La conversione di un repository Subversion attraverso un protocollo di accesso come ssh o HTTP può procedere migliaia di volte più lentamente di quanto Mercurial sia capace di operare in realtà, a causa della latenza di rete. Questo può rendere molto complicata la messa a punto di quella ricetta per la conversione perfetta. Giulio@806: Giulio@806: Il comando svnsync può velocizzare notevolmente la conversione di un repository Subversion. Serve per creare un mirror di sola lettura di un repository Subversion. L'idea è quella di creare un mirror locale del vostro albero Subversion per poi convertire il mirror in un repository Mercurial. Giulio@748: Giulio@748: Immaginiamo di voler convertire il repository Subversion che contiene il popolare progetto Memcached in un albero Mercurial. Per prima cosa, creiamo un repository Subversion locale. Giulio@748: Giulio@748: $ svnadmin create memcached-mirror Giulio@748: Giulio@752: Successivamente, impostiamo un hook Subversion di cui svnsync ha bisogno. Giulio@748: Giulio@748: $ echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change Giulio@748: $ chmod +x memcached-mirror/hooks/pre-revprop-change Giulio@748: Giulio@748: Poi inizializziamo svnsync in questo repository. Giulio@748: Giulio@748: $ svnsync --init file://`pwd`/memcached-mirror \ Giulio@748: http://code.sixapart.com/svn/memcached Giulio@748: Giulio@752: Il passo successivo consiste nell'avviare il processo di creazione del mirror con il comando svnsync. Giulio@748: Giulio@748: $ svnsync sync file://`pwd`/memcached-mirror Giulio@748: Giulio@748: Infine, importiamo la cronologia del nostro mirror locale del repository Subversion in un repository Mercurial. Giulio@748: Giulio@748: $ hg convert memcached-mirror Giulio@748: Giulio@806: Se il repository Subversion è ancora attivo, possiamo usare questo processo in maniera incrementale. Invochiamo svnsync per propagare i nuovi cambiamenti verso il nostro mirror e poi invochiamo hg convert per importarli nel nostro albero Mercurial. Giulio@806: Giulio@806: Un'importazione in due stadi realizzata con svnsync ha due vantaggi. Il primo è che svnsync usa una sincronizzazione di rete con Subversion più efficiente rispetto al comando hg convert, quindi trasferisce meno dati attraverso la rete. Il secondo è che l'importazione da un albero Subversion locale è così veloce che potete aggiustare ripetutamente le vostre impostazioni di conversione senza aspettare ogni volta la terminazione di un processo di conversione basato su rete e dolorosamente lento. Giulio@748: Giulio@748: Giulio@748: Giulio@748: Giulio@748: Migrare da Subversion Giulio@748: Giulio@752: Attualmente Subversion è il sistema di controllo di revisione open source più popolare. Sebbene ci siano molte differenze tra Mercurial e Subversion, effettuare una transizione da Subversion a Mercurial non è particolarmente difficile. I due sistemi hanno insiemi di comandi simili e interfacce generalmente uniformi. Giulio@748: Giulio@748: Giulio@748: Differenze filosofiche Giulio@748: Giulio@748: Naturalmente, la differenza fondamentale tra Subversion e Mercurial è che Subversion è centralizzato mentre Mercurial è distribuito. Dato che Mercurial memorizza tutta la cronologia di un progetto sul vostro disco locale, ha bisogno di accedere alla rete solo quando volete esplicitamente comunicare con un altro repository. Al contrario, Subversion memorizza localmente un'esigua quantità di informazioni, perciò il client deve contattare il proprio server per molte operazioni comuni. Giulio@748: Giulio@752: Subversion riesce più o meno a cavarsela senza una nozione di ramo ben definita: qualificare come ramo una porzione dello spazio di nomi sul server è una questione di convenzioni, e il software non impone alcuna costrizione. Mercurial tratta un repository come l'unità della gestione dei rami. Giulio@748: Giulio@748: Giulio@748: L'ambito dei comandi Giulio@748: Giulio@806: Dato che Subversion non sa quali parti del suo spazio di nomi siano realmente rami, tratta la maggior parte dei comandi come se richiedesse di operare al livello della directory in cui vi trovate e ai livelli sottostanti. Per esempio, se eseguite svn log, otterrete la cronologia di qualunque parte dell'albero stiate osservando, non dell'intero albero. Giulio@806: Giulio@806: Il comportamento predefinito di Mercurial è differente perché i suoi comandi operano sull'intero repository. Eseguite hg log e vi mostrerà la cronologia dell'intero albero, a prescindere da quale parte della directory di lavoro stiate visitando in quel momento. Se volete solo la cronologia di un file o di una directory particolare, vi basta fornire un nome al comando, e.g. hg log sorgenti. Giulio@752: Giulio@752: Secondo la mia esperienza, questa differenza nel comportamento predefinito dei comandi è probabilmente la cosa che può confondervi di più se dovete spostarvi frequentemente avanti e indietro tra i due strumenti. Giulio@748: Giulio@748: Giulio@748: Giulio@748: Operazioni multi-utente e sicurezza Giulio@748: Giulio@752: Con Subversion, è normale (anche se blandamente deprecato) che più persone collaborino su un singolo ramo. Se Alice e Bruno stanno lavorando insieme e Alice inserisce alcune modifiche nel ramo condiviso, Bruno deve aggiornare la vista del ramo del suo client prima di poter effettuare un commit. Dato che in quel momento non esiste alcuna registrazione permanente dei cambiamenti fatti da Bruno, le sue modifiche potrebbero rovinarsi o andare perdute durante e dopo questo aggiornamento. Giulio@752: Giulio@806: Mercurial, invece, incoraggia un modello di inserimento-e-unione. Bruno inserisce le sue modifiche nella sua copia locale del repository prima di estrarre o trasmettere i cambiamenti da o verso il server che condivide con Alice. Se Alice trasmette i suoi cambiamenti prima che Bruno provi a trasmettere i propri, Bruno non sarà in grado di trasmettere i suoi cambiamenti prima di aver estratto quelli di Alice, averli incorporati e aver effettuato il commit dei risultati dell'unione. Se Bruno commette un errore durante l'unione, può sempre ritornare al commit con il quale aveva registrato i suoi cambiamenti. Giulio@806: Giulio@806: Vale la pena sottolineare che questi sono i modi più comuni di lavorare con questi strumenti. Subversion supporta un modello più sicuro per consentirvi di lavorare nel vostro ramo personale, che però in pratica si rivela abbastanza scomodo da non essere particolarmente diffuso. Mercurial può supportare un modello meno sicuro che permette di estrarre e unire i cambiamenti nonostante la presenza di modifiche non ancora registrate, ma questo è considerato estremamente inusuale. Giulio@748: Giulio@748: Giulio@748: Giulio@748: Cambiamenti locali o pubblici Giulio@748: Giulio@748: Il comando svn commit pubblica immediatamente i cambiamenti su un server dove possono essere visti da chiunque abbia accesso in lettura. Giulio@748: Giulio@748: Con Mercurial, i commit sono sempre locali e devono essere pubblicati successivamente tramite il comando hg push. Giulio@748: Giulio@752: Ogni approccio ha i propri vantaggi e svantaggi. Il modello di Subversion prevede che i cambiamenti siano pubblicati, e quindi revisionabili e utilizzabili, immediatamente. D'altra parte, questo significa che un utente deve avere accesso in scrittura a un repository per utilizzare normalmente lo strumento, ma la maggior parte dei progetti open source non concede alla leggera i permessi di scrittura. Giulio@752: Giulio@752: L'approccio di Mercurial consente a chiunque possa clonare un repository di inserirvi modifiche senza il bisogno del permesso di qualcun altro e di pubblicare i propri cambiamenti e continuare a partecipare nel modo che preferisce. A causa della distinzione tra le operazioni di inserimento e trasmissione dei cambiamenti, può capitare che qualcuno effettui il commit di alcune modifiche sul proprio computer e si allontani per qualche giorno dimenticandosi di trasmetterli, cosa che in rari casi potrebbe bloccare temporaneamente le attività dei collaboratori. Giulio@748: Giulio@748: Giulio@748: Giulio@748: Giulio@752: Guida rapida Giulio@748: Giulio@748: Giulio@748: Equivalenze tra i comandi Subversion e Mercurial Giulio@748: Giulio@748: Giulio@748: Giulio@748: Subversion Giulio@748: Mercurial Giulio@748: Notes Giulio@748: Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn add Giulio@748: hg add Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn blame Giulio@748: hg annotate Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn cat Giulio@748: hg cat Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn checkout Giulio@748: hg clone Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn cleanup Giulio@748: n/a Giulio@748: Nessuna pulizia necessaria Giulio@748: Giulio@748: Giulio@748: svn commit Giulio@748: hg commit; hg Giulio@748: push Giulio@748: hg push pubblica le modifiche dopo il commit Giulio@748: Giulio@748: Giulio@748: svn copy Giulio@748: hg clone Giulio@748: Per creare un nuovo ramo Giulio@748: Giulio@748: Giulio@748: svn copy Giulio@748: hg copy Giulio@748: Per copiare file o directory Giulio@748: Giulio@748: Giulio@748: svn delete (svn Giulio@748: remove) Giulio@748: hg remove Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn diff Giulio@748: hg diff Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn export Giulio@748: hg archive Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn help Giulio@748: hg help Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn import Giulio@748: hg addremove; hg Giulio@748: commit Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn info Giulio@748: hg parents Giulio@748: Mostra quale revisione è stata estratta Giulio@748: Giulio@748: Giulio@748: svn info Giulio@748: hg showconfig Giulio@748: paths.parent Giulio@752: Mostra da quale URL è avvenuta l'estrazione Giulio@748: Giulio@748: Giulio@748: svn list Giulio@748: hg manifest Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn log Giulio@748: hg log Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn merge Giulio@748: hg merge Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn mkdir Giulio@748: n/a Giulio@748: Mercurial non tiene traccia delle directory Giulio@748: Giulio@748: Giulio@748: svn move (svn Giulio@748: rename) Giulio@748: hg rename Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn resolved Giulio@748: hg resolve -m Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn revert Giulio@748: hg revert Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn status Giulio@748: hg status Giulio@748: Giulio@748: Giulio@748: Giulio@748: svn update Giulio@748: hg pull -u Giulio@748: Giulio@748: Giulio@748: Giulio@748: Giulio@748:
Giulio@748:
Giulio@748:
Giulio@748: Giulio@748: Giulio@748: Suggerimenti utili per i principianti Giulio@748: Giulio@806: In alcuni sistemi di controllo di revisione, può diventare complicato stampare le differenze per una singola revisione registrata nel repository. Per esempio, con Subversion, per vedere cos'è cambiato nella revisione 104654 dovete digitare svn diff -r104653:104654. Mercurial elimina la necessità di digitare due volte l'identificatore di revisione in questo caso comune. Per ottenere solo le differenze, digitate hg export 104654. Per ottenere un messaggio dal registro della cronologia seguito dalle differenze, digitate hg log -r104654 -p. Giulio@752: Giulio@752: Quando eseguite hg status senza argomenti, vi viene mostrato lo stato dell'intero albero, con i percorsi relativi alla radice del repository. Questo rende complicato copiare un nome di file dal risultato di hg status alla riga di comando. Se eseguite hg status passandogli il nome di un file o di una directory, il comando stamperà i percorsi relativi alla vostra posizione corrente. Quindi, per ottenere da hg status lo stato di tutto l'albero, con i percorsi relativi alla vostra directory corrente invece che alla radice del repository, passate il risultato di hg root al comando hg status. Su un sistema di tipo Unix, potete farlo facilmente nel modo che segue: Giulio@748: Giulio@748: $ hg status `hg root` Giulio@748: Giulio@748: