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 1 e 8 (in 7 versioni)
Versione 1 del 05/12/2014 12.51.26
Dimensione: 50
Autore: jeremie2
Commento:
Versione 8 del 06/12/2014 02.20.39
Dimensione: 17454
Autore: jeremie2
Commento:
Le cancellazioni sono segnalate in questo modo. Le aggiunte sono segnalate in questo modo.
Linea 1: Linea 1:
Inserire una descrizione per Programmazione/Git. ## page was renamed from jepessen/Prove/Git
<<BR>>
<<Indice(depth=1)>>
<<Informazioni(forum="http://forum.ubuntu-it.org/viewtopic.php?f=46&t=590616"; rilasci="14.04")>>

= Introduzione =

'''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:

 * 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.

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.

'''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à.

<<Anchor(alias)>>
= Installazione/Configurazione base =

 0. Per installare '''Git''' digitare in un [[AmministrazioneSistema/RigaDiComando|terminale]]:{{{
sudo apt-get install git
}}}
 0. Impostare '''nome utente''' e '''indirizzo e-mail''' che si vogliono utilizzare per identificarsi nei progetti:{{{
git config --global user.name "NOME_UTENTE"
git config --global user.email INDIRIZZO_E-MAIL
}}}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à:{{{
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"
}}}

= Creazione repository =

Viene qui mostrato come creare un '''nuovo progetto''' o come importare (clonare) un '''progetto esistente'''.

== Creazione nuovo repository ==

<<Anchor(creare)>>
 0. Creare la cartella `~/gitproject` nella propria '''Home''' che conterrà il progetto e spostarsi al suo interno:{{{
mkdir gitproject
cd gitproject
}}}
 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).

== 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 [[Programmazione/Git/Commit|seguente pagina]].

= Branching =

'''Git''' prevede una gestione molto efficace dei '''branch''' (rami di sviluppo). Consultare la [[Programmazione/Git/Branch|seguente pagina]].


= 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.

= Ulteriori risorse =

 * [[http://git-scm.com/|Sito ufficiale del progetto]]
 * [[http://git-scm.com/doc|Documentazione ufficiale del progetto]]
 * [[Programmazione|Portale sulla programmazione]]

----
CategoryProgrammazione


Problemi in questa pagina? Segnalali in questa discussione

Introduzione

Git è un CVS (Control Version System). Gli aspetti importanti di un CSV si possono riassumere nel:

  • 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.

Rispetto a programmi come CVS, Subversion ma più similmente a Mercurial, 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.

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à.

Installazione/Configurazione base

  1. Per installare Git digitare in un terminale:

    sudo apt-get install git
  2. Impostare nome utente e indirizzo e-mail che si vogliono utilizzare per identificarsi nei progetti:

    git config --global user.name "NOME_UTENTE"
    git config --global user.email INDIRIZZO_E-MAIL
    avendo cura di soistituire le diciture NOME_UTENTE e INDIRIZZO_E-MAIL col proprio nome utente e indirizzo e-mail.

    È possibile modificare questi dati per un singolo repository omettendo il flag --global.

  3. Consigliato ma non obbligatorio, impostare l'alias lg per una versione personalizzata del comando log al fine di migliorarne la leggibilità:

    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"

Creazione repository

Viene qui mostrato come creare un nuovo progetto o come importare (clonare) un progetto esistente.

Creazione nuovo repository

  1. Creare la cartella ~/gitproject nella propria Home che conterrà il progetto e spostarsi al suo interno:

    mkdir gitproject
    cd gitproject
  2. 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).

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 prevede una gestione molto efficace dei branch (rami di sviluppo). Consultare la seguente pagina.

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.

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 sito ufficiale e' molto esaustiva. Ovviamente e' possibile modificare il wiki per arricchirlo e correggerlo.

Ulteriori risorse


CategoryProgrammazione