Added it/drawbacks.txt
[gitmagic.git] / it / grandmaster.txt
blob1bd5b9789d7e700208dcb67b5a72aac47f8cbf88
1 == Padroneggiare Git ==
3 A questo punto dovreste essere capaci di navigare la guida *git help* e
4 di capire quasi tutto (a condizione ovviamente di capire l'inglese).
5 Nonostante ciò ritrovare il comando esatto richiesto per risolvere un
6 particolare problema può essere tedioso. Magari posso aiutarvi a
7 risparmiare un po' di tempo: qua sotto trovate qualcuna delle ricette di
8 cui ho avuto bisogno in passato.
10 === Pubblicazione di codice sorgente ===
12 Per i miei progetti Git gestisce esattamente i file che voglio
13 archiviare e pubblicare. Per creare un archivio in formato tar del
14 codice sorgente utilizzo:
16  $ git archive --format=tar --prefix=proj-1.2.3/ HEAD
18 === Commit dei cambiamenti ===
20 Dire a Git quando avete aggiunto, cancellato o rinominato dei file può
21 essere fastidioso per certi progetti. Invece potete eseguire:
23  $ git add .
24  $ git add -u
26 Git cercherà i file della cartella corrente e gestirà tutti i dettagli
27 automaticamente. Invece del secondo comando 'add', eseguite `git
28 commit -a` se volete anche fare un commit. Guardate *git help ignore*
29 per sapere come specificare i file che devono essere ignorati.
31 Potete anche effettuare tutti i passi precedenti in un colpo solo con:
33  $ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove
35 Le opzioni *-z* e *-0* permettono di evitare effetti collaterali dovuti
36 a file il cui nome contiene strani caratteri. Visto che questo comando
37 aggiunge anche file che sono ignorati, potreste voler usare le opzioni
38 `-x` o `-X`.
40 === Il mio commit è troppo grande! ===
42 Vi siete trascurati da un po' di tempo di fare dei commit? Avete scritto
43 codice furiosamente dimenticandovi di controllo di versione? Avete
44 implementato una serie di cambiamenti indipendenti, perché è il vostro
45 stile di lavoro?
47 Non c'è problema. Eseguite:
49  $ git add -p
51 Per ognuna delle modifiche che avete fatto, Git vi mostrerà la parte di
52 codice che è stata cambiata e vi domanderà se dovrà fare parte del
53 prossimo commit. Rispondete con "y" (sì) o con "n" (no). Avete anche
54 altre opzioni, come di postporre la decisione; digitate "?" per saperne
55 di più.
57 Una volta soddisfatti, eseguite:
59  $ git commit
61 per fare un commit che comprende esattamente le modifiche selezionate
62 (le modifiche `nell'area di staging`, vedere dopo). Assicuratevi di
63 omettere l'opzione *-a*, altrimenti Git farà un commit che includerà
64 tutte le vostre modifiche.
66 Che fare se avete modificato molti file in posti diversi? Verificare ogni
67 cambiamento uno alla volta diviene allora rapidamente frustrante e
68 noioso. In questo caso usate *git add -i*, la cui interfaccia è meno
69 intuitiva ma più flessibile. Con qualche tasto potete aggiungere o
70 togliere più file alla volta dall'area di staging, oppure anche rivedere
71 e selezionare cambiamenti in file particolari. Altrimenti potete anche
72 eseguire *git commit \--interactive* che effettuerà automaticamente un
73 commit quando avrete finito.
75 === L'indice : l'area di staging ===
77 Fino ad ora abbiamo evitato il famoso 'indice' di Git, ma adesso
78 dobbiamo parlarne per capire meglio il paragrafo precedente. L'indice è
79 un'area temporanea di cosiddetto 'staging'. Git trasferisce raramente dati
80 direttamente dal vostro progetto alla sua storia. Invece, Git scrive
81 prima i dati nell'indice, e poi copia tutti i dati dell'indice nella
82 loro destinazione finale.
84 Un *commit -a* è ad esempio in realtà un processo a due fasi. La prima
85 fase stabilisce un'istantanea (un cosiddetto 'snapshot') dello stato
86 corrente di ogni file in gestione e la ripone nell'indice. La seconda
87 fase salva permanentemente questo snapshot. Effettuare un commit senza
88 l'opzione *-a* esegue solamente la seconda fase, e ha quindi solo senso
89 solo a seguito di un comando che modifica l'indice, come ad esempio *git
90 add*.
92 Normalmente possiamo ignorare l'indice e comportandoci effettivamente
93 come se se stessimo scambiando dati direttamente nella storia. In altri
94 casi come quello precedente vogliamo un controllo più fine e manipoliamo
95 quindi l'indice. Inseriamo nell'indice uno snapshot di alcuni, ma non
96 tutti i cambiamenti, e poi salviamo permanentemente questi snapshot
97 accuratamente costruiti.
99 === Non perdete la "testa"  ===
101 La tag HEAD è come un cursore che normalmente punta all'ultimo commit,
102 avanzando con ogni commit. Alcuni comandi di Git permettono di muoverla.
103 Ad esempio:
105  $ git reset HEAD~3
107 sposta HEAD tre commit indietro. Da qua via tutti i comandi Git agiscono
108 come se non aveste fatto quegli ultimi tre commit, mentre i vostri file
109 rimangono nello stato presente. Vedere la pagina di help per qualche
110 applicazione interessante.
112 Ma come fare per ritornare al futuro? I commit passati non sanno niente
113 del futuro.
115 Se conoscete il codice SHA1 dell'HEAD  originario (diciamo 1b6d...),
116 fate allora:
118  $ git reset 1b6d
120 Ma come fare se non l'avete memorizzato? Non c'è problema: per comandi
121 di questo genere Git salva l'HEAD originario in una tag chiamata
122 ORIG_HEAD, e potete quindi ritornare al futuro sani e salvi con:
124  $ git reset ORIG_HEAD
126 === Cacciatore di "teste" ===
128 ORIG_HEAD può non essere abbastanza. Diciamo che vi siete appena accorti
129 di un monumentale errore e dovete ritornare ad un vecchio commit in una
130 branch dimenticata da lungo tempo.
132 Per default Git conserva un commit per almeno due settimane, anche se
133 gli avete ordinato di distruggere la branch lo conteneva. La parte
134 difficile è trovare il codice hash appropriato. Potete sempre far
135 scorrere tutti i codici hash il `.git/objects` e trovare quello che
136 cercate per tentativi. C'è però un modo molto più facile.
138 Git registra ogni codice hash che incontra in `.git/logs`. La
139 sottocartella `refs` contiene la storia dell'attività di tutte le
140 branch, mentre il file `HEAD` mostra tutti i codici hash che HEAD ha
141 assunto. Quest'ultimo può usato per trovare commit di una branch che è
142 stata accidentalmente cancellata.
144 Il comando *reflog* provvede un'interfaccia intuitiva per gestire questi
145 file di log. Provate a eseguire:
147   $ git reflog
149 Invece di copiare e incollare codici hash dal reflog, provate:
151  $ git checkout "@{10 minutes ago}"
153 O date un'occhiata al quintultimo commit visitato con:
155  $ git checkout "@{5}"
157 Vedete la sezione ``Specifying Revisions'' di *git help rev-parse* per
158 avere più dettagli.
160 Potreste voler configurare un periodo più lungo per la ritenzione dei
161 commit da cancellare. Ad esempio:
163   $ git config gc.pruneexpire "30 days"
165 significa che un commit cancellato sarà perso permanentemente eliminato
166 solo 30 giorni più tardi, quando *git gc* sarà eseguito.
168 Potete anche voler disabilitare l'esecuzione automatica di *git gc*:
170   $ git config gc.auto 0
172 nel qual caso commit verranno solo effettivamente eliminati
173 all'esecuzione manuale di *git gc*.
175 === Costruire sopra Git ===
177 In vero stile UNIX, il design di Git ne permette l'utilizzo come
178 componente a basso livello di altri programmi, come interfacce grafiche
179 e web, interfacce di linea alternative, strumenti di gestione di patch,
180 programmi di importazione e conversione, ecc. Infatti, alcuni comandi
181 Git sono loro stessi script che fanno affidamento ad altri comandi di
182 base. Con un po' di ritocchi potete voi stessi personalizzare Git in
183 base alle vostre preferenze.
185 Un facile trucco consiste nel creare degli alias di comandi Git per
186 abbreviare le funzioni che utilizzate di frequente:
188   $ git config --global alias.co checkout
189   $ git config --global --get-regexp alias  # mostra gli alias correnti
190   alias.co checkout
191   $ git co foo                              # equivalente a 'git checkout foo'
193 Un altro trucco consiste nell'integrare il nome della branch corrente
194 nella vostra linea di comando o nel titolo della finestra. L'invocazione
197   $ git symbolic-ref HEAD
199 mostra il nome completo della branch corrente. In pratica, vorrete
200 probabilmente togliere "refs/heads/" e ignorare gli errori:
202   $ git symbolic-ref HEAD 2> /dev/null | cut -b 12-
204 La sottocartella +contrib+ è uno scrigno di utili strumenti basati su
205 Git. Un giorno alcuni di questi potrebbero essere promossi al rango di
206 comandi ufficiali. Su Debian e Ubuntu questa cartella si trova in
207 +/usr/share/doc/git-core/contrib+.
209 Uno dei più popolari tra questi script si trova in
210 +workdir/git-new-workdir+. Grazie ad un link simbolico intelligente,
211 questo script crea una nuova cartella di lavoro la cui storia è
212 condivisa con il deposito originario:
214   $ git-new-workdir un/deposito/esistente nuova/cartella
216 La nuova cartella e i suoi file possono essere visti come dei cloni,
217 salvo per il fatto che la storia è condivisa e quindi i rimane
218 automaticamente sincronizzata. Non c'è quindi nessun bisogno di fare
219 merge, push o pull.
221 === Acrobazie audaci  ===
223 Git fa in modo che sia difficile per un utilizzatore distruggere
224 accidentalmente dei dati. Ma se sapete cosa state facendo, potete
225 escludere le misure di sicurezza dei comandi più comuni.
227 *Checkout*: 'Checkout' non funziona in caso di Modifiche non integrate
228 con commit. Per distruggere i vostri cambiamenti ed effettuare comunque
229 un certo checkout, usate la flag 'force':
231   $ git checkout -f HEAD^
233 D'altro canto, se specificate un percorso particolare per il checkout,
234 non ci sono controlli di sicurezza. I percorsi forniti sono
235 silenziosamente sovrascritti. Siate cauti se utilizzate checkout in
236 questa modalità.
238 *Reset*: Anche 'reset' non funziona in presenza di cambiamenti non
239 integrate con commit. Per forzare il comando, eseguite:
241   $ git reset --hard 1b6d
243 *Branch*: Non si possono cancellare branch se questo risulta nella
244 perdita di cambiamenti. Per forzare l'eliminazione scrivete:
246   $ git branch -D branch_da_cancellare  # invece di -d
248 Similmente, un tentativo di rinominare una branch con il nome di
249 un'altra è bloccato se questo risulterebbe nella perdita di dati. Per
250 forzare il cambiamento di nome scrivete:
252   $ git branch -M origine destinazione  # à invece di -m
254 Contrariamente ai casi di 'checkout' e 'reset', questi ultimi comandi
255 non effettuano un'eliminazione immediata dell'informazione. I
256 cambiamenti sono salvati nella sottocartella .git, e possono essere
257 recuperati tramite il corrispondente codice hash in `.git/logs` (vedete
258 "Cacciatore di ``teste''" precedentemente). Per default, sono conservati
259 per almeno due settimane. 
261 *Clean*: Alcuni comandi Git si rifiutano di procedere per non rischiare
262 di danneggiare file che non sono in gestione. Se siete certi che tutti
263 questi file possono essere sacrificati, allora cancellateli senza pietà
264 con:
266   $ git clean -f -d
268 In seguito il comando precedentemente eccessivamente prudente
269 funzionerà.
271 === Prevenire commit erronei ===
273 Errori stupidi ingombrano i miei depositi. I peggiori sono quelli dovuti
274 a file mancanti per via di un *git add* dimenticato. Altri errori meno
275 gravi riguardano spazi bianchi dimenticati e conflitti di merge
276 irrisolti: nonostante siano inoffensivi, vorrei che non apparissero nel
277 registro pubblico.
279 Se solo mi fossi premunito utilizzando dei controlli preliminari
280 automatizzati, i cosiddetti _hook_, che mi avvisino di questi problemi
281 comuni!
283  $ cd .git/hooks
284  $ cp pre-commit.sample pre-commit  # Vecchie versioni di Git : chmod +x pre-commit
286 Ora Git blocca un commit se si accorge di spazi inutili o se ci sono
287 conflitti di merge non risolti.
289 Per questa guida ho anche aggiunto le seguenti linee all'inizio del mio
290 hook *pre-commit* per prevenire le mie distrazioni:
292  if git ls-files -o | grep '\.txt$'; then
293    echo FAIL! Untracked .txt files.
294    exit 1
295  fi
297 Molte operazioni di Git accettano hook; vedete *git help hooks*. Abbiamo
298 già utilizzato l'hook *post-update* in precedenza, quando abbiamo
299 discusso Git via HTTP. Questo è eseguito ogni volta che l'HEAD cambia.
300 Lo script post-update d'esempio aggiorna i file Git necessari per
301 comunicare dati via canali come HTTP che sono agnostici di Git.