Wiki Ubuntu-it

Indice
Partecipa
FAQ
Wiki Blog
------------------
Ubuntu-it.org
Forum
Chiedi
Chat
Cerca
Planet
  • Pagina non alterabile
  • Informazioni
  • Allegati
  • Differenze per "Programmazione/Git"
Differenze tra le versioni 7 e 23 (in 16 versioni)
Versione 7 del 05/12/2014 23.54.56
Dimensione: 26309
Autore: jeremie2
Commento:
Versione 23 del 27/03/2026 18.48.14
Dimensione: 8778
Autore: ivantu
Commento: +correzioni
Le cancellazioni sono segnalate in questo modo. Le aggiunte sono segnalate in questo modo.
Linea 3: Linea 3:
<<Indice(depth=2)>>
<<Informazioni(forum="http://forum.ubuntu-it.org/viewtopic.php?f=46&t=590616"; rilasci="14.04")>>
<<Indice(depth=1)>>
<<Informazioni(forum="http://forum.ubuntu-it.org/viewtopic.php?f=46&t=590616"; rilasci="24.04 22.04")>>
Linea 8: Linea 8:
'''Git''' è un [[http://it.wikipedia.org/wiki/Controllo_versione|CVS]] ('''C'''ontrol '''V'''ersion '''S'''ystem). Gli aspetti importanti di un CSV si possono riassumere nel: '''Git''' è un sistema di controllo di versione distribuito ('''[[https://it.wikipedia.org/wiki/Controllo_versione_distribuito|DVCS]]''' - '''D'''istributed '''V'''ersion '''C'''ontrol '''S'''ystem) utilizzabile da [[AmministrazioneSistema/Terminale|riga di comando]]. Gli aspetti principali riguardano:
Linea 14: Linea 14:
Rispetto a programmi come [[Programmazione/Cvs|CVS]], [[Programmazione/Subversion|Subversion]] ma più similmente a [[http://mercurial.selenic.com|Mercurial]], [[Programmazione/Bazaar|Baazar]], '''Git''' è caratterizzato da un sistema di controllo di versione localizzato, cioè utilizzabile con repository locali invece che remoti. Programmi come '''Subversion''' adottano un repository centrale, che materialmente è il posto (server, servizio web) in cui risiede il progetto. Gli utenti sincronizzano il lavoro con questo repository e quando devono salvare delle modifiche al progetto (''commit''), le salvano direttamente sul repository centralizzato. A differenza di programmi come [[Programmazione/Cvs|CVS]] o [[Programmazione/Subversion|Subversion]], e in modo simile a [[http://mercurial.selenic.com|Mercurial]] o [[Programmazione/Bazaar|Baazar]], '''Git''' è caratterizzato da una gestione localizzata, ovvero è utilizzabile con repository locali invece che esclusivamente remoti. Sistemi come '''Subversion''' adottano un repository centrale (server o servizio web) in cui risiede il progetto. In tali sistemi, la sincronizzazione del lavoro e il salvataggio delle modifiche (''commit'') avvengono direttamente sul repository centralizzato.
Linea 16: Linea 16:
'''Git''' invece lavora in locale. Non esiste un repository centralizzato nel modo che si intende in '''Subversion''' et similia. Ogni cartella di lavoro è un repository autosufficiente. Commit, ricerca log e molte altre azioni vengono eseguite in locale, senza l'appoggio di un server esterno. Quando si rende necessario è possibile sincronizzarsi con altri repository (server centrale, pc in rete, ecc..). Questo comporta ovvi vantaggi in termini di flessibilità. Ogni directory di lavoro è un repository autosufficiente. Operazioni come commit, consultazione dei log e molte altre azioni vengono eseguite localmente, senza necessità di un server esterno. La sincronizzazione con altri repository (server centrale, altri PC in rete, ecc.) avviene solo quando necessario. Ciò garantisce maggiore flessibilità e velocità d'esecuzione.

{{{#!wiki note
Se si utilizza '''[[Ufficio/EditorDiTesto/VisualStudioCode#Git_in_Visual_Studio_Code|Visual Studio Code]]''' per programmare, '''Git''' è integrato nativamente.
}}}
Linea 19: Linea 23:
= Installazione/Configurazione base = = Installazione =
Linea 21: Linea 25:
 0. Per installare '''Git''' digitare in un [[AmministrazioneSistema/RigaDiComando|terminale]]:{{{
sudo apt-get install git
Sebbene l'uso del [[AmministrazioneSistema/Terminale|terminale]] sia il metodo più diretto e completo

[[AmministrazioneSistema/InstallareProgrammi/Apt|Installare]] '''Git''', digitare in un [[AmministrazioneSistema/Terminale|terminale]] il seguente comando:{{{
sudo apt install git
Linea 24: Linea 30:
 0. Impostare '''nome utente''' e '''indirizzo e-mail''' che si vogliono utilizzare per identificarsi nei progetti:{{{
== Interfaccia grafica ==

'''Git''' include due strumenti storici ad interfaccia grafica basati su Tcl/Tk. Sono essenziali ma molto leggeri e funzionali, per agevolare la visualizzazione dei branch e la gestione dei commit:

[[AmministrazioneSistema/InstallareProgrammi/Apt|Installare]] i pacchetti:
 * '''[[apt://gitk|gitk]]''': Specializzato nella visualizzazione della cronologia e dei branch.
 * '''[[apt://git-gui|git-gui]]''': Focalizzato sulla creazione dei commit, la gestione dell'area di staging e le operazioni di merge semplici.

Essendo leggeri e funzionali '''gitk''' e '''git-gui''' richiedono l'avvio dal [[AmministrazioneSistema/Terminale|terminale]] all'interno della cartella del progetto, digitando i comandi:{{{
gitk
}}} o {{{
git-gui
}}}

=== Ottimizzazione in GNOME ===

Per l'ambiente desktop [[AmbienteGrafico/Gnome|GNOME]] '''Gitg''' offre una visualizzazione moderna e pulita dei [[Programmazione/Git/Commit|commit]] e permette di gestire le operazioni comuni.

[[AmministrazioneSistema/InstallareProgrammi/Apt|Installare]] il pacchetto [[apt://gitg|gitg]].


##=== GitKraken / SmartGit (Proprietari/Avanzati) ===

##Esistono client molto potenti e professionali, spesso usati in ambito aziendale:

## * '''!GitKraken''': Esteticamente molto curato, disponibile come pacchetto .deb o tramite Snap. È gratuito per repository pubblici.
## * '''!SmartGit''': Molto completo, gratuito per uso non commerciale.

<<Anchor(configurazione)>>
= Configurazione base =

Dopo l'installazione è necessario definire l'identità dell'utente per firmare correttamente i commit.

== Identificazione utente nei progetti ==

Impostare il '''nome utente''' e l''''indirizzo e-mail''' da utilizzare globalmente per l'identificazione nei progetti Git, digitare nel [[AmministrazioneSistema/Terminale|terminale]] questi comandi:{{{
Linea 27: Linea 69:
}}}avendo cura di soistituire le diciture NOME_UTENTE e INDIRIZZO_E-MAIL col proprio nome utente e indirizzo e-mail.
 ||<tablestyle="text-align: justify; width:100%;" style="border:none;" 5%><<Immagine(Icone/Piccole/note.png,,center)>> ||<style="padding:0.5em; border:none;">''È possibile modificare questi dati per un singolo repository omettendo il flag '''--global.''''' ||
 0. Consigliato ma non obbligatorio, impostare l'alias '''lg''' per una versione personalizzata del comando '''log''' al fine di migliorarne la leggibilità:{{{
}}}sostituendo le diciture `NOME_UTENTE` e `INDIRIZZO_E-MAIL` con i propri dati. Esempio per l'utente '''Mario Rossi''':{{{
git config --global user.name "Mario Rossi"
git config --global user.email mario.rossi@mail.com
}}}

{{{#!wiki note
Le configurazioni globali vengono salvate nel file nascosto `.gitconfig` nella propria directory '''Home'''. Per impostare dati specifici solo per un determinato repository, è sufficiente omettere l'opzione '''--global''' mentre ci si trova all'interno della cartella del progetto.
}}}

== Impostazione alias lg ==

Il monitoraggio dell'evoluzione del progetto avviene tramite la consultazione dello storico dei [[Programmazione/Git/Commit|commit]]. '''Git''' fornisce il comando nativo `git log`, tuttavia, per facilitare la lettura dei rami e delle modifiche, è prassi comune impostare un alias '''lg''' che fornisca una rappresentazione grafica, colorata e sintetica, al fine di migliorarne la leggibilità dei rami.

{{{#!wiki important
Operazione da eseguire una sola volta.
}}}

Digitare nel [[AmministrazioneSistema/Terminale|terminale]] il seguente comando:{{{
Linea 33: Linea 90:
<<Anchor(cronologia)>>
== Visualizzazione della cronologia ==

Per visualizzare la cronologia, l'andamento dei rami in qualsiasi repository del sistema una sola volta [[#Impostazione_alias_lg|configurato l'alias]] '''lg''', digitare nel [[AmministrazioneSistema/Terminale|terminale]] il seguente comando:{{{
git lg
}}}

Altrimenti per visualizzare la cronologia testuale semplice, digitare nel [[AmministrazioneSistema/Terminale|terminale]] il comando:{{{
git log
}}}

<<Anchor(creare)>>
Linea 35: Linea 104:
Viene qui mostrato come creare un '''nuovo progetto''' o come importare (clonare) un '''progetto esistente'''.   Per creare un '''nuovo progetto''' o per importare (clonare) un '''progetto esistente''', vengono descritte di seguito le procedure.
Linea 37: Linea 106:
== Creazione nuovo repository ==  0. [[AmministrazioneSistema/ComandiBase#mkdir|Creare]] la directory `gitproject` nella propria cartella '''Home''', digitare nel [[AmministrazioneSistema/Terminale|terminale]] i seguenti comandi:{{{
 mkdir ~/gitproject
 }}}
 0. [[AmministrazioneSistema/ComandiBase#cd|Spostarsi]] all'interno della cartella creata:{{{
 cd ~/gitproject
 }}}
 0. Per inizializzare un repository vuoto, digitare:{{{
 git init
 }}}Verrà creata la cartella nascosta `.git` contenente l'intera cronologia e i dati di controllo e restituito un messaggio simile al seguente:{{{
 Inizializzato un repository Git in /home/mario/gitproject/.git/
 }}}
Linea 39: Linea 118:
<<Anchor(creare)>>
 0. Creare la cartella `~/gitproject` nella propria '''Home''' che conterrà il progetto e spostarsi al suo interno:{{{
mkdir gitproject
cd gitproject
{{{#!wiki note
Si ricorda che tutte le operazioni di gestione del repository (commit, visualizzazione cronologia, gestione branch, ecc.) devono essere eseguite posizionandosi all'interno della directory del progetto (ad esempio tramite il comando `cd ~/gitproject`). In questo modo Git può accedere alla sottocartella nascosta `.git` necessaria per il corretto funzionamento dei comandi.
Linea 44: Linea 121:
 0. Per inizializzare un repository vuoto su cui poter incominciare a lavorare, digitare:{{{
git init
}}}verrà restituito un messaggio del tipo{{{
Inizializzato un repository Git in /home/USER_NAME/gitproject/.git/
}}}All'interno di `~/gitproject` sarà ora presente la cartella `.git` che contiene le informazioni del repository. Questa cartella è molto importante perché è l'unica che contiene tutti i dati necessari. (In '''Subversion''' ad es. viene creata una cartella .svn in ogni sottocartella del progetto).
Linea 50: Linea 122:
== Clonazione repository == <<Anchor(clonare)>>
= Clonazione repository =
Linea 53: Linea 126:
git clone PERCORSO/PROGETTO
}}}Verrà creata nella propria '''Home''' una cartella col nome del progetto in cui saranno copiati i contenuti.
 git clone PERCORSO/PROGETTO
 }}}Verrà creata nella propria '''Home''' una cartella col nome del progetto in cui saranno copiati i contenuti.
Linea 57: Linea 129:
git clone PERCORSO/PROGETTO PERCORSO/LOCALE
}}}
 git clone PERCORSO/PROGETTO PERCORSO/LOCALE
 }}}
Linea 66: Linea 138:
Git e' molto potente per quanto riguarda i branch. Possiamo creare alberature del repository anche molto complesse e sono molto veloci da gestire. '''Git''' permette una gestione avanzata dei '''branch''' (rami di sviluppo). Consultare la [[Programmazione/Git/Branch|seguente pagina]].
Linea 68: Linea 140:
Per mostrare la lista dei branch presenti si utilizza il comando {{{branch}}}: = Repository remoti =
Linea 70: Linea 142:
{{{
git branch
* master
Tramite gli strumenti '''fetch''', '''pull''' e '''push''' è possibile sincronizzare il lavoro tra diversi utenti. Consultare la [[Programmazione/Git/RepositoryRemoti|seguente pagina]].

= Risoluzioni problemi =

== 'lg' is not a git command ==

Se si prova a digitare `git lg`, '''Git''' restituisce il seguente errore:{{{
git: 'lg' is not a git command. See 'git --help'
Linea 75: Linea 152:
Al momento abbiamo un solo branch attivo. Per creare un nuovo branch utilizziamo lo stesso comando, seguito dal nome del branch che si vuole creare: Il comando `git lg` non esiste nativamente in '''Git''' funziona solo se è stato creato l'[[#Impostazione_alias_lg|alias corrispondente]].
Linea 77: Linea 154:
{{{
git branch gp-1
}}}
= Ulteriori risorse =
Linea 81: Linea 156:
Questo comando non produce nessun output ma se mostriamo di nuovo la lista dei branch, lo possiamo vedere nell'elenco:

{{{
git branch
  gp-1
* master
}}}

L'asterisco identifica il branch attivo, quello su cui stiamo lavorando in questo momento. Se vogliamo lavorare sul branch '''gp-1''' dobbiamo utilizzare il comando '''checkout''', che ci permette di switchare fra i vari branch:

{{{
git checkout gp-1
Switched to branch 'gp-1'
}}}

Vediamo che adesso '''gp-1''' e' il branch su cui lavoriamo:

{{{
git branch
* gp-1
  master
}}}

Che succede nel log?

{{{
git lg
* 1412239 (HEAD, master, gp-1) - user : Aggiunta data in stampa. (2 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (5 minutes ago)
* e9ea39b - user : README aggiunto (12 minutes ago)
}}}

Vediamo che sono presenti entrambi i branch. Dato che ancora sono identici, perche' non abbiamo lavorato su nessuno dei due, puntano allo stesso commit.

Andiamo adesso a fare la modifica al codice:

{{{
sed -i '3 a \\tstd::cout << "Issue gp-1 implementata" << std::endl;' src/main.cpp
cat src/main.cpp
#include <iostream>
int main() {
    std::cout << "Thu Dec 4 14:48:20 CET 2014: Benvenuti su Git!" << std::endl;
    std::cout << "Issue gp-1 implementata" << std::endl;
    return 0;
}
git status
# On branch gp-1
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: src/main.cpp
#
no changes added to commit (use "git add" and/or "git commit -a")
}}}

Possiamo vedere che Git si e' accorto della modifica, ma anche che stiamo modificando il nuovo branch (Il messaggio mostra il nome del branch su cui stiamo lavorando).

Committiamo le modifiche e vediamo che succede nel log:

{{{
git commit -a -m "Modificato codice per issue gp-1."
[gp-1 d8b610a] Modificato codice per issue gp-1.
 1 file changed, 1 insertion(+)
git lg
* d8b610a (HEAD, gp-1) - user : Modificato codice per issue gp-1. (18 seconds ago)
* 1412239 (master) - user : Aggiunta data in stampa. (4 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (7 minutes ago)
* e9ea39b - user : README aggiunto (14 minutes ago)
}}}

Che e' successo? Il branch master, che e' quello su cui lavoravamo prima, e' rimasto inalterato (infatti e' rimasto al commit precedente), mentre nel nuovo branch e' stato memorizzato il commit appena creato. Ovviamente se proviamo ad eseguire il programma otteniamo l'output modificato con la nostra aggiunta:

{{{
make clean
rm -fr bin/ obj/
make
./src/main.cpp
mkdir bin
bin/main
Thu Dec 4 14:48:20 CET 2014: Benvenuti su Git!
Issue gp-1 implementata
}}}

Torniamo nel branch '''master''', rieseguiamo il programma e vediamo che succede:

{{{
git checkout master
Switched to branch 'master'
make clean && make && bin/main
rm -fr bin/ obj/
./src/main.cpp
mkdir bin
Thu Dec 4 14:48:20 CET 2014: Benvenuti su Git!
}}}

Come possiamo vedere, siamo ancora allo stato precedente, prima di eseguire il branch. A questo punto nel log si puo' vedere una cosa interessante:

{{{
git lg
* d8b610a (gp-1) - user : Modificato codice per issue gp-1. (2 minutes ago)
* 1412239 (HEAD, master) - user : Aggiunta data in stampa. (6 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (8 minutes ago)
* e9ea39b - user : README aggiunto (16 minutes ago)
}}}

Vi ricordate di '''HEAD'''? Adesso punta al commit '''master'''. HEAD quindi e' un puntatore al commit in cui attualmente ci troviamo. Possiamo andare in qualsiasi commit, non solo sugli ultimi dei rispettivi branch, digitando

{{{
git checkout SHA1
}}}

dove {{{SHA1}}} e' il codice SHA1 del commit.

Adesso ci troviamo sul branch master. Supponiamo di voler aggiungere una cartella di documentazione:

{{{
mkdir doc
echo '== Changelog =='$'\n'$'\n''First release' > doc/Changelog
cat doc/Changelog
== Changelog ==

First release
}}}

Committiamo adesso la modifica e vediamo lo stato del nostro repository.

{{{
git add doc/
git commit -a -m "Aggiunta cartella documentazione."
[master e4064d8] Aggiunta cartella documentazione.
 1 file changed, 3 insertions(+)
 create mode 100644 doc/Changelog
git lg
* e4064d8 (HEAD, master) - user : Aggiunta cartella documentazione. (17 seconds ago)
| * d8b610a (gp-1) - user : Modificato codice per issue gp-1. (5 minutes ago)
|/
* 1412239 - user : Aggiunta data in stampa. (9 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (11 minutes ago)
* e9ea39b - user : README aggiunto (19 minutes ago)
}}}

Interessante. Possiamo notare come adesso i nostri due branch stiano prendendo strade parallele. Sono partiti da un punto in comune, ma ognuno sta avendo modifiche indipendenti.

== Merge ==

Adesso siamo nella situazione in cui:

 * Il branch '''master''' ha aggiunto la documentazione.
 * Il branch '''gp-1''' ha implementato una feature.

Vogliamo adesso effettuare un '''merge'''. Cioe' vogliamo introdurre le modifiche fatte in un branch in un altro branch.

In particolare, vogliamo che nel branch '''master''' vengano introdotte le modifiche aggiunte nel branch '''gp-1'''. Vogliamo quindi effettuare il merge di '''gp-1''' su '''master'''.

Il comando per effettuare i merge in Git e', molto fantasiosamente, {{{merge}}}. Il modo piu' diretto di utilizzare il comando e'

{{{
git merge altro_branch
}}}

Questo comando prende il branch '''altro_branch''' e introduce le sue modifiche sul branch corrente. Noi vogliamo effettuare il merge di '''gp-1''' su '''master'''. Quindi prima assicuriamoci di essere sul branch '''master''' (effettuiamo il checkout in caso non lo fossimo):

{{{
git branch
  gp-1
* master
}}}

Dopodiche', effettuamo il merge:

{{{
git merge gp-1
Merge made by the 'recursive' strategy.
 src/main.cpp | 1 +
 1 file changed, 1 insertion(+)
}}}

Che e' successo? Andiamo a vedere il log:

{{{
git lg
* f61b2e2 (HEAD, master) - user : Merge branch 'gp-1' (9 seconds ago)
|\
| * d8b610a (gp-1) - user : Modificato codice per issue gp-1. (7 minutes ago)
* | e4064d8 - user : Aggiunta cartella documentazione. (3 minutes ago)
|/
* 1412239 - user : Aggiunta data in stampa. (11 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (14 minutes ago)
* e9ea39b - user : README aggiunto (21 minutes ago)
}}}

Sono successe cose interessanti: come si puo' vedere, nel branch master e' stato creato un nuovo commit, che e' il commit di merge. Il suo commento dice che e' stato effettuato il merge del branch '''gp-1'''. Questo significa che le modifiche che abbiamo apportato su questo branch sono state riportate sul branch corrente ('''master'''). Ci troviamo ancora nel branch master:

{{{
git branch
  gp-1
* master
}}}

Ma possiamo vedere che sono state include le modifiche del secondo branch:

{{{
cat src/main.cpp
#include <iostream>
int main() {
    std::cout << "Thu Dec 4 14:48:20 CET 2014: Benvenuti su Git!" << std::endl;
    std::cout << "Issue gp-1 implementata" << std::endl;
    return 0;
}
make clean && make && bin/main
rm -fr bin/ obj/
./src/main.cpp
mkdir bin
Thu Dec 4 14:48:20 CET 2014: Benvenuti su Git!
Issue gp-1 implementata
}}}

Abbiamo quindi creato un branch secondario, abbiamo applicato una issue in questo branch, e poi abbiamo riportato sul branch principale le modifiche.

E' importante notare che quello che e' stato appena fatto non e' un mero esercizio. E' il modo standard in cui si lavora in Git con progetti seri. Di solito i passi da effettuare sono i seguenti:

 1. Si decide la issue da aggiungere/rimuovere/modificare.
 1. Dal branch principale (quale sia dipende dalla politica di gestione) si crea un nuovo branch, con un nome identificativo della modifica (puo' essere il codice associato a Bugzilla, ad esempio. Il nome '''gp-1''' e' un esempio di codice, infatti).
 1. Si lavora alla issue su quel branch.
 1. Quando si completa, si effettua il merge sul branch principale in modo che il progetto includa le modifiche e siano rese pubblicamente disponibili.

Questo modo di lavorare permette di fare tutti i casini che si vogliono sul proprio branch, senza andare ad inficiare quello principale che ne rimane immune fino a quando la issue non e' completamente testata e funzionante (si spera).

Se nel frattempo arriva un'altra issue piu' urgente un bug da risolvere o quant altro, si crea semplicemente un altro branch da quello principale, come fatto in precedenza, e si lavora su quello. I branch sono indipendenti fra di loro. Questo assicura grande flessibilita' nella gestione del progetto.

== Repository remoti ==

Quello che abbiamo fatto finora permette di lavorare da soli, ma nella maggior parte dei casi occorre che diverse persone possano accedere al repository, lavorare su di esso e mettere le modifiche.

Simuliamo in locale questo comportamento. Occorre creare una nuova cartella dove vogliamo creare il nuovo repository:

{{{
mkdir /home/user/gitproject_2
cd /home/user/gitproject_2
}}}

Adesso possiamo procedere in due modi:

=== Clonazione repository ===

Possiamo clonare direttamente un repository, avendone quindi una copia locale:

{{{
git clone /home/user/gitproject .
Cloning into '.'...
done.
}}}

Il comando {{{clone}}} ha permesso di prendere il repository remoto (nel nostro caso quello precedente, ma potrebbe essere un repository su web o su un server), e l'abbiamo copiato nella cartella corrente (.). Infatti possiamo vedere il log del repository:

{{{
git lg
* f61b2e2 (HEAD, origin/master, origin/HEAD, master) - user : Merge branch 'gp-1' (4 minutes ago)
|\
| * d8b610a (origin/gp-1) - user : Modificato codice per issue gp-1. (11 minutes ago)
* | e4064d8 - user : Aggiunta cartella documentazione. (6 minutes ago)
|/
* 1412239 - user : Aggiunta data in stampa. (15 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (18 minutes ago)
* e9ea39b - user : README aggiunto (25 minutes ago)

}}}

Il log e' '''quasi''' uguale a quello originale. Si nota la presenza di altri branch:

 * origin/master
 * origin/HEAD
 * origin/gp-1

Questi sono i branch del repository remoto, che sono materialmente quelli creati nel repository originale. '''origin''' e' il nome di default che Git da ad un repository remoto, che possono essere elencati col comando '''remote'''

{{{
git remote
origin
}}}

Questo e' l'elenco dei repository remoti:

 * E' solamente uno perche' al momento abbiamo clonato uno gia' esistente
 * Si, Git puo' avere diversi repository remoti associato allo stesso repository locale. Questo permette molta flessibilita', ma al momento ignoriamo questo aspetto.
 
Abbiamo invece solamente un branch locale, '''master''', sincronizzato con il master remoto (piu' precisamente nel punto in cui punta HEAD remoto):

{{{
git branch
* master
}}}

=== Aggiunta manuale remote ===

Il secondo metodo consiste nell'aggiungere manualmente il repository remoto a quello attuale.

Creiamo quindi un repository vuoto:

{{{
mkdir /home/user/gitproject_3
cd /home/user/gitproject_3
git init
Initialized empty Git repository in /home/user/gitproject_3/.git/
}}}

Se vediamo la lista dei repository remoti, ovviamente e' vuota:

{{{
git remote
}}}

Aggiungiamo quindi il repository remoto, tramite il comando '''remote add''':

{{{
git remote add origin /home/user/gitproject
git remote
origin
}}}

Proviamo a vedere il log:

{{{
git lg
fatal: bad default revision 'HEAD'
}}}

Il repository e' vuoto!

{{{
ls -altr
drwxrwxr-x 22 user group 4096 Dec 4 15:06 ..
drwxrwxr-x 3 user group 4096 Dec 4 15:06 .
drwxrwxr-x 7 user group 4096 Dec 4 15:07 .git
}}}

Questo perche' e' stato aggiunto il repository remoto, ma non abbiamo ancora fatto la sincronizzazione. Per poter sincronizzare il repository locale con quello remoto, occorre scaricare le modifiche. Questo viene fatto in due modi.

=== Fetch e Pull ===

Si vuole prendere il contenuto del repository remoto e sincronizzare quello locale, in maniera da poter prendere le modifiche remote. Il comando {{{fetch}}} permette di scaricare in locale le modifiche remote, ma '''NON''' di applicarle.

{{{
git fetch origin
remote: Counting objects: 23, done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 23 (delta 6), reused 0 (delta 0)
Unpacking objects: 100% (23/23), done.
From /home/user/gitproject
 * [new branch] gp-1 -> origin/gp-1
 * [new branch] master -> origin/master
}}}

Abbiamo scaricato le modifiche remote, ma se guardiamo il contenuto della cartella, risulta essere ancora vuota:

{{{
ls -altr
drwxrwxr-x 22 user group 4096 Dec 4 15:06 ..
drwxrwxr-x 3 user group 4096 Dec 4 15:06 .
drwxrwxr-x 7 user group 4096 Dec 4 15:09 .git
}}}

Questo perche' abbiamo scaricato le modifiche (che stanno dentro .git) ma non abbiamo ancora sincronizzato il tutto. Dal log possiamo vedere meglio quello che e' successo:

{{{
git lg
* f61b2e2 (origin/master) - user : Merge branch 'gp-1' (10 minutes ago)
|\
| * d8b610a (origin/gp-1) - user : Modificato codice per issue gp-1. (17 minutes ago)
* | e4064d8 - user : Aggiunta cartella documentazione. (12 minutes ago)
|/
* 1412239 - user : Aggiunta data in stampa. (21 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (23 minutes ago)
* e9ea39b - user : README aggiunto (31 minutes ago)
}}}

Come possiamo vedere, ci sono i repository remoti, ma non quello locale su cui ci troviamo. E, dato che in quello locale non abbiamo ancora fatto niente, la nostra directory e' vuota.

Effettuamo allora il merge del branch locale con quello remoto, come abbiamo visto precedentemente, e vediamo che succede:

{{{
git merge origin/master
git lg
* f61b2e2 (HEAD, origin/master, master) - user : Merge branch 'gp-1' (11 minutes ago)
|\
| * d8b610a (origin/gp-1) - user : Modificato codice per issue gp-1. (18 minutes ago)
* | e4064d8 - user : Aggiunta cartella documentazione. (13 minutes ago)
|/
* 1412239 - user : Aggiunta data in stampa. (22 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (24 minutes ago)
* e9ea39b - user : README aggiunto (32 minutes ago)
}}}

Come possiamo vedere, adesso i due branch sono allineati (puntano allo stesso commit). D'altronde, se vediamo il contenuto della cartella, possiamo vedere che e' aggiornato:

{{{
ls -altr
total 32
drwxrwxr-x 22 user group 4096 Dec 4 15:06 ..
drwxrwxr-x 2 user group 4096 Dec 4 15:11 src
-rw-rw-r-- 1 user group 16 Dec 4 15:11 README
-rw-rw-r-- 1 user group 258 Dec 4 15:11 Makefile
-rw-rw-r-- 1 user group 10 Dec 4 15:11 .gitignore
drwxrwxr-x 8 user group 4096 Dec 4 15:11 .git
drwxrwxr-x 2 user group 4096 Dec 4 15:11 doc
drwxrwxr-x 5 user group 4096 Dec 4 15:11 .
}}}

Potevamo eseguire il tutto con un unico comando, {{{pull}}}. Questo racchiude in se' il {{{fetch}}} ed il {{{merge}}}, ed e' il comando solitamente utilizzato in questi casi. Ricreiamo il repository e vediamo che succede col {{{pull}}} (in una nuova cartella vuota). Il comando {{{pull}}} richiede il nome del repository remoto e il branch di cui fare l'update:

{{{
mkdir /home/user/gitproject_4
cd /home/user/gitproject_4
git init
Initialized empty Git repository in /home/user/gitproject_4/.git/
git remote add origin /home/user/gitproject
git pull origin master
remote: Counting objects: 23, done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 23 (delta 6), reused 0 (delta 0)
Unpacking objects: 100% (23/23), done.
From /home/user/gitproject
 * branch master -> FETCH_HEAD
git lg
* f61b2e2 (HEAD, origin/master, master) - user : Merge branch 'gp-1' (15 minutes ago)
|\
| * d8b610a - user : Modificato codice per issue gp-1. (22 minutes ago)
* | e4064d8 - user : Aggiunta cartella documentazione. (17 minutes ago)
|/
* 1412239 - user : Aggiunta data in stampa. (26 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (28 minutes ago)
* e9ea39b - user : README aggiunto (36 minutes ago)
}}}

Abbiamo quindi creato un repository, e sincronizzato il suo contenuto con un repository remoto.

== Pubblicazione modifiche locali ==

Possiamo a questo punto effettuare delle modifiche nel nostro nuovo repository:

{{{
sed -i '4 a \\tstd::cout << "Modifica da un altro repository" << std::endl;' src/main.cpp
cat src/main.cpp
#include <iostream>
int main() {
    std::cout << "Thu Dec 4 14:48:20 CET 2014: Benvenuti su Git!" << std::endl;
    std::cout << "Issue gp-1 implementata" << std::endl;
    std::cout << "Modifica da un altro repository" << std::endl;
    return 0;
}
git commit -a -m "Aggiunta riga di output."
[master 0ed9a58] Aggiunta riga di output.
 1 file changed, 1 insertion(+)
git lg
* 0ed9a58 (HEAD, master) - user : Aggiunta riga di output. (15 seconds ago)
* f61b2e2 (origin/master) - user : Merge branch 'gp-1' (23 minutes ago)
|\
| * d8b610a (origin/gp-1) - user : Modificato codice per issue gp-1. (30 minutes ago)
* | e4064d8 - user : Aggiunta cartella documentazione. (26 minutes ago)
|/
* 1412239 - user : Aggiunta data in stampa. (34 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (37 minutes ago)
* e9ea39b - user : README aggiunto (44 minutes ago)
}}}

Abbiamo creato un nuovo commit, e dal log possiamo vedere che i due branch master, quello locale e quello remoto, non sono piu' (ovviamente) allineati. Per inviare al repository remoto le mostre modifiche, occorre utilizzare il comando {{{push}}}, specificando sempre il repository remoto e i branch da voler sincronizzare:

{{{
git push origin master
Counting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 395 bytes, done.
Total 4 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (4/4), done.
To /home/user/gitproject
   f61b2e2..0ed9a58 master -> master
}}}


A questo punto abbiamo mandato nel repository remoto le nostre modifiche, in modo tale che gli altri utenti del repository, una volta sincronizzati con quello remoto, possano percepire le nostre modifiche.

{{{{#!wiki note
'''Errore push'''

A questo punto si potrebbe ottenere il seguente messaggio di errore:

{{{
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To ../gitproject/
 ! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to '/home/user/gitproject'
}}}

Questo perche' il nostro repository remoto non e' di tipo '''bare'''. Al momento ignoriamo questo avviso e, per poter effettuare il push, digitare il seguente comando:

{{{
git config --global receive.denyCurrentBranch ignore
}}}

E poi rieseguire il push. Quando non e' piu' necessario settare lo stesso valore a '''refuse''':

{{{
git config --global receive.denyCurrentBranch refuse
}}}

per ripristinare lo stato originale.
}}}}

Per essere sicuri di aver fatto tutto correttamente, andiamo ad uno dei repository creato in precedenza:

{{{
cd /home/user/gitproject_3
}}}

Ed effettuiamo il pull per risincronizzarci col server remoto, che a questo punto avra' le nostre modifiche:

{{{
git pull origin master
From /home/user/gitproject
 * branch master -> FETCH_HEAD
Updating f61b2e2..0ed9a58
Fast-forward
 src/main.cpp | 1 +
 1 file changed, 1 insertion(+)
git lg
* 0ed9a58 (HEAD, origin/master, master) - user : Aggiunta riga di output. (4 minutes ago)
* f61b2e2 - user : Merge branch 'gp-1' (27 minutes ago)
|\
| * d8b610a (origin/gp-1) - user : Modificato codice per issue gp-1. (34 minutes ago)
* | e4064d8 - user : Aggiunta cartella documentazione. (30 minutes ago)
|/
* 1412239 - user : Aggiunta data in stampa. (38 minutes ago)
* e1e5a46 - user : Aggiunti sorgenti e Makefile (41 minutes ago)
* e9ea39b - user : README aggiunto (48 minutes ago)
}}}

= Conclusioni =

In questa breve guida sono stati esaminate le seguenti operationi:

 * Creazione repository vuoto
 * Clonazione repository
 * Commit di modifiche
 * Creazione branch
 * Merge di branch
 * Sincronizzazione con repository remoti.
 
Git permette di fare molte altre cose. La guida ufficiale che potete trovare sul [[http://git-scm.com/doc|sito ufficiale]]
e' molto esaustiva. Ovviamente e' possibile modificare il wiki per arricchirlo e correggerlo.
 * [[http://git-scm.com/|Sito ufficiale del progetto]]
 * [[http://git-scm.com/doc|Documentazione ufficiale del progetto]]
 * [[Programmazione|Portale sulla programmazione]]
Linea 647: Linea 161:
CategoryProgrammazione CategoryHomepage CategoryProgrammazione


Guida verificata con Ubuntu: 22.04 24.04

Problemi in questa pagina? Segnalali in questa discussione

Introduzione

Git è un sistema di controllo di versione distribuito (DVCS - Distributed Version Control System) utilizzabile da riga di comando. Gli aspetti principali riguardano:

  • tracciare la storia di un progetto e poter lavorare con le versioni precedenti;
  • permettere la collaborazione di più persone allo stesso progetto;
  • organizzare e semplificare l'andamento del progetto.

A differenza di programmi come CVS o Subversion, e in modo simile a Mercurial o Baazar, Git è caratterizzato da una gestione localizzata, ovvero è utilizzabile con repository locali invece che esclusivamente remoti. Sistemi come Subversion adottano un repository centrale (server o servizio web) in cui risiede il progetto. In tali sistemi, la sincronizzazione del lavoro e il salvataggio delle modifiche (commit) avvengono direttamente sul repository centralizzato.

Ogni directory di lavoro è un repository autosufficiente. Operazioni come commit, consultazione dei log e molte altre azioni vengono eseguite localmente, senza necessità di un server esterno. La sincronizzazione con altri repository (server centrale, altri PC in rete, ecc.) avviene solo quando necessario. Ciò garantisce maggiore flessibilità e velocità d'esecuzione.

Se si utilizza Visual Studio Code per programmare, Git è integrato nativamente.

Installazione

Sebbene l'uso del terminale sia il metodo più diretto e completo

Installare Git, digitare in un terminale il seguente comando:

sudo apt install git

Interfaccia grafica

Git include due strumenti storici ad interfaccia grafica basati su Tcl/Tk. Sono essenziali ma molto leggeri e funzionali, per agevolare la visualizzazione dei branch e la gestione dei commit:

Installare i pacchetti:

  • gitk: Specializzato nella visualizzazione della cronologia e dei branch.

  • git-gui: Focalizzato sulla creazione dei commit, la gestione dell'area di staging e le operazioni di merge semplici.

Essendo leggeri e funzionali gitk e git-gui richiedono l'avvio dal terminale all'interno della cartella del progetto, digitando i comandi:

gitk

o

git-gui

Ottimizzazione in GNOME

Per l'ambiente desktop GNOME Gitg offre una visualizzazione moderna e pulita dei commit e permette di gestire le operazioni comuni.

Installare il pacchetto gitg.

Configurazione base

Dopo l'installazione è necessario definire l'identità dell'utente per firmare correttamente i commit.

Identificazione utente nei progetti

Impostare il nome utente e l'indirizzo e-mail da utilizzare globalmente per l'identificazione nei progetti Git, digitare nel terminale questi comandi:

git config --global user.name "NOME_UTENTE"
git config --global user.email INDIRIZZO_E-MAIL

sostituendo le diciture NOME_UTENTE e INDIRIZZO_E-MAIL con i propri dati. Esempio per l'utente Mario Rossi:

git config --global user.name "Mario Rossi"
git config --global user.email mario.rossi@mail.com

Le configurazioni globali vengono salvate nel file nascosto .gitconfig nella propria directory Home. Per impostare dati specifici solo per un determinato repository, è sufficiente omettere l'opzione --global mentre ci si trova all'interno della cartella del progetto.

Impostazione alias lg

Il monitoraggio dell'evoluzione del progetto avviene tramite la consultazione dello storico dei commit. Git fornisce il comando nativo git log, tuttavia, per facilitare la lettura dei rami e delle modifiche, è prassi comune impostare un alias lg che fornisca una rappresentazione grafica, colorata e sintetica, al fine di migliorarne la leggibilità dei rami.

Operazione da eseguire una sola volta.

Digitare nel terminale il seguente comando:

git config --global alias.lg "log --pretty=format:'%C(yellow)%h%Cred%d%Creset - %C(cyan)%an %Creset: %s %Cgreen(%cr)' --decorate --graph --all --abbrev-commit"

Visualizzazione della cronologia

Per visualizzare la cronologia, l'andamento dei rami in qualsiasi repository del sistema una sola volta configurato l'alias lg, digitare nel terminale il seguente comando:

git lg

Altrimenti per visualizzare la cronologia testuale semplice, digitare nel terminale il comando:

git log

Creazione repository

Per creare un nuovo progetto o per importare (clonare) un progetto esistente, vengono descritte di seguito le procedure.

  1. Creare la directory gitproject nella propria cartella Home, digitare nel terminale i seguenti comandi:

     mkdir ~/gitproject
  2. Spostarsi all'interno della cartella creata:

     cd ~/gitproject
  3. Per inizializzare un repository vuoto, digitare:

     git init

    Verrà creata la cartella nascosta .git contenente l'intera cronologia e i dati di controllo e restituito un messaggio simile al seguente:

     Inizializzato un repository Git in /home/mario/gitproject/.git/

Si ricorda che tutte le operazioni di gestione del repository (commit, visualizzazione cronologia, gestione branch, ecc.) devono essere eseguite posizionandosi all'interno della directory del progetto (ad esempio tramite il comando cd ~/gitproject). In questo modo Git può accedere alla sottocartella nascosta .git necessaria per il corretto funzionamento dei comandi.

Clonazione repository

  • Per scaricare un progetto già esistente su di un server, il comando da eseguire è:

     git clone PERCORSO/PROGETTO

    Verrà creata nella propria Home una cartella col nome del progetto in cui saranno copiati i contenuti.

  • Se invece si preferisce clonare il repository in una cartella specifica, basta aggiungere il percorso al comando:

     git clone PERCORSO/PROGETTO PERCORSO/LOCALE

Commit

Attraverso il commit è possibile aggiungere, rimuovere e modificare i file del repository. Consultare la seguente pagina.

Branching

Git permette una gestione avanzata dei branch (rami di sviluppo). Consultare la seguente pagina.

Repository remoti

Tramite gli strumenti fetch, pull e push è possibile sincronizzare il lavoro tra diversi utenti. Consultare la seguente pagina.

Risoluzioni problemi

'lg' is not a git command

Se si prova a digitare git lg, Git restituisce il seguente errore:

git: 'lg' is not a git command. See 'git --help'

Il comando git lg non esiste nativamente in Git funziona solo se è stato creato l'alias corrispondente.

Ulteriori risorse


CategoryProgrammazione