Installer et configurer un serveur GIT sous Linux

Cet article fait partie d’une série d’articles sur GIT.
Mise à jour : 6 juin 2017

Dans cet article, j’explique comment installer un « serveur GIT » ie un dépôt GIT centralisé  sur une machine Linux équipée de l’OS Debian.
Ces explications devraient être très facilement transposables sur d’autres OS Linux, dont bien évidement Ubuntu.

Prérequis

  • Disposer d’une machine Linux « le serveur », qui comme tout serveur digne de ce nom, est fiable au niveau :
    • Système d’exploitation : Linux (eg Debian) version stable, fréquemment mise à jour (au moins en ce qui concerne les mises à jour critiques et de sécurité) ;
    • Stockage matériel : disques dur en RAID (pour pallier à une panne matérielle, même avec des disques SSD !) ;
    • Electrique : un onduleur correctement configuré (qui permet d’éteindre proprement le système en cas de coupure électrique prolongée, notamment pour épargner son système RAID) ;
    • Sauvegarde : système efficace et robuste ;
    • Connexion Internet : évitez le 56k … ;
    • Sécurité des accès distants : un firewall correctement configuré (iptables, fail2ban, …).
  • Vous devez bien entendu avoir accès à cette machine :
    • En local mais surtout à distance (SSH) ;
    • Avec des droits administrateur (« root », ou au minimum être membre du groupe « sudo »).
  • Pour l’accès aux dépôts GIT de ce serveur depuis les clients GIT :
    • Un serveur SSH fonctionnel et correctement configuré (sécurisé) ;
      et/ou
    • Un serveur HTTP(S) fonctionnel et correctement configuré (sécurisé).

Installer le paquet GIT

C’est l’étape la plus simple. Seul le paquet « git-core » est nécessaire.

# sur le serveur
$ sudo aptitude install git-core

Créer un utilisateur (et un groupe) GIT

Même si l’on peut tout à fait se passer de créer un utilisateur (et donc un groupe) git, cette solution à de nombreux avantages, et vous comprendrez pourquoi par la suite.

# sur le serveur
$ sudo adduser git
Ajout de l'utilisateur git ...
Ajout du nouveau groupe git ...
Ajout du nouvel utilisateur git avec le groupe git ...
Création du répertoire personnel /home/git ...
Copie des fichiers depuis /etc/skel ...
Entrez le nouveau mot de passe UNIX : ******
Retapez le nouveau mot de passe UNIX : ******
passwd: le mot de passe a été mis à jour avec succès

A présent, sauf mention contraire, nous travaillerons sous le login git dans son /home :

# sur le serveur
$ su git # on change d'utilisateur pour git
Mot de passe : ******
git@serveur:/home/user$ cd # on va dans le home de l'utilisateur git
git@serveur:~$ pwd # on vérifie que l'on y est bien
/home/git

Créer une architecture de dossiers pour les dépôts

(dans un premier temps, suivez ces instructions, vous bidouillerez plus tard si le coeur vous en dit)

Je vous conseille  :

  • De stocker les dépôts dans un dossier racine nommé repositories situé à la racine du /home de l’utilisateur git : /home/git/repositories
# sur le serveur
git@serveur:~$ mkdir repositories
  • De créer dès le début une hiérarchie de dossiers pour organiser les différents dépôts. Prenez une minute pour réfléchir à celle-ci. Par exemple :
# sur le serveur
git@serveur:~$ cd repositories/
git@serveur:~/repositories$ mkdir perso pro tests users
git@serveur:~/repositories$ tree ../repositories/
../repositories/
├── perso
├── pro
├── tests
└── users
  • De créer un lien symbolique à la racine du serveur, nommé /git, et qui pointe vers /home/git/repositories  (il faut être root pour cela) :
# sur le serveur, en root (ou avec sudo)
root@serveur:~$ ln -s /home/git/repositories/ /git

Créer un nouveau dépôt

Concrètement, un dépôt GIT côté serveur est un dossier, nommé par convention my_repository.git, et situé dans un des sous-dossiers créés précédemment.

Plusieurs solutions pour créer un dépôt GIT sur le serveur :

  • La solution la plus simple et rapide : créer simplement un dépôt vide sur le serveur. Ensuite, en local, après avoir fait un clone  de ce dépôt vide, vous y ajouterez au fur et à mesure vos nouveaux fichiers. Après (un ou plusieurs) commit(s) en local, un push enverra votre travail (les différentes versions commitées) vers le serveur.
    Attention ! Si vous possédez déjà un dépôt GIT en local, avec  un ensemble de révisions (ie de commits), vous pouvez copier/coller vos fichiers (tous sauf le dossier .git) dans le dossier de votre nouveau dépôt cloné du dépôt initialement vide du serveur, puis les ajouter (add), les commiter et les pusher. Vous perdrez toutefois toutes les révisions antérieures ! Il est dans ce cas préférable d’utiliser la solution suivante.
  • La solution d’Envoyer un dépôt existant sur le serveur est certainement la plus utile, car elle vous permet d’envoyer sur le serveur un dépôt existant (à priori en local) vers le serveur, en conservant l’ensemble des révisions. Après tout, GIT est fait pour çà !

   Créer simplement un dépôt vide

  • Pour créer un dépôt nommé my_test_repo.git, créons tout d’abord un dossier nommé my_test_repo.git  dans le dossier repositories/tests/  :
# sur le serveur
git@serveur:~$ cd repositories/tests
git@serveur:~/repositories/tests$ mkdir my_test_repo.git
  • A présent, initialisons ce dépôt :
# sur le serveur
git@serveur:~/repositories/tests$ cd my_test_repo.git
git@serveur:~/repositories/tests/my_test_repo.git$ git init --bare --shared
Dépôt Git partagé vide initialisé dans /home/git/repositories/tests/my_test_repo.git/
  • Explications :
    • git init est la commande d’initialisation d’un dépôt GIT qui est utilisée en local (sur un client) et qui ne doit pas être utilisée seule pour initialiser un dépôt sur le serveur ;
    • git init –bare permet d’initialiser un dépôt GIT sur le serveur : cela créé un ensemble de fichiers (config, description, HEAD) et de dossiers (branches, looks, info, objects, refs) utiles à GIT ;
    • L’option –shared (facultative) permet de configurer automatiquement les droits des fichiers et dossiers du dépôt en écriture au groupe git, voir ci-dessous.
  • A propos des droits :
    • L’utilisation de –shared créé un dépôt partagé en écriture aux membres du groupe git.
# sur le serveur
git@serveur:~/repositories/tests/my_test_repo.git$ git init --bare --shared
Dépôt Git *partagé* vide initialisé dans /home/git/repositories/tests/my_test_repo.git/

git@serveur:~/repositories/tests/my_test_repo.git$ ls -l
total 32K
drwxrwsr-x 2 git git branches
-rwxrw-r-- 1 git git config
-rw-rw-r-- 1 git git description
-rw-rw-r-- 1 git git HEAD
drwxrwsr-x 2 git git hooks
drwxrwsr-x 2 git git info
drwxrwsr-x 4 git git objects
drwxrwsr-x 4 git git refs
  • Sans cette option, les membres du groupe git ont juste accès en lecture (comme on le verra, c’est plutôt pratique !).
# sur le serveur
git@serveur:~/repositories/tests/my_test_repo.git$ git init --bare
Dépôt Git vide initialisé dans /home/git/repositories/tests/my_test_repo.git/

git@serveur:~/repositories/tests/my_test_repo.git$ ls -l
total 32
drwxr-sr-x 2 git git branches
-rwxr--r-- 1 git git config
-rw-r--r-- 1 git git description
-rw-r--r-- 1 git git HEAD
drwxr-sr-x 2 git git hooks
drwxr-sr-x 2 git git info
drwxr-sr-x 4 git git objects
drwxr-sr-x 4 git git refs

   Créer moins simplement un dépôt vide

Sur le serveur ou sur un client (qu’importe), nous allons créer un dépôt GIT qui ne contient pour l’instant aucun fichier.
Si vous êtes sur le serveur, cette manipulation se fait ailleurs que dans le dossier repositories (ou un de ses sous-dossiers) créé précédemment.

  • Créons un dossier pour le dépôt :
# sur n'importe quelle machine
$ mkdir my_test_repo2
$ cd my_test_repo2/
  • Nous allons à présent initialiser ce dépôt avec GIT (il faut donc que GIT soit installé sur la machine) :
# toujours dans le dossier my_test_repo
$ git init
Dépôt Git vide initialisé dans /blablabla/my_test_repo2/.git/

Dans ce cas, l’option –shared est inutile, car lors de la création de la version bare (ci-dessous), les droits ne sont pas conservés. Nous corrigerons les permissions manuellement plus tard. 

  • Créons à présent  une version bare de notre dépôt my_test_repo2.
    Un bare repository est un dépôt qui ne contient que le nécessaire pour être placé sur le serveur (en l’occurence, qui ne contient pas les fichiers relatifs à la version de travail (ie working directory), mais qui grossièrement ne contient que le contenu du dossier .git à la racine du dépôt initial à envoyer sur le serveur) :
# toujours sur la même machine
$ cd ..

$ git clone --bare my_test_repo2/ my_test_repo2.git 
Clonage dans le dépôt nu 'my_test_repo2.git' 
warning: Vous semblez avoir cloné un dépôt vide.
fait. 

$ ls -l 
my_test_repo2.git #la version 'bare', que l'on va placer sur le serveur 
my_test_repo2 #le dossier qui contient le dépôt que l'on a créé précédemment, et qui ne nous intéresse plus, donc ... 

$ rm -rf my_test_repo2 
  • Déplaçons la version bare du dépôt sur le serveur
# si vous étiez déjà sur le serveur, mv suffit : 
$ mv my_test_repo2.git /home/git/repositories/tests/.

# si vous avez créé la version bare sur une autre machine, on peut par exemple utiliser SCP (transfert de fichier via SSH) pour copier le dossier vers le serveur GIT : 
$ scp -r my_test_repo2.git  git@serveur:repositories/tests/
  • Si besoin, définissez correctement le propriétaire (git) et le groupe (git) des fichiers et dossiers de toute l’arborescence du dépôt :
    Vous devez être root pour faire cela ; dans tous les cas, ne donnez pas les droits root à l’utilisateur git (hors de question d’ajouter l’utilisateur git au groupe sudo !)
# si besoin :
root@serveur:/home/git/repositories/tests& chown -R git my_test_repo2.git/

# si besoin :
root@serveur:/home/git/repositories/tests& chgrp -R git my_test_repo2.git/ 

# si besoin :
root@serveur:/home/git/repositories/tests& chmod 775 my_test_repo2.git/
  • Attentions aux droits des fichiers et dossiers !
    Pour information, voici les droits corrects de chacun des fichiers et dossiers, corrigez les vôtres si besoin :

    • pour un dépôt partagé (comme s’il avait été initialisé avec l’option –shared)
      # Pour un dépôt partagé 
      $ tree -a -p
      .
      ├── [drwxrwsr-x] branches
      ├── [-rwxrw-r--] config
      ├── [-rw-rw-r--] description
      ├── [-rw-rw-r--] HEAD
      ├── [drwxrwsr-x] hooks
      │   ├── [-rwxrwxr-x] applypatch-msg.sample
      │   ├── [-rwxrwxr-x] commit-msg.sample
      │   ├── [-rwxrwxr-x] post-update.sample
      │   ├── [-rwxrwxr-x] pre-applypatch.sample
      │   ├── [-rwxrwxr-x] pre-commit.sample
      │   ├── [-rwxrwxr-x] prepare-commit-msg.sample
      │   ├── [-rwxrwxr-x] pre-push.sample
      │   ├── [-rwxrwxr-x] pre-rebase.sample
      │   └── [-rwxrwxr-x] update.sample
      ├── [drwxrwsr-x] info
      │   └── [-rw-rw-r--] exclude
      ├── [drwxrwsr-x] objects
      │   ├── [drwxrwsr-x] info
      │   └── [drwxrwsr-x] pack
      └── [drwxrwsr-x] refs
       ├── [drwxrwsr-x] heads
       └── [drwxrwsr-x] tags
      9 directories, 13 files
      
    • pour un dépôt non partagé (comme s’il avait été initialisé sans l’option –shared) :
      # Pour un dépôt NON partagé 
      $ tree -a -p
      .
      ├── [drwxr-xr-x] branches
      ├── [-rwxr--r--] config
      ├── [-rw-r--r--] description
      ├── [-rw-r--r--] HEAD
      ├── [drwxr-xr-x] hooks
      │   ├── [-rwxr-xr-x] applypatch-msg.sample
      │   ├── [-rwxr-xr-x] commit-msg.sample
      │   ├── [-rwxr-xr-x] post-update.sample
      │   ├── [-rwxr-xr-x] pre-applypatch.sample
      │   ├── [-rwxr-xr-x] pre-commit.sample
      │   ├── [-rwxr-xr-x] prepare-commit-msg.sample
      │   ├── [-rwxr-xr-x] pre-push.sample
      │   ├── [-rwxr-xr-x] pre-rebase.sample
      │   └── [-rwxr-xr-x] update.sample
      ├── [drwxr-xr-x] info
      │   └── [-rw-r--r--] exclude
      ├── [drwxr-xr-x] objects
      │   ├── [drwxr-xr-x] info
      │   └── [drwxr-xr-x] pack
      └── [drwxr-xr-x] refs
       ├── [drwxr-xr-x] heads
       └── [drwxr-xr-x] tags
      
      9 directories, 13 files
      

    Envoyer un dépôt existant sur le serveur

Vous avez compris comment « Créer moins simplement un dépôt vide » (sous section précédente) ?
Dans ce cas, vous ne devriez pas avoir de mal à envoyer sur votre serveur une version bare de votre dépôt existant !

Récapitulatif :

############
# en local #
############
# Allez à la racine de votre dépôt :
user@local:/chemin_vers/my_work_repo$

# Vérifiez que vous avez comité vos dernières modifications
user@local:/chemin_vers/my_work_repo$ git status
user@local:/chemin_vers/my_work_repo$ git add .
user@local:/chemin_vers/my_work_repo$ git commit -m "dernier commit avant de créer la version bare pour mon serveur"

# Créez la version bare
user@local:/chemin_vers/my_work_repo$ cd ..
user@local:/chemin_vers$ git clone --bare my_work_repo/ my_work_repo.git
Clonage dans le dépôt nu 'my_work_repo.git'
fait.

# Archivez puis supprimez le dépôt que l'on ne va plus utiliser
user@local:/chemin_vers$ zip -r my_work_repo my_work_repo
user@local:/chemin_vers$ rm -rf my_work_repo/

# Copiez la version bare sur le serveur
user@local:/chemin_vers$ scp -r my_work_repo.git git@serveur:repositories/work/

##################
# sur le serveur #
##################
# Allez à la racine de votre dépôt en root : 
root@serveur:/home/git/repositories/work&

# Vérifiez le propriétaire et groupe
# Si besoin :
root@serveur:/git/work& chown -R git my_work_repo.git/
root@serveur:/git/work& chgrp -R git my_work_repo.git/
root@serveur:/git/work& chmod 775 my_work_repo.git/

# Corrigez les droits si besoin (voir dans la section précédente en supra)

Communiquer avec le serveur GIT par SSH

Principe

C’est simple comme bonjour … à condition de maitriser un minimum les questions de connexion SSH et de droits UNIX (utilisateurs, groupes, chmod, …).

Concrètement, un utilisateur l-user d’une machine local et qui possède un compte s-user sur le serveur server pourra :

  • « utiliser GIT » en local pour « interagir » avec le server s’il peut se connecter en SSH au server depuis sa machine local : cela soulève la problématique de la connexion (login, clé SSH, …) ;
  • « lire » avec GIT (en local, depuis le server), c’est à dire faire un git clone ou un git pull (qui reviennent à lire le dépôt du server) s’il a les droits de lecture sur le dépôt (donc aux fichiers et dossiers du dépôt sur le server) ;
  • « écrire » avec GIT (de local, vers le server), c’est à dire faire un git push (qui revient à écrire sur le dépôt du server) s’il a les droits d’écriture sur le dépôt (donc aux fichiers et dossiers du dépôt sur le server).

Cloner un dépôt du serveur

En local, pour cloner un dépôt GIT hébergé sur un serveur, la commande est la suivante :

l-user@local$ git clone s-user@server:/git/work/my_repo.git

La connexion au serveur et la gestion des droits de lecture et d’écriture

Tout d’abord, jetez un coup d’oeil sur ma série d’articles sur SSH.

Les différentes solutions :

  • Utiliser le mot de passe git
    On oublie ! 
    Il y a bien plus élégant et moins risqué. En effet, un utilisateur qui possède (ou vol) le mot de passe de l’utilisateur git sur le server peut le changer, ce qui impacterait tous les utilisateurs. Même si l’on est le seul utilisateur du dépôt, cette solution est contraignante car il faut retaper le mot de passe à chaque pull, push, …
  • Incorporer la clé publique de chaque utilisateur aux authorized_keys du compte git
    Cette solution permet de gérer assez simplement la liste d’utilisateurs (via l’édition du fichier /home/git/.ssh/authorized_keys) mais un utilisateur peut alors avoir accès (en lecture et écriture) à tous les fichiers de git et donc à tous les dépôts, et peut même modifier les authorized_keys.
  • Créer puis utiliser un compte propre à chaque utilisateur sur le serveur
    C’est la solution la plus élégante, sûre et flexible. Il suffit de créer un compte pour chaque utilisateur (r-user) sur le server, puis de gérer ses accès en lecture et/ou écriture aux différents dépôts (donc aux fichiers et dossiers des dépôts). Pour gérer ces droits, plusieurs solutions, dont :

    • Utiliser les groupes et droits UNIX : pour permettre l’accès aux dépôts, il faut ajouter chaque utilisateur (s-user) du server au groupe git, ceux-ci peuvent alors accéder à tous les dépôts en lecture (sauf configuration tordue), et y écrire si les fichiers et dossiers de ces dépôts ont des droits UNIX configurés pour autoriser l’écriture aux membres du groupe git. La limite est évidente : il est impossible de configurer (simplement) des droits propres à chaque utilisateur ;
    • Utiliser les groupes et droits UNIX et chowner les dépôts
      En changeant le propriétaire (commande chown) des fichiers d’un dépôt (donc ne plus utiliser du tout le compte git), il est possible de contourner certaines difficultés. Cette solution est finalement celle d’un mode d’accès privé d’un utilisateur à « ses » dépôts.
    • Utiliser les Access Control Lists (ACL) d’UNIX : c’est « la solution magique », qui dépasse largement le cadre de cet article.

Exemples

Cette section est en cours de rédaction …

Communiquer avec le serveur GIT par HTTP(S)

Cette section est en cours de rédaction …

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *