|
Size: 28413
Comment: proofreading
|
Size: 29571
Comment: complete review
|
| Deletions are marked like this. | Additions are marked like this. |
| Line 16: | Line 16: |
| * si conosca l'uso di base della linea di comando e l'utilizzo di un editor di testo a scelta (DebianPkg:emacs, DebianPkg:vim, DebianPkg:gedit, DebianPkg:kate, etc.); | * si conosca l'uso di base della riga di comando e l'utilizzo di un editor di testo a scelta (DebianPkg:emacs, DebianPkg:vim, DebianPkg:gedit, DebianPkg:kate, etc.) per modificare file. |
| Line 24: | Line 24: |
| Cos'è '''git'''? Git è un sistema di '''''Controllo di versione distribuito'''''. La parte importante è ''Controllo di versione'' -- significa che è un programma che permette di tenere traccia dei cambiamenti dei file e comparare le differenti "versioni", e fare anche un'altra cosa fantastica, come tornare indietro a precedenti versioni di un certo file. | Cos'è '''git'''? Git è un sistema di '''''Controllo di versione distribuito'''''. La parte importante è ''Controllo di versione'': significa che è un programma che permette di tenere traccia dei cambiamenti dei file e comparare le differenti "versioni", e fare anche altre cose fantastiche, come tornare indietro a precedenti versioni di un certo file. |
| Line 31: | Line 31: |
| === sistema di controllo di versione''Distribuito'' === Noi abbiamo analizzato ''git'' come Sistema di Controllo di Versione, ma ''git'' è un '''''VCS Distribuito'''''. ''Distribuito'' è un dettaglio dell'architettura di ''git'', che ha alcuni pro e alcuni contro. Ci sono altri "sistemi VCS'' famosi, come ''CVS'' e ''SVN'', chiamati ''VCS Centralizzati''; questi hanno bisogno di avere una connessione al server centrale, per conservare tutti i dati e per eseguire molte operazioni. Pensa al comando ''log'': SVN ha bisogno di connettersi al server e scaricare i dati. Con i ''VCS Distribuiti'' (e ''git'' è uno di questi) ciò non avviene: ogni copia del repository è una copia '''completa'''. Questo significa che le operazione sono più veloci, e che soprattutto puoi usare git sul tuo computer locale, senza avere un server. Ovviamente anche i VCS Distribuiti hanno i loro difetti, il problema più importante che ho riscontrato è il gran numero di ''conflitti'. Questo perché con i VCS Centralizzati un commit è di solito rifiutato se determina un conflitto con la copia del server. Invece con i VCS distrubuiti, chiunque può eseguire un commit nel suo repo, e il conflitto avviene solo quando viene ''pushato'' (il termine "push" verrà spiegato in seguito). |
=== Sistema di controllo di versione ''distribuito'' === Noi abbiamo analizzato ''git'' come Sistema di Controllo di Versione (VCS), ma ''git'' è un '''''VCS distribuito'''''. ''Distribuito'' è un dettaglio dell'architettura di ''git'', che ha alcuni pro e alcuni contro. Ci sono altri "sistemi VCS famosi, come ''CVS'' e ''SVN'', chiamati ''VCS centralizzati''; questi hanno bisogno di avere una connessione al server centrale, dove sono conservati tutti i dati, per eseguire molte operazioni. Basti pensare al comando ''log'': SVN ha bisogno di connettersi al server e scaricare i dati. Con i ''VCS distribuiti'' (e ''git'' è uno di questi) ciò non avviene: ogni copia del repository è una copia '''completa'''. Questo significa che le operazione sono più veloci e che, soprattutto, si può usare git sul proprio computer locale, senza avere un server. Ovviamente anche i VCS distribuiti hanno i loro difetti, il problema principale secondo l'autore di questa guida è il gran numero di ''conflitti''. Questo avviene perché con i VCS centralizzati un commit è di solito rifiutato se determina un conflitto con la copia del server. Invece con i VCS distribuiti, chiunque può eseguire un commit nel suo repository e il conflitto avviene solo al momento del ''push'' (il termine "push" verrà spiegato in seguito). |
| Line 43: | Line 43: |
| Un ''oggetto'' git può essere un ''blob'', un ''tree'', ''commit'' o ''tag''. Esaminiamoli uno alla volta: * Un '''blob''' è un oggetto git su cui sono conservati i dati. Questo è generalmente un file su disco. * Un '''tree''' è come una cartella, fa referenza ad altri tree e/o blob. Si può immaginarlo come una cartella con file e sottocartelle al suo interno. * Un '''commit''' è un riferimento ad un singolo tree, e contiene anche altre meta-informazioni, come il timestamp, l'autore (nome ed email) che ha apportato le modifiche e un puntatore al commit precedente. Generalmente, quando si usa git, si fa riferimento solo ai commit. * Un '''tag''' è solo un modo per segnare un commit come se fosse in un certo modo speciale. Generalmente, i tag vengono usati per segnare commit con i numeri di versione, release e così via. Se pensiamo al modello di immagazzinamento di git, distinguiamo una "area di lavoro", un "index" e un "repository": * L' '''area di lavoro''' è composta dai file presenti nella nostra cartella git * L' '''index''' e '''repository''', invece, sono contenuti all'interno di {{{./.git/}}} -- qui è dove tutti i repository git risiedono, ed è sufficiente per ricreare il contenuto delle cartelle. Andando oltre, possiamo dire che l' ''index'' è come una temporanea area di sosta, dove tu puoi aggiungere i file prima di eseguire il commit. Una volta che il commit è stato eseguito, il contenuto andrà all'interno del repository, e l'azione compiuta verrà conservata nella sua cronologia, se tu non esegui il commit, puoi rimuovere i file dall'index senza lasciare traccia nella cronologia del repository. |
Un ''oggetto'' git può essere un ''blob'', un ''tree'', un ''commit'' o un ''tag''. Di seguito le descrizioni di ciascuno di essi. * Un '''blob''' è un oggetto git su cui sono conservati i dati. È generalmente un file su disco. * Un '''tree''' è come una directory, ha riferimenti ad altri tree o blob. Si può immaginarlo come una directory con file e sottodirectory al suo interno. * Un '''commit''' è un riferimento ad un singolo tree e contiene anche altre meta-informazioni, come la data e l'ora, l'autore (nome ed email) che ha apportato le modifiche e un puntatore al commit precedente. Generalmente, quando si usa git, si fa riferimento solo ai commit. * Un '''tag''' è solo un modo per segnare un commit come speciale per qualche caratteristica. Generalmente, i tag vengono usati per segnare commit con i numeri di versione, rilascio e così via. Se si pensa al modello di immagazzinamento di git, si può distinguere una "area di lavoro", un "indice" e un "repository": * L' '''area di lavoro''' è composta dai file attualmente presenti nella directory git * L'{{{}}}'''indice''' e il '''repository''', invece, sono contenuti all'interno di {{{./.git/}}} : qui è dove tutti i repository git risiedono ed è sufficiente per ricreare il contenuto delle directory. Andando oltre, si può dire che l'{{{}}}''indice'' è come una temporanea area di sosta, dove si possono aggiungere i file prima di fare il commit. Una volta che il commit è stato eseguito, i file vanno all'interno del repository e l'azione compiuta verrà conservata nella sua cronologia, se il commit non viene eseguito, i file possono essere rimossi dall'indice senza lasciare traccia nella cronologia del repository. |
| Line 61: | Line 61: |
| Per la parte pratica, ho voluto usare un progetto reale, anzichè creare qualche repository. Ho scelto di usare "GNU Hello", scaricalo da [[http://ftp.gnu.org/gnu/hello/hello-2.6.tar.gz]]. Noi creeremo un repository da questo codice sorgente. Scarichiamo il tarball: |
Per la parte pratica, si è preferito usare un progetto reale, anziché inventarsi un repository. Si è scelto di usare "GNU Hello"; il suo archivio tar può essere scaricato da [[http://ftp.gnu.org/gnu/hello/hello-2.6.tar.gz]]. In questa guida verrà creato un repository a partire da questo codice sorgente. Scaricare l'archivio tar: |
| Line 69: | Line 69: |
| Una volta fatto, spacchettiamolo: | Una volta fatto, spacchettarlo: |
| Line 75: | Line 75: |
| Questo comando creerà la cartella {{{hello-2.6/}}}. Adesso entriamo nella cartella ed iniziamo a giocare con ''git'' :) Prima di tutto, abbiamo bisogno di configurare il nostro username e la nostra e-mail. Queste informazioni verranno usate nei nostri commit, e saranno visibili nella cronologia del repository. Per fare ciò, usiamo {{{git config}}}. In particolare, visto che siamo dei principianti, vogliamo settare username ed e-mail in modo globale. Quindi lanciamo i comandi: |
Questo comando creerà la directory {{{hello-2.6/}}}. Adesso si può entrare nella directory ed iniziare a giocare con ''git'' :) Prima di tutto, si deve configurare l'username e l'indirizzo e-mail. Queste informazioni verranno usate nei commit e saranno visibili nella cronologia del repository. Per fare ciò, si usa {{{git config}}}. In particolare, dato che in questo caso si tratta del primo utilizzo, si vuole impostare un username e un indirizzo e-mail in modo globale. Per farlo lanciare i comandi: |
| Line 83: | Line 84: |
| Naturalmente usa i tuoi dati :) L'opzione {{{--global}}} fa in modo che il cambiamento sia globale, ad esempio per ogni repository git sul tuo computer lui scrive le informazioni in {{{~/.gitconfig}}}. Controlla questo file, dopo che avrai eseguito questi due comandi. Vedrai le informazioni che hai fornito. L'username e l'e-mail possono anche essere cambiate in base al repository: in questo caso, puoi farlo dopo aver creato il repository, e senza l'opzione {{{--global}}}. Senza {{{--global}}}, le informazioni verranno inserite localmente in {{{./.git/config}}}. Abbiamo impostato l'username e l'e-mail. Ora, abbiamo bisogno di creare il repository git. Quindi abbiamo una cartella {{{hello-2.6/}}}: entriamoci ed lanciamo: |
Naturalmente usare i propri dati :) L'opzione {{{--global}}} fa in modo che il cambiamento sia globale, cioè per ogni repository git sul computer i dati verranno scritti in {{{~/.gitconfig}}}. Controllare questo file, dopo che aver eseguito questi due comandi. Si vedranno le informazioni fornite. L'username e l'indirizzo e-mail possono anche essere impostati per ciascun repository: in questo caso, lo si deve fare dopo aver creato il repository e senza usare l'opzione {{{--global}}}. Senza {{{--global}}}, le informazioni verranno inserite localmente in {{{./.git/config}}}. Sono stati impostati l'username e l'indirizzo e-mail. Ora, si deve creare il repository git. Perciò entrare nella directory {{{hello-2.6/}}} e lanciare: |
| Line 96: | Line 97: |
| Il risultato sarà qualcosa di simile: | Il risultato sarà qualcosa di simile a: |
| Line 102: | Line 103: |
| {{{git init}}} semplicemente crea una cartella {{{.git/}}}, con alcuni valori di default. Per vedere lo stato di un repository, lancia: | {{{git init}}} semplicemente crea una directory {{{.git/}}}, con alcuni valori predefiniti. Per vedere lo stato di un repository, eseguire: |
| Line 108: | Line 109: |
| Tale comando mostra i file monitorati e non, e lo stato dell'index. In più, ti mostrerà in qualche ''branch'' sei (spiegherò i branch più tardi). === Indexing === Non abbiamo ancora nulla nel repository. Quindi aggiungiamo il codice sorgente: |
Tale comando mostra i file monitorati e non, e lo stato dell'indice. In più, mostrerà in qualche ''branch'' si è (i branch verranno spiegati in seguito). === Indicizzazione === Nel repository non c'è ancora nulla. Aggiungere perciò il codice sorgente: |
| Line 118: | Line 119: |
| Il "." è una sintassi dei sistemi Unix-like -- significa "cartella corrente". Quindi in questo modo aggiungiamo tutto il contenuto. Ora, controlla {{{git status}}} di nuovo. Vedrai che qualcosa è cambiato. Quello che vedi ora è lo stato di ''index''. Possiamo ancora rimuovere file o cartelle dall'index, senza lasciare tracce nella cronologia. Facciamolo! rimuoviamo il file {{{AUTHORS}}} dall'index e rimettiamo nello stato di "non tracciato" |
Il "." è una sintassi comune dei sistemi simil-Unix: significa "directory corrente". Perciò di fatto viene aggiunto tutto. Ora, controllare {{{git status}}} di nuovo. Si vedrà che qualcosa è cambiato. Quello che si vede ora è lo stato dell'{{{}}}''indice''. Si potrebbe ancora rimuovere elementi dall'indice senza lasciare traccia nella cronologia. Provare a farlo! Rimuovere il file {{{AUTHORS}}} dall'indice e rimetterlo nello stato di "non tracciato": |
| Line 126: | Line 127: |
| Ora dai di nuovo uno sguardo a {{{git status}}}. Vedrai ''Changes to be committed''(cambiamenti che devono essere committati) (l'index) e ''Untracked files'' (file non tracciati). === Committing === Ora vogliamo '''committare'''i file nell'index: questo creerà un commit, con un hash, e verrà conservato nella cronologia del repository. Lanciamo: |
Ora guardare di nuovo {{{git status}}}. Si vedrà ''Changes to be committed''(cambiamenti di cui si deve fare il commit) (l'indice) e ''Untracked files'' (file non tracciati). === Commit === Ora si vuole fare il '''commit''' dei file nell'indice: questo creerà un commit, con un hash, e verrà conservato nella cronologia del repository. Eseguire: |
| Line 136: | Line 137: |
| Questo comando aprirà il proprio {{{$EDITOR}}} (il mio è {{{nano}}}, controlla il tuo), in cui va scritto un messaggio di commit. Se non ne scrivi uno, il commit verrà annullato (si, tu '''devi''' inserire un messaggio di commit) Chiamiamolo "Commit iniziale". Ora, lancia di nuovo {{{git status}}} . I file dall'index sono spariti! Sono stati committati all'interno del repository, e il log è stato conservato. Puoi vedere i log con: |
Questo comando aprirà l'{{{$EDITOR}}} (quello dell'autore è {{{nano}}}, controllare quale sia il proprio), in cui va scritto un messaggio di commit. Se non ne viene scritto uno, il commit verrà annullato (sì, si '''deve''' inserire un messaggio di commit). Chiamarlo "Commit iniziale". Ora, lanciare di nuovo {{{git status}}} . I file nell'indice sono spariti! Ne è stato fatto il commit all'interno del repository e ne è stato fatto un log. Il log si può vedere con: |
| Line 146: | Line 147: |
| Ti verrà mostrato il committer (l'autore del commit, con le informazioni inserite prima), il timestamp, e l'hash del commit. Puoi anche vedere l'ultimo commit con: |
Verrà mostrato l'autore del commit (con le informazioni inserite prima), la data e l'ora e l'hash del commit. Si può anche vedere l'ultimo commit con: |
| Line 154: | Line 155: |
| Aprirà automaticamente {{{$PAGER}}} e mostrerà il contenuto del tuo ultimo commit. {{{git show}}} accetta anche un hash come argomento. Il mio commit ha hash: 11aab8486d20490b16b1b7d847e1cb1e4f7aa2fe . Che è differente da quello dei tuoi. Non è necessario scrivere l'hash completo: normalmente bastano i primi 7,8 caratteri. Quindi possiamo lanciare: | Aprirà automaticamente il {{{$PAGER}}} (more, less, ...) e mostrerà il contenuto dell'ultimo commit. {{{git show}}} accetta anche un hash come argomento. Per chi scrive l'hash del commit è 11aab8486d20490b16b1b7d847e1cb1e4f7aa2fe . Il valore sarà diverso per ogni lettore che provi a seguire l'esempio. Non è necessario scrivere l'hash completo: normalmente bastano i primi 7 o 8 caratteri. Quindi si può lanciare: |
| Line 160: | Line 161: |
| {{{git}}} supporta anche un numero di nomi simbolici, ma non verranno spiegati ora in quanto credo non siano argomenti "di base" da poter essere spiegati in questa sessione (sto parlando di {{{HEAD}}}, {{{HEAD^}}}, {{{HEAD~2}}} e così via). Quindi, abbiamo rimosso {{{AUTHORS}}} dal nostro repository... poveracci! nessun merito al loro lavoro! Possiamo correggere questo problema: |
{{{git}}} supporta anche diversi nomi simbolici, ma non verranno spiegati qui in quanto non argomenti "di base" (ci si riferisce a {{{HEAD}}}, {{{HEAD^}}}, {{{HEAD~2}}} e così via). Gli autori ({{{AUTHORS}}}) sono stati lasciati fuori dal repository... poveracci! nessun merito al loro lavoro! Questo problema può essere corretto con: |
| Line 166: | Line 167: |
| $ git commit -m 'Also add AUTHORS' }}} {{{-m}}} è una scorciatoia per il ''messagio'' -- evita così di aprire {{{$EDITOR}}} Ora, abbiamo bisogno di moficare alcuni file, guardare le differenze, e commitarle. Prima fingiamo di aver scritto un pezzo di codice. Aggiungiamo il nostro nome al file {{{AUTHORS}}} :) E aggiungiamo anche qualcosa a "ChangeLog". Quello che vuoi, è solo un esempio. Ora, {{{git status}}}. Vedrai le prime due linee indicate con ''modified''(modificato). Per vedere le differenze introdotte: |
$ git commit -m 'Aggiunti AUTHORS' }}} {{{-m}}} è una scorciatoia per ''messaggio'': si evita in questo modo di aprire {{{$EDITOR}}}. Ora, si proverà a modificare alcuni file, guardare le differenze e farne il commit. Fingere di aver scritto un pezzo di codice. Aggiungere il proprio nome al file {{{AUTHORS}}} :) E aggiungere anche qualcosa al "!ChangeLog". Quello che si vuole, è solo un esempio. Ora usare {{{git status}}}. Si vedranno due righe che iniziano con ''modified''(modificato). Per vedere le differenze introdotte: |
| Line 181: | Line 182: |
| (Opzionalmente, {{{git diff filename}}} mostrerà solo le differenze in quel file.) Se queste modifiche vanno bene, committiamo! È possibile lanciare {{{git add}}} uno per uno e committare {{{git commit}}} oppure usare soltanto: |
(Opzionalmente, {{{git diff nomefile}}} mostrerà solo le differenze in quel file.) Se queste modifiche vanno bene, fare il commit! È possibile usare {{{git add}}} per ciascun file e fare il commit {{{git commit}}} oppure usare semplicemente: |
| Line 189: | Line 190: |
| L'argomento {{{-a}}} aggiungerà tutto all'index (ma solo i file tracciati, quelli non tracciati non saranno toccati). Vedrai: | L'opzione {{{-a}}} aggiungerà tutto all'indice (ma solo i file tracciati, quelli non tracciati non saranno toccati). Si otterrà: |
| Line 196: | Line 197: |
| ''master'' è il branch in cui siamo ora. La stringa dopo di quello è l'hash del commit, puoi usarla in molti comandi ({{{git show <commit>}}}, {{{git log <commit>}}}, etc). E dopo, vi è il messaggio di commit e le statistiche dei cambiamenti apportati (diffstats). === Branching === |
''master'' è il branch in cui si è attualmente. La stringa successiva è l'hash del commit; può essere usata in molti comandi ({{{git show <commit>}}}, {{{git log <commit>}}}, ecc.). Dopo vi è il messaggio di commit e le statistiche dei cambiamenti apportati. === Branch === |
| Line 202: | Line 203: |
| Pensa al repository git come ad un fiume. Ad un certo punto, lo sviluppo può divergere dal "flusso principale" e rimanere solo lì, oppure unirsi di nuovo al fiume originale. Ora il nostro ''master'' è ''il fiume principale''. Creiamo un branch, chiamiamolo ''debian'': |
Si pensi al repository git come ad un fiume. Ad un certo punto, lo sviluppo può divergere dal "flusso principale" e rimanere per conto suo, oppure unirsi di nuovo al fiume originale. Il ''master'' è ''il fiume principale''. Creare un branch, chiamandolo ''debian'': |
| Line 210: | Line 211: |
| Per cambiare a questo nuovo branch lancia: | Per spostarsi in questo nuovo branch, lanciare: |
| Line 222: | Line 223: |
| Ok, ora siamo nel branch ''debian''. Per controllare se è vero, esegui {{{git branch}}}, senza argomenti. Ti mostrerà i branch locali, e un {{{*}}} anteposto ti mostrerò quello in cui sei ora. Per tornare indietro al branch principale, esegui: {{{git checkout master}}}. Ma per il momento rimarremo sul branch ''debian'': {{{*debian}}}. All'interno di questo branch faremo il lavoro di pacchettizzazione. Quindi, creiamo una cartella {{{debian/}}}. Se la cartella è vuota, {{{git status}}} non la mostrerà, è il comportamento previsto: ''git'' non tiene traccia delle cartelle vuote. Per ingannarlo a fare queto puoi aggiungere un file vuoto alla cartella. Io normalmente aggiungo un {{{.gitignore}}} (è un file speciale usato da git), per lasciargli tracciare una cartella vuota. Quindi eseguiamo questo: |
Perfetto, si è fatto il checkout del branch ''debian''. Per controllare se è vero, eseguire {{{git branch}}}, senza argomenti. Mostrerà i branch locali attuali; quello in cui si è sarà preceduto da un {{{*}}}. Per tornare indietro al branch principale, eseguire: {{{git checkout master}}}. Ma per il momento restare nel branch ''debian'': {{{*debian}}}. Si immagini di fare il lavoro di pacchettizzazione all'interno di questo branch. Quindi, creare una directory {{{debian/}}}. Se è vuota, {{{git status}}} non la mostrerà; è il comportamento atteso: ''git'' non tiene traccia delle directory vuote. Per ingannarlo a farlo si può aggiungere un file vuoto alla directory. L'autore normalmente aggiunge un file {{{.gitignore}}} (è un file speciale usato da git), per fare tracciare una directory vuota. Eseguire perciò: |
| Line 237: | Line 238: |
| Ora {{{git status}}} mostrerà la non-tracciata {{{debian/}}}. Aggiungila e committala. Ora torniamo al branch ''master'' |
Ora {{{git status}}} mostrerà la non-tracciata {{{debian/}}}. Aggiungerla e farne il commit. Tornare ora al branch ''master'' |
| Line 245: | Line 246: |
| Ora vogliamo far divergere questi due branch, per simulare un branch reale: cambia tutti i file che vuoi, e committa i cambiamenti. Puoi usare un'interfaccia grafica ( come ad esempio ''gitg'' o ''gitk''), o qualcosa da linea di comando ({{{git show-branch}}}) Per vedere come i due branch sono divergenti. Visto che le gui sono facili da usare, useremo la riga di comando :D |
Ora si vuole far divergere questi due branch, per simulare un branch reale: cambiare tutti i file che si desidera, in qualunque modo, e farne il commit. Si può usare un'interfaccia grafica (come ad esempio ''gitg'' o ''gitk'') o qualcosa da riga di comando ({{{git show-branch}}}) per vedere come i due branch sono divergenti. Visto che le interfacce grafiche sono facili da usare, verrà usata la riga di comando :D |
| Line 253: | Line 254: |
| Vedrai che i due branch hanno un commit inziale in comune, ma a parte questo hanno commit differenti. Quindi uniamo i cambiamenti di "debian" in "master" | Si vedrà che i due branch hanno un commit inziale in comune, ma poi hanno commit differenti. Unire i cambiamenti di "debian" in "master" |
| Line 259: | Line 260: |
| Vedrai qualcosa come: | Si vedrà qualcosa come: |
| Line 268: | Line 269: |
| E ora ci saranno dei "conflitti". Se in ''debian'' abbiamo cambiato uno dei file cambiati prima del merge, questi potrebbero andare in conflitto. Sarebbe utile lanciare {{{git mergetool}}} dopo il merge, per risolvere i conflitti. Userà uno dei possibili programmi per gestire i conflitti. Non voglio entrare nei dettagli, in ogni caso è sempre meglio risolvere i conflitti manualmente. Abbiamo unito ''debian'' in ''master''. Ora vediamo i log, dovresti vedere qualcosa come: |
È in questo momento che avverranno i "conflitti". Se in ''debian'' abbiamo cambiato uno dei file cambiati prima del merge, potrebbe essere avvenuto un conflitto. Potrebbe essere utile eseguire {{{git mergetool}}} dopo il merge, per risolvere i conflitti. Userà uno dei diversi possibili programmi per gestire i conflitti. Non si entrerà qui nei dettagli, per un uso base risolvere i conflitti manualmente è sufficiente. È stato fatto il merge di ''debian'' in ''master''. Guardando i log, si dovrebbe vedere qualcosa come: |
| Line 297: | Line 299: |
| Some message | Messaggio a piacere |
| Line 303: | Line 305: |
| Also add AUTHORS | Aggiunti AUTHORS |
| Line 309: | Line 311: |
| Initial commit | Commit iniziale |
| Line 314: | Line 316: |
| L'ultima cosa che voglio spiegare per quanto riguarda la parte della guida ''in locale'' è '''{{{git revert}}}'''. Supponiamo che io trovi qualcosa che non mi piace nel mio {{{git log}}}. Per esempio diciamo che è il (mio) commit 2ba81dfaeb919e6a0c634be54fe363b11487d65a, quello con cui ho aggiunto la cartella {{{debian/}}}. Ricordati che gli hash sono diffenti per ciascuna persona, quindi guarda i log per vedere il tuo. Dunque, non mi piace. Cosa dovrei fare ora? Posso usare il comando {{{git revert}}}. Questo comando prende semplicemente il cambiamento (diff) da un commit, e lo applica al contrario, e lascia i conflitti, se ce ne sono, proviamolo: |
L'ultima cosa da spiegare per quanto riguarda il lavoro ''in locale'' è '''{{{git revert}}}'''. Supponiamo di trovare qualcosa che non piace nel {{{git log}}}. Per esempio, diciamo che è il commit 2ba81dfaeb919e6a0c634be54fe363b11487d65a, quello con cui è stata aggiunta la directory {{{debian/}}}. Ci si ricordi che gli hash sono differenti per ciascuna persona, quindi si guardi il log per vedere il proprio. Dunque, quel commit non piace. Cosa si deve fare ora? Si può usare il comando {{{git revert}}}. Questo comando prende semplicemente il cambiamento (diff) da un commit, lo applica al contrario e lascia i conflitti, se ce ne sono; provarlo: |
| Line 326: | Line 328: |
| {{{$EDITOR}}} (''nano'', ''vim'', ecc) si aprirà di nuovo. C'è un messaggio di default; puoi lasciarlo così com'è, o spiegare (in un modo migliore) perchè stai ripristinano i cambiamenti. Per semplicità lasciamolo intatto. Salva il messaggio ed esci dall'editor. Vedrai: |
{{{$EDITOR}}} (''nano'', ''vim'', ecc.) si aprirà di nuovo. C'è un messaggio di commit predefinito; si può lasciarlo così com'è o spiegare (scelta consigliata) perché si stanno annullando i cambiamenti. Per semplicità in questo caso lasciarlo intatto. Salvare il messaggio ed uscire dall'editor. Si vedrà: |
| Line 338: | Line 340: |
| Questo significa che anche il rispristino è un commit. Con un Committer, un Autore, un Timestamp ed un Hash. Potresti anche ripristinare un ripristino (ma è meglio non farlo). '''NOTA:''' Ripristinare un merge non è semplice. Devi specificare anche il commit superiore. Documentati sull'opzione {{{-m}}} di {{{git revert}}}. Che ha anche qualche brutto effetto collaterale (IMHO), quindi non fare nessun merge se non sei assolutamente sicuro di poterlo fare. == Processo Distribuito == Git è un VCS distribuito, è una parete fondamentale. Ti permette di condividere il tuo lavoro, il tuo sviluppo, con altre persone quindi mettiamo da parte il repository. === Clonare e Pushare === Ho preparato un repository online per i sorgenti di GNU Hello che stiamo usando. Questo è normalmente quello che trovarete per i progetti esistenti: un repository online. Puoi copiare i loro contenuti (clonarli), usa il comando {{{git clone}}}. Quindi cloniamo il repository, (ah, prima di farlo esci dalla cartella {{{hello-2.6/}}}): |
Questo significa che anche il rispristino è un commit. Con un committer, un autore, una data e un orario ed un hash. Si potrebbe anche ripristinare un ripristino (ma è meglio non farlo). '''NOTA:''' Ripristinare un merge non è semplice. Si deve specificare anche il genitore principale. Si legga la documentazione dell'opzione {{{-m}}} di {{{git revert}}}. Ha anche qualche brutto effetto collaterale (IMHO), quindi non fare nessun merge se non si è assolutamente sicuri. == Lavorare in modo distribuito == Git è un VCS distribuito; perciò quella trattata ora è una parte fondamentale. Permette di condividere il proprio lavoro, e il proprio sviluppo, con altre persone. Si metta perciò da parte il repository. === Usare clone e push === Per questa guida è stato preparato un repository online per i sorgenti di GNU Hello che vengono usati. Questo è normalmente quello che si trova per i progetti esistenti: un repository online. Si può copiare il loro contenuto (clonarli) usando il comando {{{git clone}}}. Clonare quindi il repository, (Ah! prima di farlo, uscire dalla directory {{{hello-2.6/}}}): |
| Line 354: | Line 356: |
| Vedrai qualcosa come: | Si vedrà qualcosa come: |
| Line 365: | Line 367: |
| Ora, entra in {{{hello/}}}, e inizia a curiosare un po' con {{{git log}}}, {{{git show}}}... È un repository pulito, ma è stato preso dal web. Se fosse stato un vero repository, probabilmente non avrebbe mostrato solo un commit o solo un branch. Ora, vediamo l'indirizzo del repository. Puoi ottenere o impostare l'indirizzo da dove prendere il repository con {{{git remote}}}. C'è il ''remote'' di default, chiamato ''origin''. È anche dove '''i push''' hanno luogo. Diamo un'occhiata: |
Ora, entrare in {{{hello/}}} e iniziare a curiosare un po' con {{{git log}}}, {{{git show}}}, ... È un repository pulito, ma è stato preso dal web. Se fosse stato un vero repository, probabilmente non avrebbe mostrato solo un commit, né solo un branch. Vedere ora da dove è stato preso il repository. Si possono ottenere o impostare informazioni sula fonte da cui è stato preso il repository con {{{git remote}}}. C'è un ''remote'' predefinito, chiamato ''origin''. È anche quello predefinito in cui verranno fatti i '''push'''. Guardare com'è: |
| Line 375: | Line 377: |
| Per ora, curiamoci solo di queste due linee: | Per ora, solo queste due righe sono interessanti: |
| Line 382: | Line 384: |
| Significa che stiamo sincronizzando dal "Fetch URL", e stiamo pushando dal "Push URL". Questi non devono per forza combaciare. Ad esempio, diciamo che tu stai conservando la versione patchata di un software da qualche parte: puoi recuperarla dal tuo upstream, e pusharla sulla tua posizione. Possiamo aggiungere un remote evitando di rimuovere il tuo lavoro precedente. Per questo, è possibile usare {{{git remote add}}}. La sintassi è la seguente {{{ git remote add <remote_name> <remote_url> }}} Di solito, se vuoi pushare un repository, hai bisogno di usare un url `git+ssh://` o `ssh://`. Un url `git://git.[...]` normalmente non ti permette di pushare. (Per essere onesti, io non ho mai visto uno che permette di usarlo, ma è meglio dire "è meglio non farlo di norma" che "non farlo"'). {{{git remote add}}} è utile quando stai creando un nuovo repository, ovvero quando non devi clonare da nessuna parte. == Domanda e Risposte == |
Significa che si sta sincronizzando dal "Fetch URL" e si sta facendo il push sul "Push URL". Questi non devono per forza combaciare, possono essere diversi; come, ad esempio, se si sta mantenendo una versione con patch di un software da qualche parte: si prendono i dati dagli autore a monte e si fa il push nella propria posizione. Si può aggiungere un remote senza rimuovere il lavoro precedente. Per fare questo, si può usare {{{git remote add}}}. La sintassi è la seguente: {{{ git remote add <nome_remoto> <url_remoto> }}} Di solito, se si vuole essere in grado di fare il push su un repository, si deve usare un url `git+ssh://` o `ssh://`. Un url `git://git.[...]` normalmente non permette di fare push. (A dire il vero, l'autore di questa guida non ne ha mai visto uno che lo permettesse, ma è meglio usare "normalmente non permette" che "non permette mai".) {{{git remote add}}} è utile specialmente quando si sta creando un nuovo repository, ovvero quando non si sta clonando da qualche parte. == Domande e risposte == |
| Line 398: | Line 400: |
| RISPOSTA: Un oggetto tree del commit rappresenta l'intero repository ad un certo punto del tempo, quindi contiene le referenze dell'intero progetto DOMANDA: Gli oggetti vanno nell'index con: {{{git commit}}}? RISPOSTA: No, {{{git commit}}} creata un commit che viene inserito nel repository. Ne ho parlato prima, ma questa immagine spiega meglio il concetto: [[http://osteele.com/images/2008/git-transport.png]]. DOMANDA: Se ricopio i file senza la cartella {{{.git}}} perdo tutta la cronologia? RISPOSTA: Si, la cartella {{{.git}}} è l'unica che contiene l'intera cronologia. E una persone ha bisogno dell'intera cartella {{{.git}}} per ricreare il repository . DOMANDA: L'index è presenta nella cartella {{{.git}}}? RISPOSTA: Si, è conservata li. DOMANDA: Il push fallisce se ci sono conflitti? Se è così questo pro può essere un contro perchè un repository condiviso (se usato) sarà sempre in uno stato di lavoro. RISPOSTA: Si, il push fallisce. Ho detto prima che un grande numero di conflitti è un problema nei VCS distribuiti, ma git ti permette di risolverli e pushare. Per quanto riguarda "i repository condivisi che funzionano sempre", i VCS centralizzati risolvono i conflitti, ma loro lo fanno in modo automatico. Questo porta però a soluzioni erronee --git, invece, è un tracciatore di contenuti (come dice la parola) "stupido", quindi chiede aiuto ogni volta che ne ha bisogno. Quindi, mentre SVN corregge automaticamente gli errori per te, (anche se tu non sai realmente cosa accade nel repository) in git il push fallisce, e tu gestisci i conflitti localmente (e dopo ripushi). DOMANDA: E quindi c'è bisogno solo della cartella {{{.git}}} per ricreare il repository; qual'è il comando per ricrearla? RISPOSTA: Devi solo lanciare {{{git clone}}} dalla directory. Se tu hai, per esempio, {{{.git/}}} di alcuni progetti -- basta rinominarli a {{{project.git}}}, e dopo lanciare "git clone project.git": ti ritroverai con la cartella {{{project/}}} con tutto al suo interno. La rinominazione rende tutto più semplice, basta solo fare {{{git clone .git myotherdir}}} (e tutto diventerà {{{myotherdir/}}}) DOMANDA: come posso trovare i settaggi correnti per l'username e l'e-mail globale? (Voglio solo conoscere le informazioni prima di cambiarle :) ) {{{~/.gitconfig}}} ? RISPOSTA: Per ottenere un'informazione specifica puoi usare {{{git config --get}}}. Quindi, {{{git config --global --get user.name}}}. Puoi anche vedere tutte le informazioni con {{{git config -l}}} e puoi modificarle con {{{git config}}}, oppure aprendo con un editor {{~/.gitconfig}}} o {{{./.git/config}}} (o ovunque tu voglia modificare le impostazioni globali o locali). DOMANDA: Posso patchare il valore di {{{user.name}}}, ecc all'interno dei file gestiti da git? RISPOSTA: Si, puoi avere un config separato per repo, basta evitare l'opzione {{{--global}}}. Ma la questione si apre per altre risposte: Credo che la questione sia circa {{{git filter-branch}}}. Il committer git è incorporato nell'oggetto Commit (ricorda, ho detto che ha anche metadati). Quindi, quando cambi committer, non puoi lasciare lo stesso hash, esso deve cambiare. Quindi argomenti avanzati come filter-branch (che ti permette di riscrivere la cronologia di un repository), non deveono mai essere usati su repository pubblico, perchè significa creare tonnellate di conflitti e mal di testa. Tuttavia, è interessante vede come una persone può temporaneamente sovrascrivere l'utente e l'email configurati. git commit può leggere alcune variabili di ambiente: {{{GIT_COMMITTER_NAME}}}, {{{GIT_COMMITTER_EMAIL}}}, {{{GIT_AUTHOR_NAME}}} e {{{GIT_AUTHOR_EMAIL}}}. Queste, se impostate, sovrascriveranno quello che c'è in git config. In generale, per ogni variabile di configurazione, git controllerà, |
RISPOSTA: Un oggetto tree del commit rappresenta l'intero repository ad un certo punto del tempo, quindi contiene i riferimenti a tutto il tree dell'intero progetto. DOMANDA: I file vanno nell'indice con: {{{git commit}}}? RISPOSTA: No, {{{git commit}}} crea un commit che viene inserito nel repository. Ne ho parlato prima, ma questa [[http://osteele.com/images/2008/git-transport.png|immagine]] spiega bene il concetto. DOMANDA: Se ricopio i file senza la directory {{{.git}}} perdo tutta la cronologia? RISPOSTA: Sì, la directory {{{.git}}} è quella che che contiene l'intera cronologia, i commit e tutto quanto. Ed è sufficiente una directory {{{.git}}} per ricreare il repository. DOMANDA: L'indice è nella directory {{{.git}}}? RISPOSTA: Sì, è conservato lì. DOMANDA: Il push fallisce se ci sono conflitti? Se è così, questo pro può essere un contro perché un repository condiviso (se usato) sarà sempre in uno stato funzionante. RISPOSTA: Sì, il push fallisce. È stato detto prima che un maggiore numero di conflitti è uno svantaggio dei VCS distribuiti, ma git permette di risolverli e rifare il push. Per quanto riguarda "i repository condivisi che funzionano sempre", anche i VCS centralizzati risolvono i conflitti, ma lo fanno in modo automatico. Questo può portare però a soluzioni erronee; git, invece, è un tracciatore di contenuti "stupido" (come dice la parola), quindi chiede aiuto ogni volta che ne ha bisogno. Quindi, mentre un SVN correggerebbe automaticamente gli errori per conto dell'utente, (che non saprà realmente per certo cosa andrà a finire nel repository), in git il push fallisce e l'utente gestisce i conflitti localmente (e dopo rifa il push). DOMANDA: «Ed è sufficiente una directory {{{.git}}} per ricreare il repository.» : qual è il comando per ricrearla? RISPOSTA: Si deve semplicemente lanciare {{{git clone}}} dalla directory. Se, per esempio, si ha una directory {{{.git/}}} di un progetto, basta rinominarla in {{{project.git}}} e dopo lanciare "git clone project.git": ci si ritroverà con la directory {{{project/}}} con tutto al suo interno. La rinominazione rende tutto più semplice, basterebbe fare {{{git clone .git miaaltradir}}} (e tutto finirà in {{{miaaltradir/}}}) DOMANDA: Come si possono trovare le impostazioni attuali per l'username e l'e-mail globale? (Se si vogliono solo conoscere le informazioni prima di cambiarle :) ) {{{~/.gitconfig}}}? RISPOSTA: Per ottenere un valore specifico si può usare {{{git config --get}}}. Quindi, {{{git config --global --get user.name}}}. Si può anche vedere un elenco di tutti i valori con {{{git config -l}}} e si può modificarli con {{{git config}}} oppure aprendo con un editor {{{~/.gitconfig}}} o {{{./.git/config}}} (a seconda se si desidera modificare le impostazioni globali o quelle locali). DOMANDA: Posso fare una patch al valore di {{{user.name}}}, ecc. all'interno dei file gestiti da git? RISPOSTA: Sì, si può avere un config separato per ogni repository, basta evitare l'opzione {{{--global}}}. Ma la domanda permette di dare altre risposte: la domanda sembra riferirsi a {{{git filter-branch}}}. Il Committer git è incorporato nell'oggetto Commit (come si è detto ha anche metadati). Quindi, quando si cambia il committer, non si può mantenere lo stesso hash, esso deve cambiare. Quindi opzioni avanzate come filter-branch (che permette di riscrivere la cronologia di un repository) non dovrebbero mai essere usate su repository pubblico, perché significa creare tonnellate di conflitti e mal di testa. Tuttavia, è interessante vedere come si può temporaneamente sovrascrivere l'username e l'email configurati. git commit può leggere alcune variabili di ambiente: {{{GIT_COMMITTER_NAME}}}, {{{GIT_COMMITTER_EMAIL}}}, {{{GIT_AUTHOR_NAME}}} e {{{GIT_AUTHOR_EMAIL}}}. Queste, se impostate, sovrascriveranno quello che c'è in git config. In generale, per ogni variabile di configurazione, git controllerà, |
| Line 438: | Line 438: |
| Se configuri qualcosa in {{{./.git/config}}} , questa sovrascriverà quella globale. Se tu configuri una variabile d'ambiente GIT_* , sovrascriverà anche tutte le altre. | Se si configura qualcosa in {{{./.git/config}}}, questa sovrascriverà quella globale. Se si configura una variabile d'ambiente GIT_*, essa sovrascriverà tutto. |
| Line 442: | Line 442: |
| DOMANDA: Come posso ottenere la lista dei file cambiati? git log mostra l'autore, il timestamp, il commento ma io non ho bisogno del contenuto dei file (Ho solo bisogno del loro elenco). RISPOSTA: L'elenco dei file modificati può essere visto con {{{git log --raw}}}. Ogni comando git ha molte opzioni, e le pagine man sono normalmente tue amiche. Per esempio, è possibile combinare {{{git log}}} con {{{--raw}}} e {{{--pretty}}}, per ottenere un output più carino che usando solo {{{--raw}}} Lo stesso per {{{git show}}}: possiamo formattare il risultato con {{{--pretty}}} Questo non è "l'uso di base", tuttavia puoi usare una GUI, Io uso gitg a volte. DOMANDA: Git preserva i permessi dei file di cui tiene traccia o devo usare degli stratagemmi? RISPOSTA: Preserva i permessi, ma ti notifica anche quando questi vengono cambiati, un commit, ad esempio, può anche consistere solo di un cambio di permessi. |
DOMANDA: Come posso ottenere la lista dei file cambiati? git log mostra l'autore, la data e l'ora, il commento ma io non ho bisogno del contenuto dei file (ho solo bisogno del loro elenco). RISPOSTA: L'elenco dei file modificati in ciascun commit può essere visto con {{{git log --raw}}}. Ogni comando git ha molte opzioni e le pagine man normalmente sono molto utili. Per esempio, è possibile combinare {{{git log}}} con {{{--raw}}} e {{{--pretty}}}, per ottenere un output più carino di quello con solo {{{--raw}}}. Lo stesso per {{{git show}}}: si può passare una stringa di formattazione a {{{--pretty}}}. Questo, tuttavia, non è "l'uso di base"; si può usare una GUI, l'autore di questa guida usa gitg a volte. DOMANDA: Git preserva i permessi dei file di cui tiene traccia o devono essere usati degli stratagemmi? RISPOSTA: Preserva i permessi e si accorge anche di quando vengono cambiati; un commit, cioè, può anche consistere solamente in un cambio di permessi. |
| Line 456: | Line 456: |
| RISPOSTA: Questo è perchè il primo commit dove abbiamo importato tutto. Di norma è meglio che fare commit "atomici" (volevo dire che questo è solo un buon metodo). Quindi di solito, non dovresti vedere un output così grosso, ad ogni modo, non dovresti avere molti problemi con questo :) DOMANDA: Posso solo copiare la cartella sul mio webserver e lasciare che gli altri la clonino su `http://myserver/hello-2.6` ? RISPOSTA: Solo se non hai bisogno dei file attuali in quella cartella, ma di solito è meglio condividere solo la cartella {{{.git}}} con il nome {{{project.git}}}. Questo viene di solito chiamato "bare repository". DOMANDA: C'è un modo per semplificare: {{{git add}}} + {{{git commit -m}}} ? O devo lanciarli uno ad uno? RISPOSTA: Si c'è. Se vuoi committare tutti i file puoi usare l'opzione {{{-a}}} di {{{git commit}}}. Quindi, {{{git commit -a -m "Messagio"}}} committera tutto quello già tracciato. DOMANDA: Una delle cose che mi sembrano strane è avere il repository come parte dell'area di lavoro. È più semplice avere un repo in una cartella differente? O dove creare repository addizionali? RISPOSTA: Puoi, ma è un po' più complicato di così. Leggi la manpage di {{{git-config}}} nella sezione {{{core.worktree}}}. DOMANDA: Ad esempio io ho una applicazione web sotto git e voglio distribuirla con/senza cartella git. Qual'è il miglio modo per farlo? RISPOSTA: La stessa risposta di prima: impostare esplicitamente {{{core.worktree}}} in {{{./.git/config}}} ad un percorso differente. DOMANDA: Ho creato una cartella vuota (test1) ma {{{git status}}} non visualizza niente, quindi ho fatto {{{echo test > test1/testfile}}} e l'output di {{{git status}}} mi restituisce # test1/ ma nessun testfile. È un comportamento aspettato? RISPOSTA: Si, come ho detto prima, abbiamo creato con touch un .gitignore vuoto all'interno di una cartella vuota per fare in modo che git la tracci. DOMANDA: Cosa succede se ripristino un cambiamento, in un branch che non è lo stesso che hai estratto? RISPOSTA: Se non succede niente il ripristino non è avvenuto. DOMANDA: Se prendo un branch, faccio il merge, ma voglio ripstinarlo, come trovo l'hash? |
RISPOSTA: È così perché è il primo commit dove è stato importato tutto. Di norma è meglio fare commit "atomici". (Si può dire che è la prassi raccomandata.) Quindi di solito, non si vede un output così grosso; comunque usa less in modo predefinito per cui non si dovrebbero avere molti problemi con questo :) DOMANDA: Posso semplicemente copiare la directory sul mio server web e lasciare che gli altri la clonino usando git clone `http://myserver/hello-2.6`? RISPOSTA: Sì, si può. Se non si ha bisogno dei file in quella cartella, è solitamente meglio condividere solamente la directory {{{.git}}} con il nome {{{project.git}}}. Questo viene di solito chiamato "bare repository". DOMANDA: C'è un modo per semplificare: {{{git add}}} + {{{git commit -m}}} ? O vanno lanciati uno ad uno? RISPOSTA: Sì, c'è. Se si vuole fare il commit di tutti i file, si può usare l'opzione {{{-a}}} di {{{git commit}}}. Quindi, {{{git commit -a -m "Messaggio"}}} farà il commit di tutto ciò che è già tracciato. DOMANDA: Una delle cose che mi sembrano strane è avere il repository come parte dell'area di lavoro. È semplice avere un repository in un albero di directory diverso? O è necessario creare repository addizionali? RISPOSTA: Si può, ma è una modalità di lavoro un po' avanzata. Leggere la sezione {{{core.worktree}}} nella pagina man di {{{git-config}}}. DOMANDA: Ad esempio io ho un'applicazione web sotto git e voglio usarla senza la directory .git. Qual è il miglio modo per farlo? RISPOSTA: La risposta è la stessa di prima: impostare esplicitamente {{{core.worktree}}} in {{{./.git/config}}} ad un percorso differente. DOMANDA: Ho creato una cartella vuota (test1) ma {{{git status}}} non visualizza niente, quindi ho fatto {{{echo test > test1/testfile}}} e l'output di {{{git status}}} mi restituisce # test1/ ma nessun testfile. È il comportamento atteso? RISPOSTA: Sì, come è stato detto prima, è stato creato con touch un .gitignore vuoto all'interno di una directory vuota per fare in modo che git la tracci. DOMANDA: Cosa succede se si annulla un cambiamento su un branch che non è lo stesso che è stato estratto? RISPOSTA: Non succede niente, cioè il ripristino non avviene. DOMANDA: Se ho un branch e faccio il merge, ma voglio ripstinarlo, come trovo l'hash? |
| Line 486: | Line 486: |
| DOMANDA: l'opzione clone, clona solo il branch master... o anche gli altri? RISPOSTA: {{{git clone}}} clona solo il branch master. Significa che, gli altri branch verranno recuperati, ma nessun branch locale verrà creato per loro. Per correggere questo problema, solitamento lancio questo comando per ogni branch che mi interessa. {{{$ git checkout -b mybranch -t origin/mybranch}}} ({{{-t origin/mybranch}}} significa "traccia mybranch da origin") DOMANDA: c'è differenza tra `git+ssh://` e `git://` ? RISPOSTA: Si c'è. `git://` è un "protocollo stupido", e non supporta l'autenticazione. Quindi nel primo caso, questo protocollo viene incapsulato in SSH -- un po' come `svn+ssh://` o `cvs+ssh://` o altri. Nel secondo caso, stai usando il protocollo git direttamente, senza supporto per l'autenticazione. DOMANDA: C'è una rettifica sulla questione git+ssh, è opposto a ssh (???) RISPOSTA: Si, c'è una differenza anche qui. Io non ho un caso d'uso tra le mani. Tranne i tecnicismi del protocollo usato e cosa supporta il server. Non mi viene in mente nessuna differenza dal punto di vista dell'utente. DOMANDA: Quali sono le limitazione di un repo git in locale clonato con {{{--depth 1}}}, sarò comunque in grado di cambiare branch e avrà effetto su un'età più limitata per quanto riguarda la cronologia e git pull? RISPOSTA: {{{--depth}}} specifica quanta cronologia ottenere da un repository. Significa che, per esempio, sei interessato solo alla cronologia recente di un grande progetto ed ha anche le sue limitazioni: per esempio, non puoi clonarlo, o pushare da/dentro di lui. Devo essere onesto, non ho mai usato {{{--depth}}}. Ho solo letto di questa opzione agli inizi, quando ho iniziato a studiare git. == Guarda anche == |
DOMANDA: L'opzione clone, clona solo il branch master... o anche gli altri? RISPOSTA: {{{git clone}}} clona solo il branch master. Cioè, gli altri branch verranno scaricati, ma non verrà creato nessun branch locale per loro. Per correggere questa situazione, solitamente l'autore lancia questo comando per ogni branch che mi interessa. {{{$ git checkout -b miobranch -t origin/miobranch}}} ({{{-t origin/miobranch}}} significa "traccia miobranch da origin") DOMANDA: C'è differenza tra `git+ssh://` e `git://`? RISPOSTA: Sì, c'è. `git://` è un "protocollo stupido" e non supporta l'autenticazione. Quindi, nel primo caso, questo protocollo viene incapsulato in SSH: in modo simile a `svn+ssh://` o `cvs+ssh://` o altri. Nel secondo caso, si sta usando il protocollo git direttamente, senza supporto per l'autenticazione. DOMANDA: Rettifico la domanda su git+ssh, c'è differenza con ssh? RISPOSTA: Sì, anche in questo caso ci sono differenze. L'autore è spiacente ma non sa pensare ad un caso pratico. A parte i tecnicismi del protocollo usato e di ciò che il server supporta, non riesce a pensare ad alcuna differenza dal punto di vista dell'utente. DOMANDA: Quali sono le limitazioni di un repository git in locale clonato con {{{--depth 1}}}, sarò comunque in grado di cambiare branch e invecchiando diventerà un repository meno limitato col passare del tempo e i vari git pull? RISPOSTA: {{{--depth}}} specifica quanta cronologia ottenere da un repository. Ciò significa che, ad esempio, si è interessati solo alla cronologia recente di un grande progetto; ha anche le sue limitazioni: per esempio, non può essere clonato né si può fare il push da o verso di esso. Per essere sinceri, l'autore non ha mai usato {{{--depth}}}, ha solo letto di questa opzione agli inizi, quando ha iniziato a studiare git. == Vedere anche == |
Translation(s): English - Italiano
Contents
Usare Git
Seminario online tenuto da David Paleino per Debian Women, 25-Nov-2010
Questa è una guida introduttiva all'uso di git. Verranno spiegate le basi per capire il suo funzionamento e il suo uso.
Requisiti
In questa guida si presume che:
si conosca l'uso di base della riga di comando e l'utilizzo di un editor di testo a scelta (emacs, vim, gedit, kate, etc.) per modificare file.
Requisiti tecnici:
Introduzione
Cos'è git? Git è un sistema di Controllo di versione distribuito. La parte importante è Controllo di versione: significa che è un programma che permette di tenere traccia dei cambiamenti dei file e comparare le differenti "versioni", e fare anche altre cose fantastiche, come tornare indietro a precedenti versioni di un certo file.
Git viene usato da molti progetti software moderni, quindi è bene conoscere almeno un po' del suo funzionamento. Non c'è bisogno di andare molto nei dettagli, verrà spiegato solo il suo funzionamento di base e il suo uso generale.
Teoria
Sistema di controllo di versione ''distribuito''
Noi abbiamo analizzato git come Sistema di Controllo di Versione (VCS), ma git è un VCS distribuito. Distribuito è un dettaglio dell'architettura di git, che ha alcuni pro e alcuni contro. Ci sono altri "sistemi VCS famosi, come CVS e SVN, chiamati VCS centralizzati; questi hanno bisogno di avere una connessione al server centrale, dove sono conservati tutti i dati, per eseguire molte operazioni. Basti pensare al comando log: SVN ha bisogno di connettersi al server e scaricare i dati.
Con i VCS distribuiti (e git è uno di questi) ciò non avviene: ogni copia del repository è una copia completa. Questo significa che le operazione sono più veloci e che, soprattutto, si può usare git sul proprio computer locale, senza avere un server.
Ovviamente anche i VCS distribuiti hanno i loro difetti, il problema principale secondo l'autore di questa guida è il gran numero di conflitti. Questo avviene perché con i VCS centralizzati un commit è di solito rifiutato se determina un conflitto con la copia del server. Invece con i VCS distribuiti, chiunque può eseguire un commit nel suo repository e il conflitto avviene solo al momento del push (il termine "push" verrà spiegato in seguito).
Il modello di immagazzinamento di git
Ogni oggetto all'interno di un repository git è identificato da una stringa univoca. Questa è chiamata hash. Normalmente è una somma SHA1 di alcune proprietà di cui parleremo più tardi.
Un oggetto git può essere un blob, un tree, un commit o un tag. Di seguito le descrizioni di ciascuno di essi.
Un blob è un oggetto git su cui sono conservati i dati. È generalmente un file su disco.
Un tree è come una directory, ha riferimenti ad altri tree o blob. Si può immaginarlo come una directory con file e sottodirectory al suo interno.
Un commit è un riferimento ad un singolo tree e contiene anche altre meta-informazioni, come la data e l'ora, l'autore (nome ed email) che ha apportato le modifiche e un puntatore al commit precedente. Generalmente, quando si usa git, si fa riferimento solo ai commit.
Un tag è solo un modo per segnare un commit come speciale per qualche caratteristica. Generalmente, i tag vengono usati per segnare commit con i numeri di versione, rilascio e così via.
Se si pensa al modello di immagazzinamento di git, si può distinguere una "area di lavoro", un "indice" e un "repository":
L' area di lavoro è composta dai file attualmente presenti nella directory git
L'indice e il repository, invece, sono contenuti all'interno di ./.git/ : qui è dove tutti i repository git risiedono ed è sufficiente per ricreare il contenuto delle directory. Andando oltre, si può dire che l'indice è come una temporanea area di sosta, dove si possono aggiungere i file prima di fare il commit. Una volta che il commit è stato eseguito, i file vanno all'interno del repository e l'azione compiuta verrà conservata nella sua cronologia, se il commit non viene eseguito, i file possono essere rimossi dall'indice senza lasciare traccia nella cronologia del repository.
Pratica
Creare un repository
Per la parte pratica, si è preferito usare un progetto reale, anziché inventarsi un repository. Si è scelto di usare "GNU Hello"; il suo archivio tar può essere scaricato da http://ftp.gnu.org/gnu/hello/hello-2.6.tar.gz. In questa guida verrà creato un repository a partire da questo codice sorgente.
Scaricare l'archivio tar:
$ wget http://ftp.gnu.org/gnu/hello/hello-2.6.tar.gz
Una volta fatto, spacchettarlo:
$ tar zxvf hello-2.6.tar.gz
Questo comando creerà la directory hello-2.6/. Adesso si può entrare nella directory ed iniziare a giocare con git
Prima di tutto, si deve configurare l'username e l'indirizzo e-mail. Queste informazioni verranno usate nei commit e saranno visibili nella cronologia del repository. Per fare ciò, si usa git config. In particolare, dato che in questo caso si tratta del primo utilizzo, si vuole impostare un username e un indirizzo e-mail in modo globale. Per farlo lanciare i comandi:
$ git config --global user.name "Debian Woman Attendant" $ git config --global user.email "attendant@debian.org"
Naturalmente usare i propri dati
L'opzione --global fa in modo che il cambiamento sia globale, cioè per ogni repository git sul computer i dati verranno scritti in ~/.gitconfig. Controllare questo file, dopo che aver eseguito questi due comandi. Si vedranno le informazioni fornite.
L'username e l'indirizzo e-mail possono anche essere impostati per ciascun repository: in questo caso, lo si deve fare dopo aver creato il repository e senza usare l'opzione --global. Senza --global, le informazioni verranno inserite localmente in ./.git/config.
Sono stati impostati l'username e l'indirizzo e-mail. Ora, si deve creare il repository git. Perciò entrare nella directory hello-2.6/ e lanciare:
$ git init
Il risultato sarà qualcosa di simile a:
Initialized empty Git repository in /tmp/dw/hello-2.6/.git/
git init semplicemente crea una directory .git/, con alcuni valori predefiniti. Per vedere lo stato di un repository, eseguire:
$ git status
Tale comando mostra i file monitorati e non, e lo stato dell'indice. In più, mostrerà in qualche branch si è (i branch verranno spiegati in seguito).
Indicizzazione
Nel repository non c'è ancora nulla. Aggiungere perciò il codice sorgente:
$ git add .
Il "." è una sintassi comune dei sistemi simil-Unix: significa "directory corrente". Perciò di fatto viene aggiunto tutto. Ora, controllare git status di nuovo. Si vedrà che qualcosa è cambiato. Quello che si vede ora è lo stato dell'indice.
Si potrebbe ancora rimuovere elementi dall'indice senza lasciare traccia nella cronologia. Provare a farlo! Rimuovere il file AUTHORS dall'indice e rimetterlo nello stato di "non tracciato":
$ git rm --cached AUTHORS
Ora guardare di nuovo git status. Si vedrà Changes to be committed(cambiamenti di cui si deve fare il commit) (l'indice) e Untracked files (file non tracciati).
Commit
Ora si vuole fare il commit dei file nell'indice: questo creerà un commit, con un hash, e verrà conservato nella cronologia del repository. Eseguire:
$ git commit
Questo comando aprirà l'$EDITOR (quello dell'autore è nano, controllare quale sia il proprio), in cui va scritto un messaggio di commit. Se non ne viene scritto uno, il commit verrà annullato (sì, si deve inserire un messaggio di commit).
Chiamarlo "Commit iniziale". Ora, lanciare di nuovo git status . I file nell'indice sono spariti! Ne è stato fatto il commit all'interno del repository e ne è stato fatto un log.
Il log si può vedere con:
$ git log
Verrà mostrato l'autore del commit (con le informazioni inserite prima), la data e l'ora e l'hash del commit.
Si può anche vedere l'ultimo commit con:
$ git show
Aprirà automaticamente il $PAGER (more, less, ...) e mostrerà il contenuto dell'ultimo commit. git show accetta anche un hash come argomento. Per chi scrive l'hash del commit è 11aab8486d20490b16b1b7d847e1cb1e4f7aa2fe . Il valore sarà diverso per ogni lettore che provi a seguire l'esempio. Non è necessario scrivere l'hash completo: normalmente bastano i primi 7 o 8 caratteri. Quindi si può lanciare:
$ git show 11aab848
git supporta anche diversi nomi simbolici, ma non verranno spiegati qui in quanto non argomenti "di base" (ci si riferisce a HEAD, HEAD^, HEAD~2 e così via).
Gli autori (AUTHORS) sono stati lasciati fuori dal repository... poveracci! nessun merito al loro lavoro! Questo problema può essere corretto con:
$ git add AUTHORS $ git commit -m 'Aggiunti AUTHORS'
-m è una scorciatoia per messaggio: si evita in questo modo di aprire $EDITOR.
Ora, si proverà a modificare alcuni file, guardare le differenze e farne il commit. Fingere di aver scritto un pezzo di codice.
Aggiungere il proprio nome al file AUTHORS
E aggiungere anche qualcosa al "ChangeLog". Quello che si vuole, è solo un esempio.
Ora usare git status. Si vedranno due righe che iniziano con modified(modificato). Per vedere le differenze introdotte:
$ git diff
(Opzionalmente, git diff nomefile mostrerà solo le differenze in quel file.)
Se queste modifiche vanno bene, fare il commit! È possibile usare git add per ciascun file e fare il commit git commit oppure usare semplicemente:
$ git commit -a -m "Messaggio a piacere"
L'opzione -a aggiungerà tutto all'indice (ma solo i file tracciati, quelli non tracciati non saranno toccati). Si otterrà:
[master 3295347] Messaggio a piacere 2 files changed, 5 insertions(+), 0 deletions(-)
master è il branch in cui si è attualmente. La stringa successiva è l'hash del commit; può essere usata in molti comandi (git show <commit>, git log <commit>, ecc.). Dopo vi è il messaggio di commit e le statistiche dei cambiamenti apportati.
Branch
Cos'è un branch?
Si pensi al repository git come ad un fiume. Ad un certo punto, lo sviluppo può divergere dal "flusso principale" e rimanere per conto suo, oppure unirsi di nuovo al fiume originale. Il master è il fiume principale.
Creare un branch, chiamandolo debian:
$ git branch debian
Per spostarsi in questo nuovo branch, lanciare:
$ git checkout debian
Una scorciatoia per entrambi i comandi è:
$ git checkout -b debian
Perfetto, si è fatto il checkout del branch debian. Per controllare se è vero, eseguire git branch, senza argomenti. Mostrerà i branch locali attuali; quello in cui si è sarà preceduto da un *.
Per tornare indietro al branch principale, eseguire: git checkout master.
Ma per il momento restare nel branch debian: *debian. Si immagini di fare il lavoro di pacchettizzazione all'interno di questo branch.
Quindi, creare una directory debian/. Se è vuota, git status non la mostrerà; è il comportamento atteso: git non tiene traccia delle directory vuote. Per ingannarlo a farlo si può aggiungere un file vuoto alla directory. L'autore normalmente aggiunge un file .gitignore (è un file speciale usato da git), per fare tracciare una directory vuota. Eseguire perciò:
$ mkdir debian $ touch debian/.gitignore
Ora git status mostrerà la non-tracciata debian/. Aggiungerla e farne il commit.
Tornare ora al branch master
$ git checkout master
Ora si vuole far divergere questi due branch, per simulare un branch reale: cambiare tutti i file che si desidera, in qualunque modo, e farne il commit.
Si può usare un'interfaccia grafica (come ad esempio gitg o gitk) o qualcosa da riga di comando (git show-branch) per vedere come i due branch sono divergenti. Visto che le interfacce grafiche sono facili da usare, verrà usata la riga di comando
$ git show-branch
Si vedrà che i due branch hanno un commit inziale in comune, ma poi hanno commit differenti. Unire i cambiamenti di "debian" in "master"
$ git merge debian
Si vedrà qualcosa come:
Merge made by recursive. 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 debian/.gitignore
È in questo momento che avverranno i "conflitti". Se in debian abbiamo cambiato uno dei file cambiati prima del merge, potrebbe essere avvenuto un conflitto.
Potrebbe essere utile eseguire git mergetool dopo il merge, per risolvere i conflitti. Userà uno dei diversi possibili programmi per gestire i conflitti. Non si entrerà qui nei dettagli, per un uso base risolvere i conflitti manualmente è sufficiente.
È stato fatto il merge di debian in master. Guardando i log, si dovrebbe vedere qualcosa come:
commit cdfd20167aa05f74f4785ef7aa03355d51add5b3
Merge: 7e9ff3a 2ba81df
Author: David Paleino <dapal@debian.org>
Date: Thu Nov 25 23:45:28 2010 +0100
Merge branch 'debian'
commit 7e9ff3a18dc114b4ce1e1a96f1dd3ecd696f064d
Author: David Paleino <dapal@debian.org>
Date: Thu Nov 25 23:43:49 2010 +0100
New author
commit 2ba81dfaeb919e6a0c634be54fe363b11487d65a
Author: David Paleino <dapal@debian.org>
Date: Thu Nov 25 23:42:42 2010 +0100
add debian/
commit 3295347b1dbd7b5925dca7fcc6858af51a710ada
Author: David Paleino <dapal@debian.org>
Date: Thu Nov 25 23:32:55 2010 +0100
Messaggio a piacere
commit f6aa148a5ce1331de6d17e770a8efbb98ad32344
Author: David Paleino <dapal@debian.org>
Date: Thu Nov 25 23:11:57 2010 +0100
Aggiunti AUTHORS
commit 11aab8486d20490b16b1b7d847e1cb1e4f7aa2fe
Author: David Paleino <dapal@debian.org>
Date: Thu Nov 25 23:03:42 2010 +0100
Commit iniziale
Ripristino
L'ultima cosa da spiegare per quanto riguarda il lavoro in locale è git revert.
Supponiamo di trovare qualcosa che non piace nel git log. Per esempio, diciamo che è il commit 2ba81dfaeb919e6a0c634be54fe363b11487d65a, quello con cui è stata aggiunta la directory debian/. Ci si ricordi che gli hash sono differenti per ciascuna persona, quindi si guardi il log per vedere il proprio.
Dunque, quel commit non piace. Cosa si deve fare ora? Si può usare il comando git revert.
Questo comando prende semplicemente il cambiamento (diff) da un commit, lo applica al contrario e lascia i conflitti, se ce ne sono; provarlo:
$ git revert 2ba81dfaeb919e6a0c634be54fe363b11487d65a
$EDITOR (nano, vim, ecc.) si aprirà di nuovo. C'è un messaggio di commit predefinito; si può lasciarlo così com'è o spiegare (scelta consigliata) perché si stanno annullando i cambiamenti. Per semplicità in questo caso lasciarlo intatto. Salvare il messaggio ed uscire dall'editor.
Si vedrà:
Finished one revert. [master 37ce99f] Revert "add debian/" 0 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 debian/.gitignore
Questo significa che anche il rispristino è un commit. Con un committer, un autore, una data e un orario ed un hash. Si potrebbe anche ripristinare un ripristino (ma è meglio non farlo).
NOTA: Ripristinare un merge non è semplice. Si deve specificare anche il genitore principale. Si legga la documentazione dell'opzione -m di git revert. Ha anche qualche brutto effetto collaterale (IMHO), quindi non fare nessun merge se non si è assolutamente sicuri.
Lavorare in modo distribuito
Git è un VCS distribuito; perciò quella trattata ora è una parte fondamentale. Permette di condividere il proprio lavoro, e il proprio sviluppo, con altre persone. Si metta perciò da parte il repository.
Usare clone e push
Per questa guida è stato preparato un repository online per i sorgenti di GNU Hello che vengono usati. Questo è normalmente quello che si trova per i progetti esistenti: un repository online. Si può copiare il loro contenuto (clonarli) usando il comando git clone. Clonare quindi il repository, (Ah! prima di farlo, uscire dalla directory hello-2.6/):
$ git clone git://gitorious.org/debian-women/hello.git
Si vedrà qualcosa come:
Cloning into hello... remote: Counting objects: 263, done. remote: Compressing objects: 33% (54/16Receiving objects: 6% (16/263), 52.00 remote: Compressing objects: 50% Receiving objects: 9% (24/263), 108.00 KiB |remote: Compressing objReceiving objects: 10% (27/263), 108.00 KiB | 93 KiB/s remote: Compressing objects: 100% (161/161), done. remote: Total 263 (delta 101), reused 263 (delta 101) Receiving objects: 100% (263/263), 626.93 KiB | 120 KiB/s, done. Resolving deltas: 100% (101/101), done.
Ora, entrare in hello/ e iniziare a curiosare un po' con git log, git show, ...
È un repository pulito, ma è stato preso dal web. Se fosse stato un vero repository, probabilmente non avrebbe mostrato solo un commit, né solo un branch.
Vedere ora da dove è stato preso il repository. Si possono ottenere o impostare informazioni sula fonte da cui è stato preso il repository con git remote. C'è un remote predefinito, chiamato origin. È anche quello predefinito in cui verranno fatti i push. Guardare com'è:
$ git remote show origin
Per ora, solo queste due righe sono interessanti:
Fetch URL: git://gitorious.org/debian-women/hello.git Push URL: git://gitorious.org/debian-women/hello.git
Significa che si sta sincronizzando dal "Fetch URL" e si sta facendo il push sul "Push URL". Questi non devono per forza combaciare, possono essere diversi; come, ad esempio, se si sta mantenendo una versione con patch di un software da qualche parte: si prendono i dati dagli autore a monte e si fa il push nella propria posizione.
Si può aggiungere un remote senza rimuovere il lavoro precedente. Per fare questo, si può usare git remote add. La sintassi è la seguente:
git remote add <nome_remoto> <url_remoto>
Di solito, se si vuole essere in grado di fare il push su un repository, si deve usare un url git+ssh:// o ssh://. Un url git://git.[...] normalmente non permette di fare push. (A dire il vero, l'autore di questa guida non ne ha mai visto uno che lo permettesse, ma è meglio usare "normalmente non permette" che "non permette mai".)
git remote add è utile specialmente quando si sta creando un nuovo repository, ovvero quando non si sta clonando da qualche parte.
Domande e risposte
DOMANDA: Un oggetto tree del commit contiene l'intero tree del progetto o solo i file cambiati?
RISPOSTA: Un oggetto tree del commit rappresenta l'intero repository ad un certo punto del tempo, quindi contiene i riferimenti a tutto il tree dell'intero progetto.
DOMANDA: I file vanno nell'indice con: git commit?
RISPOSTA: No, git commit crea un commit che viene inserito nel repository. Ne ho parlato prima, ma questa immagine spiega bene il concetto.
DOMANDA: Se ricopio i file senza la directory .git perdo tutta la cronologia?
RISPOSTA: Sì, la directory .git è quella che che contiene l'intera cronologia, i commit e tutto quanto. Ed è sufficiente una directory .git per ricreare il repository.
DOMANDA: L'indice è nella directory .git?
RISPOSTA: Sì, è conservato lì.
DOMANDA: Il push fallisce se ci sono conflitti? Se è così, questo pro può essere un contro perché un repository condiviso (se usato) sarà sempre in uno stato funzionante.
RISPOSTA: Sì, il push fallisce. È stato detto prima che un maggiore numero di conflitti è uno svantaggio dei VCS distribuiti, ma git permette di risolverli e rifare il push.
Per quanto riguarda "i repository condivisi che funzionano sempre", anche i VCS centralizzati risolvono i conflitti, ma lo fanno in modo automatico. Questo può portare però a soluzioni erronee; git, invece, è un tracciatore di contenuti "stupido" (come dice la parola), quindi chiede aiuto ogni volta che ne ha bisogno. Quindi, mentre un SVN correggerebbe automaticamente gli errori per conto dell'utente, (che non saprà realmente per certo cosa andrà a finire nel repository), in git il push fallisce e l'utente gestisce i conflitti localmente (e dopo rifa il push).
DOMANDA: «Ed è sufficiente una directory .git per ricreare il repository.» : qual è il comando per ricrearla?
RISPOSTA: Si deve semplicemente lanciare git clone dalla directory. Se, per esempio, si ha una directory .git/ di un progetto, basta rinominarla in project.git e dopo lanciare "git clone project.git": ci si ritroverà con la directory project/ con tutto al suo interno. La rinominazione rende tutto più semplice, basterebbe fare git clone .git miaaltradir (e tutto finirà in miaaltradir/)
DOMANDA: Come si possono trovare le impostazioni attuali per l'username e l'e-mail globale? (Se si vogliono solo conoscere le informazioni prima di cambiarle
) ~/.gitconfig?
RISPOSTA: Per ottenere un valore specifico si può usare git config --get. Quindi, git config --global --get user.name. Si può anche vedere un elenco di tutti i valori con git config -l e si può modificarli con git config oppure aprendo con un editor ~/.gitconfig o ./.git/config (a seconda se si desidera modificare le impostazioni globali o quelle locali).
DOMANDA: Posso fare una patch al valore di user.name, ecc. all'interno dei file gestiti da git?
RISPOSTA: Sì, si può avere un config separato per ogni repository, basta evitare l'opzione --global. Ma la domanda permette di dare altre risposte: la domanda sembra riferirsi a git filter-branch. Il Committer git è incorporato nell'oggetto Commit (come si è detto ha anche metadati). Quindi, quando si cambia il committer, non si può mantenere lo stesso hash, esso deve cambiare. Quindi opzioni avanzate come filter-branch (che permette di riscrivere la cronologia di un repository) non dovrebbero mai essere usate su repository pubblico, perché significa creare tonnellate di conflitti e mal di testa.
Tuttavia, è interessante vedere come si può temporaneamente sovrascrivere l'username e l'email configurati. git commit può leggere alcune variabili di ambiente: GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, GIT_AUTHOR_NAME e GIT_AUTHOR_EMAIL. Queste, se impostate, sovrascriveranno quello che c'è in git config. In generale, per ogni variabile di configurazione, git controllerà, in ordine:
~/.gitconfig -> ./.git/config -> variabile d'ambiente, se esiste.
Se si configura qualcosa in ./.git/config, questa sovrascriverà quella globale. Se si configura una variabile d'ambiente GIT_*, essa sovrascriverà tutto.
./.git/config estende ~/.gitconfig. Significa che non si deve copiare tutto il contenuto dalla configurazione globale.
DOMANDA: Come posso ottenere la lista dei file cambiati? git log mostra l'autore, la data e l'ora, il commento ma io non ho bisogno del contenuto dei file (ho solo bisogno del loro elenco).
RISPOSTA: L'elenco dei file modificati in ciascun commit può essere visto con git log --raw. Ogni comando git ha molte opzioni e le pagine man normalmente sono molto utili. Per esempio, è possibile combinare git log con --raw e --pretty, per ottenere un output più carino di quello con solo --raw.
Lo stesso per git show: si può passare una stringa di formattazione a --pretty.
Questo, tuttavia, non è "l'uso di base"; si può usare una GUI, l'autore di questa guida usa gitg a volte.
DOMANDA: Git preserva i permessi dei file di cui tiene traccia o devono essere usati degli stratagemmi?
RISPOSTA: Preserva i permessi e si accorge anche di quando vengono cambiati; un commit, cioè, può anche consistere solamente in un cambio di permessi.
DOMANDA: git show mostra un file enorme. Nessun commento su questo?
RISPOSTA: È così perché è il primo commit dove è stato importato tutto. Di norma è meglio fare commit "atomici". (Si può dire che è la prassi raccomandata.) Quindi di solito, non si vede un output così grosso; comunque usa less in modo predefinito per cui non si dovrebbero avere molti problemi con questo
DOMANDA: Posso semplicemente copiare la directory sul mio server web e lasciare che gli altri la clonino usando git clone http://myserver/hello-2.6?
RISPOSTA: Sì, si può. Se non si ha bisogno dei file in quella cartella, è solitamente meglio condividere solamente la directory .git con il nome project.git. Questo viene di solito chiamato "bare repository".
DOMANDA: C'è un modo per semplificare: git add + git commit -m ? O vanno lanciati uno ad uno?
RISPOSTA: Sì, c'è. Se si vuole fare il commit di tutti i file, si può usare l'opzione -a di git commit. Quindi, git commit -a -m "Messaggio" farà il commit di tutto ciò che è già tracciato.
DOMANDA: Una delle cose che mi sembrano strane è avere il repository come parte dell'area di lavoro. È semplice avere un repository in un albero di directory diverso? O è necessario creare repository addizionali?
RISPOSTA: Si può, ma è una modalità di lavoro un po' avanzata. Leggere la sezione core.worktree nella pagina man di git-config.
DOMANDA: Ad esempio io ho un'applicazione web sotto git e voglio usarla senza la directory .git. Qual è il miglio modo per farlo?
RISPOSTA: La risposta è la stessa di prima: impostare esplicitamente core.worktree in ./.git/config ad un percorso differente.
DOMANDA: Ho creato una cartella vuota (test1) ma git status non visualizza niente, quindi ho fatto echo test > test1/testfile e l'output di git status mi restituisce # test1/ ma nessun testfile. È il comportamento atteso?
RISPOSTA: Sì, come è stato detto prima, è stato creato con touch un .gitignore vuoto all'interno di una directory vuota per fare in modo che git la tracci.
DOMANDA: Cosa succede se si annulla un cambiamento su un branch che non è lo stesso che è stato estratto?
RISPOSTA: Non succede niente, cioè il ripristino non avviene.
DOMANDA: Se ho un branch e faccio il merge, ma voglio ripstinarlo, come trovo l'hash?
RISPOSTA: git log è la soluzione.
DOMANDA: L'opzione clone, clona solo il branch master... o anche gli altri?
RISPOSTA: git clone clona solo il branch master. Cioè, gli altri branch verranno scaricati, ma non verrà creato nessun branch locale per loro. Per correggere questa situazione, solitamente l'autore lancia questo comando per ogni branch che mi interessa.
$ git checkout -b miobranch -t origin/miobranch
(-t origin/miobranch significa "traccia miobranch da origin")
DOMANDA: C'è differenza tra git+ssh:// e git://?
RISPOSTA: Sì, c'è. git:// è un "protocollo stupido" e non supporta l'autenticazione. Quindi, nel primo caso, questo protocollo viene incapsulato in SSH: in modo simile a svn+ssh:// o cvs+ssh:// o altri. Nel secondo caso, si sta usando il protocollo git direttamente, senza supporto per l'autenticazione.
DOMANDA: Rettifico la domanda su git+ssh, c'è differenza con ssh?
RISPOSTA: Sì, anche in questo caso ci sono differenze. L'autore è spiacente ma non sa pensare ad un caso pratico. A parte i tecnicismi del protocollo usato e di ciò che il server supporta, non riesce a pensare ad alcuna differenza dal punto di vista dell'utente.
DOMANDA: Quali sono le limitazioni di un repository git in locale clonato con --depth 1, sarò comunque in grado di cambiare branch e invecchiando diventerà un repository meno limitato col passare del tempo e i vari git pull?
RISPOSTA: --depth specifica quanta cronologia ottenere da un repository. Ciò significa che, ad esempio, si è interessati solo alla cronologia recente di un grande progetto; ha anche le sue limitazioni: per esempio, non può essere clonato né si può fare il push da o verso di esso. Per essere sinceri, l'autore non ha mai usato --depth, ha solo letto di questa opzione agli inizi, quando ha iniziato a studiare git.
