Outils pour utilisateurs

Outils du site


Panneau latéral

git

GIT

Ah, git… tout est dit, non ?

C'est un bel outil, puissant parait-il, complexe, très complexe, trop complexe ?
Enfin, ça semble plus qu'adéquat pour faire la sauvegarde et le versioning de mes petits projets, alors allons-y !
On trouve pas mal de “super tutos”, des cheat-list, etc… pour savoir comment utiliser git en ligne de commande : j'ai jamais rien compris et nombreux sont ceux qui peuvent témoigner du nombre de jurons que j'ai pu proférer contre git. Alors cette page n'a pas pour vocation d'être un autre de ces tutos, mais elle revient plutôt à l'essence même de ce site : être mon aide mémoire. C'est à dire exposer les commandes dont j'ai besoin et les qques concepts qu'il faut connaître pour les comprendre.
La plupart des explications de cet article viennent de http://git-scm.com/doc

Outils pratiques :

  • gitList, une sorte de visionneuse web du dépôt git (fichiers, historiques des commit…)
  • gogs qui en plus des fonctions de visionneuse rajoute des métadonnées autour du projet (wiki, issue/milestone list..) et une dimension sociale si on code à plusieurs /!\ il faut passer par le protocole https: et non ssh: pour que gogs soit au courant des modifs dans le dépot git
  • gitlab, self-hostable, open source, mais un peu lourd en besoin de ressources, je lui préfère gogs

CONCEPTS

Principes de base

Git est un gestionnaire de version, il sert à conserver la version d'un fichier entre chaque changement, et permet de récupérer à tout moment l'état d'une version antérieure.

Git est décentralisé, ça signifie que chacun des clients possède l'intégralité de l'historique du dépot. Entre autres, on peut avoir plusieurs dépôts distants pour synchroniser son dépot local.

Les 3 états, les 3 zones

Git possède 3 états dans lesquels peuvent être les fichiers :

  • modifié (modified), c'est à dire dans le système de fichier classique (working directory)
  • indexé (staged), c'est à dire dans la zone d'index (staging area)
  • validé (commited), c'est à dire bien au chaud, rangés dans le dossier .git (git directory / git database)

Un fichier doit passer par la case staged avant d'aller dans la case commit.
On va voir par la suite comment fonctionner avec ces états et comment passer de l'un à l'autre.

Comprendre

Commit

Un commit contient un index (liens vers les fichiers), un message de commit, et un lien vers l'ancien commit. Il peut donc y avoir une succession de commit en remonttant de l'un à l'autre.
ça peut paraître obscur ou incomplet (ça l'est surement), mais ces histoires de pointeurs est à approfondir, elles permettent de vraiment comprendre comment git stocke les choses, et comment elles s'articulent entre elles, et donc de bien utiliser git (ce qui est quand même l'objectif).

Stockage des fichiers

Git conserve chaque fichier intégralement. Si entre 2 commit un fichier ne change pas, le fichier n'est pas sauvegardé mais un lien vers le fichier du commit précédent est fait. Cela permet de ne pas consommer trop de place en gardant une vitesse de traitement convenable (contrairement aux autres systèmes qui ne conservent que des delta entre les différentes versions, certes utile pour optimiser l'espace, par contre pas rapide du tout).

Obtenir de l'aide

# Par exemple sur la fonctionnalité config :
git help config

CONFIG

# On peut voir la config avec
git config --list
 
 
## A la première execution de git, il faut règler qques petits aspects de config :
 
# Identité
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
 
# Editeur par défaut
git config --global core.editor vim
 
# Pour ne pas retaper le mot de passé tout le temps :
# enregistre les infos creditential qques minutes
git config --global credential.helper cache

CREER UN DEPOT

# Créer un dépôt git dans un dossier existant :
git init
 
# Cloner un dépôt existant :
git clone https://github.com/libgit2/libgit2 [dossierDestination]
# cloner crée aussi un lien vers le dépôt distant nommé ''origin''
# cloner crée en local une branche appelée ''master'' qui suit ''origin/master''

TENIR UN DEPÔT (en fait une branche) A JOUR

Toutes les commandes qui suivent permettent de tenir à jour la branche actuelle. Voir le paragraphe suivant pour la gestion des branches.

# pour savoir où on en est : 
git status
 
 
# Pour indexer (et suivre) des nouveaux fichiers :
git add FILE_NAME
 
 
# Si on a changé un fichier suivi et qu'on veut sauvegarder son état actuel
# dans la staging area (git status nous donne la commande à utiliser) :
git add FILE_NAME
# NOTE : le fichier sera ensuite gelé tel quel dans la staging area, 
# si on le modifie de nouveau par la suite AVANT un commit, il faudra ré-utiliser 
# la commande ''git add'' pour mettre à jour la staging area avec 
# la nouvelle version du fichier
 
 
# Pour Unstage un fichier qu'on aurait ajouté par erreur avec ''git add file''
# (comme souvent la commande est suggérée par ''git status'' )
git reset HEAD FILE_NAME
# NOTE : le fichier reste modifié dans le working directory, 
# il est juste sorti du stage area (et donc du prochain commit)
 
 
# Pour archiver/valider les modifications présentes dans la staging area
# (et non celles dans le working directory)
git commit
# NOTE : Cela va ouvrir notre éditeur de texte par défaut pour
# qu'on puisse laisser un message décrivant le commit.
 
# Version courte :
git commit -m "bugfix #185 : speed request improved"
 
 
# pour rajouter un truc à un commit qu'on aurait fait trop vite :
git add FICHIER_OUBLIE
git commit --amend
 
 
# Pour enlever des fichiers,
# il faut les enlever de la staging area et faire un commit. 
...
# OU en 1 commande:
git rm FILE_NAME
# NOTE : ''git rm'' supprime aussi le fichier du working directory
 
# permet de ne plus suivre un fichier mais de le laisser dans le working directory
git rm --cached FILE_NAME
 
 
# Pour déplacer des fichiers : 
# de base, git ne suit pas les déplacements effectués via le système de fichier, 
# il faut les lui signaler explicitement, ou utiliser la commande magique :
git mv FILE_FROM FILE_TO
# NOTE : git effectue aussi les actions dans le système de fichier ($> rm FILE_NAME)
 
 
# Pour annuler une modification d'un fichier du working directory, 
# c'est à dire récupérer la version du dernier commit :
# (encore une fois ''git status'' nous suggère la commande)
git checkout -- FILE_NAME
# NOTE : il est préférable de faire un commit dans une nouvelle branche
# puis de récupérer l'ancienne branche que d'écraser ainsi
# un fichier qui serait définitivement perdu !

Astuces

Pour ignorer des fichiers, il faut mettre leur nom dans le fichier .gitignore à la racine du dépôt. Différentes syntaxes (regex ?) peuvent être utilisées comme filtre :

blabla --- A REMPLIR

Tag

# liste des tag (filtrée ou non)
git tag [-l "REGEX"]
 
# créer un tag "léger" sur le dernier commit
# (c'est un simple pointeur vers un commit particulier)
git tag TAG_NAME
 
# Transférer un tag vers un dépôt distant (par défaut, ils sont uniquement locaux)
git push REMOTE_NAME TAG_NAME
 
# faire un checkout sur un tag particulier
git checkout -b BRANCH_NAME TAG_NAME
 
# on peut faire d'autres choses :
# - des tag annotés
# - des tag sur un commit particulier déjà dépassé
# ...

GESTION DES DEPÔTS DISTANTS

La commande git remote permet de lister les dépôts distants, d'en ajouter ou d'en retirer :

# afficher la liste des dépôts distants et leur alias
git remote -v 
 
# ajouter un nouveau dépôt distant 
git remote add REMOTE_NAME URL
 
# pour link un dépot distant avec une branche distante (pour avoir que git push et git pull)
git push -u REMOTE_NAME BRANCH_NAME
 
# enlever un dépot distant
git remote remove REMOTE_NAME
 
# pour inspecter la config (et les branches) d'un dépôt distant
git remote show REMOTE_NAME
 
# pour plus d'info
git help remote
 
 
# récupère les données du dépôts distant
# mais ne bascule pas sur ces données ni n'écrase le working directory
git fetch REMOTE

BRANCHES

Comprendre

Une branche n'est en réalité qu'un pointeur vers un commit.

HEAD fait référence à la branche actuelle, soit au dernier commit de cette branche.

Gestion des branches

# voir les branches (
git branch
git branch [-v]  # avec les messages des derniers commit 
git branch [--merged] [--no-merged]  # filtres
 
 
# créer une branche (donc un pointeur vers le dernier commit de la branche actuelle)
git branch  BRANCH_NAME
 
# basculer sur une autre branche 
# !! ça change le working directory et charge les données de la branche !!
# !! normalement, si ce n'est possible de le faire proprement :
# (aka il y a des modifs non commit), git ne change pas de branche 
git checkout BRANCH_NAME
 
# merge : 
# on se place dans la branche de destination
# on appelle la commande merge avec le nom de la branche à ramener
# cela crée un commit dans la branche de destination et avance les pointeurs commit
git checkout BRANCH_DEST
git merge --no-ff BRANCH_NAME
# => utile : l'option --no-ff
# ne crée pas tous les commit intermédiaires de la branche à finir 
# dans la branche de destination, juste le commit du merge.
# Pratique si on considère qu'une branche sert une fonctionnalité 
# et qu'on veut pas que les autres branches/fonctionnalités parasitent
# la branche de destination
 
# supprimer une branche
git branch -d BRANCH_NAME
 
# git switch et git restore
# Le but de ces 2 commandes est de différencier les 2 activités de `git checkout` 
git switch <branch_name> # can now be used to change branches, as git checkout <branchname> does
git restore <file_path>  # can be used to reset files to certain revisions, as git checkout -- <path_to_file> does

Conflits

Lorsqu'il y a conflit, le merge n'aboutit pas et git annote les fichiers pour resolution manuelle du conflit, il faut ensuite marquer le conflit comme résolu à l'aide d'un git add FILE_NAME

aller plus loin : git mergetool

Branches distantes

Elles sont references sous la forme REMOTE/BRANCH. Elles ne bougent pas sans synchro extérieure (git fetch BRANCH_NAME ← met à jour la database locale de git) Par exemple : master (local)

# Partager son travail avec le monde extérieur
# cela va mettre à jour la branche du depot distant avec la branche de notre dépôt
git push REMOTE_NAME BRANCH_NAME
 
# pour récupérer le travail d'autrui
git fetch AUTRUI
git checkout BRANCH_NAME
git merge AUTRUI/BRANCH_NAME
 
 
# pour supprimer une branche distante
git push REMOTE --delete BRANCH

Branches suivies (tracking)

Ce sont des branches qui ont un lien direct avec une branche d'un depot distant. Ce qui permet d'utiliser git pull.

## creation d'une tracking branche
# tracking de REMOTE/BRANCH depuis la branche actuelle
git branch -u REMOTE/BRANCH 
# OU
# crée master et origin, master suit origin/master
git clone ...
# OU
# créer une branche locale qui track remote/origin, et bascule sur cette branche
git checkout -b BRANCH_NAME REMOTE/BRANCH 
 
 
# voir les branches qui sont suivies
git branch -vv
 
 
# recupère les changements depuis le depot distant 
# mais NE modifie PAS le working directory
git fetch

RACCOURCIS

En vrac, pour toutes les sections :

# créer une branche et basculer vers celle-ci
git checkout -b BRANCH_NAME
# =
git branch BRANCH_NAME
git checkout BRANCH_NAME
 
# récupérer le contenu distant et le mettre dans son working directory
git pull
# =
git fetch
git merge
 
# Si on a foutu le bazar dans le repertoire mais qu'on a pas commit,
# retrouve le répertoire à l'état du dernier commit
git reset --hard HEAD
# Est-ce que ça touche aux fichiers non indexés ? Non

MODELE DE DEVELOPPEMENT

C'est un condensé de cet article, que je trouve bien fait.
En gros :

  • la branche master représente l'état production du projet, c'est sensé tourner en permanence
  • la branche dev contient les nouvelles fonctionnalités, encore à l'état instable. Lorsque l'état est suffisamment stable, le contenu peut etre placé dans la branche master
  • au besoin, des branches temporaires :
    • feature, pour le developpement de fonctionnalités particulières dont l'avenir est incertain ou particulièrement instable,
    • ou hotfix pour ajouter un bugfix à la branche master sans ajouter de nouvelles fonctionnalités (potentiellement instables)

!!! les merge se font avec l'option –no-ff, pour éviter de reporter les commit de développement d'une fonctionnalité particulière dans les branches principales (master, dev)

PROTOCOLES

On peut utiliser plusieurs protocoles selon ce qui est mis à dispo par le serveur pour synchroniser un dépôt git :

# il y a ssh
git clone ssh://ID@HOTE:PATH
# PATH peu être relatif ou absolu
 
# ssh + port spécifique 
git clone ss://ID@HOTE:PORT/ABS_PATH
 
# il y a https (peut être utile pour mettre à jour un service de suiv comme github, gogs ou gitlab
git clone https://URL
git.txt · Dernière modification: 2023/11/08 21:12 de luc