Version française
RefCard d'utilisation de Git 2.37.0
Écrit par Ludovic Dussart.
- Présentation
- Principes de fonctionnement
- Cheat Sheet
- Débuter avec un projet
- Configuration minimale
- Ignorer des fichiers (.gitignore)
- Workflow type d'un développement avec Git
- Workflow de branches et conventions
- Conventions de commits
- Plus de commandes
- Enrichir le configuration de Git
- Création de tag
- Fusion de branche
- Rebasage de branche
- Ajout interactif
- Le remisage
- Gestion des conflits
- Reflog (votre filet de secours)
- Utiliser une plateforme de versioning
- Glossaire
- Références
- L'ours
Git est un gestionnaire de version qui enregistre (historise) l'évolution des modifications opérées sur un fichier ou un ensemble de fichiers au fil du temps.
Créé en 2005 (à l'initiative de Linus Torvalds, le créateur de Linux), ce nouveau système offre les promesses suivantes :
- vitesse
- conception simple
- support pour les développements non linéaires (milliers de branches parallèles)
- complètement distribué
- capacité à gérer efficacement des projets d’envergure tels que le noyau Linux (vitesse et compacité des données)
Depuis sa naissance en 2005, Git a évolué et mûri pour être facile à utiliser tout en conservant ses qualités initiales. La communauté l'a très rapidement adopté et c'est aujourd'hui l'outil de référence pour le versioning de fichiers :
Crédits : GitPrime
Pour utiliser Git de manière optimale, il est nécessaire de comprendre comment il fonctionne pour versionner vos fichiers.
Git manipule des objets qui sont identifiés et vérifiés par une chaîne de contrôle unique sur 40 caractères (empreinte SHA-1). Concept très important, cette empreinte est calculée en fonction du contenu du fichier ou de la structure du répertoire considéré.
Une empreinte SHA-1 ressemble à ceci :
24b9da6552252987aa493b52f8696cd6d3b00373
Chaque objet se compose de 3 éléments : un type, une taille et un contenu.
- Le blob
Un blob est utilisé pour stocker les données d’un fichier. Il n’est rien de plus qu’un morceau de données binaires. Il ne fait référence à rien et n’a aucun attribut, même pas un nom de fichier.
La commande
git show
permet d'examiner le contenu d'un blob
- Le tree
Un tree est comme un répertoire — il référence une liste d’autres « tree » et/ou d’autres « blobs » (i.e. fichiers et sous-répertoires). Il permet de reconstituer la hiérarchie des fichiers d'un instantané (commit).
La commande
git ls-tree
permet d'examiner le contenu d'un tree (de manière plus détaillée qu'ungit show
)
- Le commit (instantané)
Un « commit » pointe vers un unique « tree » et le marque afin de représenter le projet à un certain point dans le temps. Il contient des méta-informations à propos de ce point dans le temps, comme une description, un timestamp, l’auteur·trice du contenu depuis le dernier commit, un pointeur vers le (ou les) dernier(s) commit(s), etc.
Notez qu’un « commit » ne contient pas d’information à propos de ce qui a été modifié ; tous les changements sont calculés en comparant les contenus du « tree » référencés dans ce « commit » avec le « tree » associé au(x) parent(s) du « commit ».
La commande
git show
ougit log --pretty=raw
permet d'examiner vos « commits » favoris
Si nous avons un simple projet avec la structure de dossiers/fichiers suivante :
$>tree
.
|-- README
`-- lib
|-- inc
| `-- tricks.rb
`-- mylib.rb
2 directories, 3 files
Elle sera gérée par Git de cette manière :
- Le tag
Le tag permet de poser une étiquette sur un commit. Généralement utilisé pour gérer les releases. Cet objet permet d'étiqueter une version du code source à un instant donné.
Il contient un nom d’objet (simplement nommé « object »), un type d’objet, un nom de tag, le nom de la personne (« taggeur ») qui a créé le tag et un message (qui peut contenir une signature, visible en utilisant git cat-file
)
Contrairement aux autres systèmes, Git ne gère pas et ne stocke pas la liste de fichiers et les modifications effectuées sur chaque fichier dans le temps. Il capture un instantané du contenu de votre espace de travail et enregistre une référence à cet instantané. Pour être efficace, si les fichiers n’ont pas changé, Git ne stocke pas le fichier à nouveau, juste une référence vers le fichier original qu’il a déjà enregistré.
Contrairement aux autres systèmes, l'historisation des changements et les opérations effectuées sur votre espace de travail sont gérées localement. Tout est stocké sur votre disque et constitue votre dépôt local. La publication des modifications sur des serveurs distants s'effectue dans un second temps.
Généralement, Git ne fait qu’ajouter des données. Quand vous réalisez des actions dans Git, la quasi-totalité d’entre elles ne fait qu’ajouter des données dans la base de données de Git. Il est très difficile de faire réaliser au système des actions qui ne soient pas réversibles ou de lui faire effacer des données d’une quelconque manière. Par contre, comme dans la plupart des systèmes de gestion de version, vous pouvez perdre ou corrompre des modifications qui n’ont pas encore été entrées en base ; mais dès que vous avez validé un instantané dans Git, il est très difficile de le perdre, spécialement si en plus vous synchronisez votre base de données locale avec un dépôt distant.
Ce concept est primordial
Git gère trois états dans lesquels les fichiers peuvent résider : modifié, indexé et validé
- Modifié : signifie que vous avez modifié le fichier mais qu’il n’a pas encore été validé en base
- Indexé : signifie que vous avez marqué un fichier modifié dans sa version actuelle pour qu’il fasse partie du prochain instantané (commit) du projet
- Validé : signifie que les données sont stockées en sécurité dans votre base de données locale
Répertoire de travail (WD), zone d’index et répertoire Git.
Crédits : Git-scm
- Le répertoire de travail (nommé WD par la suite) est une extraction unique d’une version du projet. Ces fichiers sont extraits depuis la base de données compressée dans le répertoire Git et placés sur le disque pour pouvoir être utilisés ou modifiés.
- La zone d’index est un simple fichier, généralement situé dans le répertoire Git, qui stocke les informations concernant ce qui fera partie du prochain instantané (commit). On l’appelle aussi des fois la zone de préparation.
- Le répertoire Git est l’endroit où Git stocke les métadonnées et la base de données des objets de votre projet. C’est la partie la plus importante de Git, et c’est ce qui est copié lorsque vous clonez un dépôt depuis une autre source.
L’utilisation standard de Git se déroule en 3 étapes :
- vous modifiez des fichiers dans votre répertoire de travail
- vous indexez les fichiers modifiés, ce qui ajoute des instantanés de ces fichiers dans la zone d’index
- vous validez, ce qui a pour effet de basculer les instantanés des fichiers de l’index dans la base de données du répertoire Git
- Créez une branche pour tout nouveau développement (cf. Workflow de branches et conventions)
- Préfixez le nom de votre branche par un type (cf. Workflow de branches et conventions)
- Un commit = une tâche (cf. Ajout interactif)
- Préférez l'indexation de lignes (hunks) plutôt que de fichiers (cf. Ajout interactif)
- Utilisez les conventions de commits (cf. Conventions de commits)
- Retravaillez votre historique de branche avant de la proposer pour qu'elle soit intégrée (cf. Rebase interactif)
- Ne pas réécrire un historique publié sur une branche distante collaborative
- J'ai besoin de fusionner une
feature branch
surdevelop
: cf. Fusion de branche - J'ai besoin d'étiqueter mon application : cf. Création de tag
- Je ne sais pas par où commencer : cf. Workflow type d'un développement avec Git
- Ma branche n'est pas à jour avec la branche
develop
: cf. Rebasage de branche - Je viens de mettre ma branche à jour et cette dernière a des conflits : cf. Gestion des conflits
- J'ai besoin de réécrire (nettoyer) l'historique de ma branche : cf. Rebasage interactif
- J'ai fait une mauvaise manipulation et j'ai perdu mes modifications : cf. Reflog
- J'ai fini de travailler sur ma tâche et je dois la proposer à mon équipe : cf. Soumettre une demande de merge
git config --global -l
Affiche toutes les configurations globales. Utilisez --local
ou --system
pour changer le scope.
git config --global -e
Permet d'éditer les configurations globales. Utilisez --local
ou --system
pour changer le scope.
git config --global <paramètre> <valeur>
Permet de définir une configuration globale. Utilisez --local
ou --system
pour changer le scope.
git status
Liste toutes les modifications qui n'ont pas encore été commitées.
git diff # WD vs index
git diff --staged # index vs HEAD (last commit)
git diff HEAD # WD & index vs HEAD (last commit)
git diff <sha1-commit1> <sha1-commit2> # commit1 vs commit2
Affiche les différences entre deux références d'objet.
git log
Affiche l'historique de commits de la branche courante. Utilisez les options --oneline --graph
pour plus de lisibilité et --all
pour afficher l'historique de toutes les branches.
git show <optional ref>
Permet de consulter le contenu d'un objet.
git reflog
Affiche l'historique de tout ce qu'il s'est passé sur votre dépôt local. Ajoutez l'option --relative-date
pour ajouter une notion temporelle.
git add --all
git add -A
git add .
Ajoute toutes les modifications de tous les fichiers à l'index pour qu'elles soient prêtes à être commitées.
git add <file>
Ajoute toutes les modifications du fichier à l'index pour qu'elles soient prêtes à être commitées.
git add -p <optional file>
Propose l'ajout des modifications, ligne par ligne d'un ou plusieurs fichiers pour qu'elles soient prêtes à être commitées.
git reset <optional file>
Déplace les modifications d'un ou plusieurs fichiers, de la zone d'index au WD.
git restore <file>
Annule les modifications locales d'un fichier.
git commit -m "<type>(<optional scope>): <commit message>"
Crée un commit des modifications précédemment indexées avec une description simple. Enchainez les -m
pour saisir également body
et footer
.
git commit
Propose un prompt de création d'un message de commit, avec les modifications précédemment indexées.
git commit --amend
Intègre les modifications précédemment indexées dans le dernier commit (HEAD
). Ajoutez l'option --no-edit
pour ne pas modifier le message.
git reset HEAD~<optional amount>
Annule un ou plusieurs commits. Leurs contenus (modifications sur les fichiers) est remis dans le WD.
git branch
Liste l'ensemble des branches locales. Ajoutez l'option --all
pour afficher les branches distantes.
git branch <branch name>
Crée une nouvelle branche (depuis la HEAD
) avec le nom donné. Modifiez le nom d'une branche avec l'option -m <old-name> <new-name>
.
git switch <branch name>
Bascule la HEAD
sur la branche désignée et met à jour le répertoire de travail. Utilisez git switch -
pour basculer sur la référence précédente.
git switch -c <branch name> <optional base-ref>
Crée une nouvelle branche et se positionne dessus. Un second paramètre <base-ref>
initie la branche depuis l'objet ciblé.
git branch -d <branch name>
Supprime la branche spécifiée.
git tag <tagname>
Crée un tag sur le commit de HEAD
.
git push <remote> <tagname>
Publie le tag sur le dépôt distant.
git reset --hard <SHA-1>
Annule tous les commits qui se trouvent après l'identifiant du commit mais ne conserve pas les changements.
git revert <SHA-1>
Rejoue les modifications inverses du commit ciblé et crée un nouveau commit de "revert".
git remote -v
Liste l'ensemble des dépôts distants configurés.
git remote show <remote>
Affiche les détails sur le dépôt distant.
git remote add <remote> <url>
Ajoute un dépôt distant.
git fetch <remote> <branch>
Met à jour l'état d'un dépôt distant dans votre dépôt local (mais ne met pas à jour le WD). Utilisez l'option --all
pour mettre à jour tous les états de tous les dépôts distants.
git merge <branch name>
Fusionne (par le dessus) les commits de la branche spécifiée sur la branche courante.
git rebase <branch name>
Réécrit l'historique de commits de la branche courante en y rejouant, par le dessous, celui de la branche spécifiée.
git pull <remote> <branch>
Met à jour l'état d'un dépôt distant dans votre dépôt local et fusionne les changements dans votre espace de travail (WD).
git push -u <remote> <branch>
Publie les commits de la branche spécifiée sur le dépôt distant (-u
définit le upstream). Utilisez <branch>:<new name>
pour publier la branche sous un nom différent.
git init <nom du projet>
Création d'un nouveau dépôt local (.git/
) avec le nom donné.
git clone <url du dépôt distant>
Clone un dépôt distant avec l'entièreté de son contenu dans votre dépôt local. L'option -b
permet de ne cloner que le contenu d'une branche spécifique.
git config --global user.name "<votre identité>"
Définit le texte qui sera associé aux commits de tous les projets. Pour le configurer localement, retirer le --global
.
git config --global user.email "<votre adresse email>"
Définit l'adresse email qui sera associée aux commits de tous les projets. Pour la configurer localement, retirer le --global
.
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
Définit un alias lg
proposant une vue moins verbeuse et plus exploitable du git log
. Vous pouvez ajouter n'importe quelles autres options à la suite de git lg
.
Git offre un mécanisme pour ignorer des fichiers de votre espace de travail. Les fichiers à ignorer sont généralement des artefacts de build (target
sous Maven, dist
ou build
sous NPM par exemple) et des fichiers générés par la machine qui sont dérivés de votre dépôt de source ou qui ne devraient pas être commités (/node_modules
, /.idea
, le code compilé, etc).
Les éléments renseignés dans le .gitignore
n'apparaitront plus dans le résultat des commandes git status
, git add
, etc.
- Créez un fichier
.gitignore
à la racine de votre projet - Complétez-le avec les patterns de fichiers à ignorer en vous basant sur les modèles de développement. Voici quelques exemples :
**/logs
: le double*
cible tous les répertoires partout dans le dépôt local*.log
: tous les fichiers qui se terminent par.log
!important.log
: le!
permet d'ajouter des exceptions pour forcer la prise en compte de l'élément et invalider la règle généraledebug.log
: par défaut, les modèles correspondent aux fichiers de tout répertoire
- Indexez et commitez votre fichier
.gitignore
Un
.gitignore
global peut être utilisé grâce à la configurationcore.excludesFile
:git config --global core.excludesFile ~/.gitignore
Si vous souhaitez ignorer un fichier que vous avez commité par le passé, vous devrez supprimer le fichier de votre dépôt avant d'ajouter une règle .gitignore
pour ce dernier. Si vous utilisez l'option --cached
avec git rm
, le fichier sera supprimé de votre dépôt, mais demeurera dans votre répertoire de travail en tant que fichier ignoré.
echo debug.log >> .gitignore
git rm debug.log
git commit -m "chore(.gitignore): Start ignoring debug.log"
Ce chapitre a pour objectif de vous guider pas à pas dans vos usages quotidiens avec Git.
- Pour initier ou récupérer un projet : Débuter avec un projet
- Des configurations minimales Git doivent être effectuées : Configurations de Git
Utilisez les workflows et les conventions de nommage de branches détaillées dans le chapitre Workflow de branches et conventions
-
Synchronisez la branche initiale avec la version du dépôt distant :
git pull origin <référence à l'instantané de départ>
Exemple :
git pull origin develop
-
Créez votre nouvelle branche depuis un instantané (généralement une autre branche) :
git switch -c <nom de votre branche> <référence à l'instantané de départ>
Exemples :
git switch -c <type>/<branch description> develop
git switch -c <type>/<branch description> 38a1303
git switch -c <type>/<branch description> 1.0.0
- Modifiez vos fichiers
- Ajoutez vos modifications à l'index
- Pour tous les fichiers (non recommandé) :
git add .
ougit add --all
- Fichier par fichier (mieux) :
git add <nom du fichier>
- Ligne par ligne (hunk par hunk) (idéal) :
git add -p
pour l'ensemble des fichiers,git add -p <nom du fichier>
de manière unitaire (consultez le chapitre sur l'ajout interactif)
- Pour tous les fichiers (non recommandé) :
- Contrôlez l'état de votre espace de travail (WD)
- Pour visionner les modifications trackées (indéxées), ou non :
git status
- Pour comparer les différences entre vos modifications
- Entre votre espace de travail et l'index :
git diff
- Entre l'index et la
HEAD
:git diff --staged
- Entre votre espace de travail + l'index et la
HEAD
:git diff HEAD
- Entre votre espace de travail et l'index :
- Pour visionner les modifications trackées (indéxées), ou non :
- Annulez l'ajout de modifications si besoin
- Pour annuler des ajouts à l'index (repasser vos modifications dans le WD) :
git reset
- Pour annuler des ajouts à l'index (repasser vos modifications dans le WD) :
- Créez un instantané (commit) contenant vos modifications dans l'index :
git commit
- Des conventions de commits doivent être appliquées. Se référer au chapitre Conventions de commits
- Pour créer un message de commit sur une seule ligne :
git commit -m "<type>(<optional scope>): <votre message sur 50 chars. max>"
- Pour entrer dans le mode édition (et pouvoir saisir un en-tête, un corps et un pied de message):
git commit
Utilisez alors le format
<type>(<optional scope>): <description> <BLANK LINE> <optional body> <BLANK LINE> <optional footer>
- Pour embarquer vos modifications dans le commit précédent (
HEAD
) :git commit --amend
- et sans en modifier le message :
git commit --amend --no-edit
- et sans en modifier le message :
- Pour lier vos modifications à un des commits précédents (i.e. si ces modifications concernent un commit déjà créé):
git commit --fixup=<SHA-1 du commit cible>
- Annulez les instantanés créés si besoin
- Pour modifier le dernier instantané et repasser ses modifications dans le WD :
git reset HEAD~
- Pour que ses modifications restent dans la zone d'index :
git reset --soft HEAD~
- Pour que ses modifications restent dans la zone d'index :
- Pour annuler plusieurs commits :
git reset <SHA-1 qui deviendra le dernier commit>
git reset HEAD~<nombre de commits à annuler>
- Pour modifier le dernier instantané et repasser ses modifications dans le WD :
- Consultez l'historique des instantanés ou leurs contenus :
git lg
ougit show <SHA-1 du commit>
- Réitérez les étapes précédentes
À ce stade, tout ce que vous avez fait réside dans votre dépôt local (répertoire .git/
) et y restera tant que vous n'aurez pas publié vos modifications.
- Ajoutez un dépôt distant si besoin :
git remote add <remote> <url>
- Listez vos dépôts distants avec :
git remote -v
- Listez vos dépôts distants avec :
- Mettez à jour votre espace de travail avec le contenu de la branche distante de départ :
git pull origin <branche de départ>
- Si des modifications sont encore présentes dans votre WD :
git stash
- Résolvez les conflits si besoin
- Appliquez votre
stash
si besoin :git stash apply
- Si des modifications sont encore présentes dans votre WD :
- Effectuez une revue de votre historique :
git lg
- Nettoyez votre historique en retravaillant les commits (fusionnez les commits liés par la même tâche ensemble par ex.) :
- Identifiez le nombre de commits propres à votre branche (de la
HEAD
au premier commit de votre branche) - Effectuez une réécriture de commits sur ce nombre de commit :
git rebase -i --autosquash HEAD~<nombre de commits>
- Référez-vous au chapitre Rebase interactif pour positionner les actions sur vos commits
- Déroulez les étapes du
rebase
et résolvez les conflits potentiels- Utilisez
git rebase --continue
après chaque résolution - Utilisez
git rebase --abort
si vous souhaitez annuler lerebase
- Utilisez
- Effectuez une nouvelle revue de votre historique :
git lg
- Assurez-vous que le commit parent de votre branche n'a pas été réécrit (la référence à la branche initiale doit toujours apparaître)
- Identifiez le nombre de commits propres à votre branche (de la
- Publiez votre branche sur le dépôt distant
- Si elle n'a pas encore été publiée ou que vous n'avez pas réécrit l'historique :
git push <remote> <branch name>
- Si vous avez réécrit l'historique :
git push <remote> <branch name> --force-with-lease
- Prévenez vos équipiers que votre branche a été force push
- Si elle n'a pas encore été publiée ou que vous n'avez pas réécrit l'historique :
- Créez une demande d'intégration de vos modifications sur l'une des branches du dépôt distant
- ou faites la fusion par vous-même si votre organisation le permet
Afin de maîtriser efficacement le cycle de vie de vos développements, il est nécessaire d'imposer des règles et des processus pour la gestion des branches de votre projet. Le workflow le plus courant est celui de branche par fonctionnalité :
- Chaque fonctionnalité est développée dans une branche prévue à cet effet plutôt que dans la branche
master
. Grâce à cette encapsulation, plusieurs développeurs peuvent travailler aisément sur une même fonctionnalité sans modifier la base de code principale. Cela signifie également que la branchemaster
ne contiendra jamais de code bogué : un avantage non négligeable pour les environnements d'intégration continue. - Ce fonctionnement va permettre de proposer les modifications présentes sur une branche aux plateformes de versioning de manière isolée. Il est alors extrêmement facile pour votre équipe de faire des retours sur le travail effectué.
Partant de ce principe de base, Vincent Driessen (nvie) a popularisé un workflow offrant une grande flexibilité aux équipes; nommé Gitflow :
GitFlow est parfaitement adapté aux projets avec un cycle de livraison planifié
- Deux branches principales sont identifiées et doivent être protégées
master
: abrite le code de production. Cette branche est déployabledevelop
: abrite le code de pré-production. Elle contient souvent le code des prochaines features testées et validées
- des branches nommées
hotfix/<branch>
peuvent être créées lorsqu'il s'agit de patcher la production (master
), généralement pour corriger un bogue.- la branche du correctif doit être initiée depuis
master
- elle doit être fusionnée sur
master
- ainsi que sur
develop
pour que les correctifs soient intégrés à la prochaine version taguée dedevelop
- la branche du correctif doit être initiée depuis
- Toutes les autres branches seront des branches de fonctionnalité. Qu'il s'agisse d'une nouvelle fonctionnalité, d'un correctif, d'améliorations apportées à la documentation, ou de travaux de refactoring : ces développements doivent être isolés dans des branches dédiées, préfixée avec un type, délimité par un
-
ou un/
:<type>/<branch name>
- les types introduits par les conventions de commits peuvent être repris (
feat
,fix
,refactor
, etc) - chaque nouveau développement doit partir d'une branche (généralement
develop
) - les développements sur ces branches seront intégrés tôt ou tard (quand testés et validés) à la branche
develop
- les types introduits par les conventions de commits peuvent être repris (
Il existe d'autres workflow de branches. Libre à vous de choisir (ou de mélanger ?) celui qui convient le mieux à la taille et la maturité de votre équipe :
Avec l'adoption croissante de l'outil auprès des communautés OSS notamment, un besoin d'uniformisation de la description des commits s'est rapidement fait sentir. Impulsée par les équipes Angular notamment, une convention de commit a rapidement fait l'unanimité et est à présent décrite sous forme d'une spécification.
Cette spécification fournit un ensemble simple de règles pour créer un historique de commit explicite et lisible. Cette convention est liée à SemVer, en décrivant les fonctionnalités, les correctifs et les modifications importantes apportées aux messages de commit.
Le message du commit doit être structuré comme suit :
<type>(<optional scope>): <subject>
<BLANK LINE>
<optional body>
<BLANK LINE>
<optional footer>
- type :
- fix : corrige un bogue dans le code (cela est en corrélation avec PATCH en SemVer).
- hotfix : corrige un bogue dans le code de production (cela est en corrélation avec PATCH en SemVer).
- feat : introduit une nouvelle fonctionnalité dans le code (cela est en corrélation avec MINOR).
- chore / docs / style / perf / test / …: à la discrétion des équipes
- scope : section du code impactée par la modification
- subject : description courte de moins de 50 caractères sur les modifications opérées sur le code
- body : description longue (paragraphes) entrant dans les détails de la modification du code.
- Doit commencer par une ligne vide
- Peut contenir le bloc
BREAKING CHANGE
: introduit un changement cassant l’API (cela est en corrélation avec MAJOR en SemVer)
- footer : références de problèmes supplémentaires concernant les modifications du code (Fixes #13)
- Doit commencer par une ligne vide
- Ne peut contenir que
BREAKING CHANGE
, des liens externes, des références de publication et d’autres méta-informations
- Vous pouvez retrouver des exemples de commits sur https://www.conventionalcommits.org
- Vous pouvez générer automatiquement un CHANGELOG issue de vos commits, basés sur ces conventions : Conventional-changelog
Utilisez
git
+ TABULATION pour que le terminal vous propose les commandesUtilisez TABULATION n'importe quand pour que Git auto-complète votre commande (commandes, noms de branches, etc)
git help everyday
Un guide step-by-step d'un usage de Git à la journée.
git clean -f
Supprime les fichiers non trackés du WD. Utilisez l'option -d
pour supprimer également les répertoires.
git rm <file>... # git rm *.log
Extrait et supprime un ou plusieurs fichiers du WD et de l'index Git. Utilisez --dry-run
pour tester la présence du fichier. Utilisez --cached
pour ne le supprimer que dans la zone d'index.
git mv <source> <destination>
Déplace un fichier ou un répertoire. Les modifications sont ajoutées à l'index mais le commit reste nécessaire.
git add -N <optional file>
Indique à Git que les modifications sur le fichier seront ajoutées plus tard. Indispensable pour indexer les nouveaux fichiers (sans leurs modifications) avant le git add -p
.
git sparse-checkout set <path>
Permet de ne récupérer qu'une partie des fichiers d'un projet. Pratique sur des projets mono-repository.
git commit --fixup <commit>
Crée un commit de fixup
destiné à être intégré dans le commit <commit>
lors d'un rebase -i --autosquash
.
git commit -p
Crée un commit après une phase d'ajout interactif.
git cherry-pick <ref>
Applique la référence d'objet (commits, branche, etc) à la branche courante en créant un nouveau commit.
git revert <commit>
Joue les modifications du commit dans le sens inverse et en crée un nouveau commit. Pratique pour annuler les changements sur une branche partagée.
git rebase -i <commit>~ --autosquash
Permet de retoucher l'historique de commits, du commit <commit>
à la HEAD
. cf. Rebase interactif.
git rebase --onto <nouvelle branche> <ancienne branche> <branche courante>
Permet de changer la branche de rattachement de la branche courante. cf. Rebase --onto.
git shortlog
Affiche les commits regroupés par auteur.
git difftool
Lance la comparaison avec l'outil configuré via diff.tool
. Ajoutez l'option -t
pour préciser l'outil à utiliser (exemple : git difftool -t vscode
).
git blame <file>
Permet de lister la dernière date de modification d'une ligne et son auteur pour un fichier donné.
git grep <text>
Similaire au grep
Unix : permet de rechercher du texte dans les fichiers du WD. De nombreuses options sont disponibles.
git notes add <ref>
git notes append <ref>
Permet d'ajouter une note à un objet.
git notes show <ref>
Permet de consulter la note d'un objet.
git push <remote> refs/notes/*
Permet de publier les notes sur un dépôt distant.
git remote rename <remote> <nouveau nom> # git remote rename origin ineat
Permet de renommer un dépôt distant.
git remote set-url <remote> <url> # git remote set-url origin [email protected]:ineat/refcards.git
Permet de redéfinir l'url d'un dépôt distant.
git clone -b <branch> --depth=<x> <url> <local dir>
Clone uniquement les <x>
commits de la branche <branch>
du dépôt distant <url>
dans un dossier local <local dir>
.
git show-ref
Permet de lister les références du dépôt local.
- L'option
--system
permet de définir une configuration à un système entier.export LANG=<locale>
permet de changer la langue d'affichage des messages de Git (ex :export LANG=en_US.UTF-8
)
git config --global core.editor <path/to/tool>
: Permet d'utiliser un autre éditeur quevi
ouvim
- Pour Notepad++ (Windows) par exemple :
git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
git config --global core.pager ''
: Désactive lespager
pour toutes les commandes.git config --global core.autocrlf true
: Convertit automatiquement les fins de ligne Windows en format Unix (et inversement).git config --global core.excludesFile <path/to/.gitignore>
: Permet de définir un.gitignore
global.git config --global alias.<name> "<definition>"
: Permet de définir un alias réutilisable.
git config --global commit.template <path/to/template>
: Permet de définir un template par défaut pour les messages de commit.
git config --global fetch.prune true
: La commandefetch
sera jouée avec l'option--prune
automatiquement.
git config --global pull.rebase merges
: Conserve les commits de merge quand ils existent sur la branche d'où viennent les modifications.
git config --global merge.ff only
: N'autorise que les fusions en fast-forward (pour se pré-munir des commits de merge).git config --global merge.tool kdiff3
: Configure l'outilkdiff3
pour la résolution de conflits.git config --global diff.tool kdiff3
: Configure l'outilkdiff3
pour l'affichage des différences.
git config --global mergetool.keepBackup false
: Supprime les fichiers.orig
après la résolution des conflits.git config --global mergetool.keepTemporaries false
: Supprime les fichiers temporaires après la résolution des conflits.
git config --global rebase.autosquash true
: Positionne les commits defixup
automatiquement lors d'unrebase -i
(option--autosquash
).git config --global rebase.autoStash true
:stash
les modifications de votre WD avant unpull
, et applique cestash
juste après.git config --global sequence.editor interactive-rebase-tool
: utilise interactive-rebase-tool lors desrebase -i
.
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
: Configure la commande à lancer lors de l'utilisation degit difftool -t vscode
.git config --global rerere.enabled true
: Activegit-rerere
, i.e Git se souviendra de certaines résolutions de conflits et les réappliquera automatiquement dans les futures résolutions pour des conflits similaires .git config --global pager.branch false
: Permet de visualiser l'ensemble des branches en dehors du mode édition. L'attributpager
fonctionne pour d'autres commandes commetag
,log
,diff
, etc.git config --global help.autoCorrect immediate
: Si vous tapez mal une commande, Git corrigera votre saisie pour jouer la commande déduite automatiquement (testez avecgit stats
par exemple).
Git vous donne la possibilité d'étiqueter vos instantanés. Généralement on utilise cette fonctionnalité pour marquer les états de publication, c'est à dire les numéros de version des releases (livrables destinés a être déployés sur des environnements).
- Placez-vous sur la branche où se trouve l'instantané que vous souhaitez étiqueter
- Invoquez la commande
git tag <numero du tag>
- Par défaut, le tag portera la description du commit annoté
- Vous pouvez spécifier un message propre à votre tag grâce à l'option
-m
:git tag -a <numero du tag> -m <libellé du tag>
- Listez les tags présents sur votre dépôt local :
git tag
- Publiez votre tag sur le dépôt distant :
git push <remote> <numero du tag>
Vous pouvez fusionner votre branche de deux manières différentes :
- via un commit dit de merge (merge explicite)
- ou en fast-forward (merge implicite)
Considérez la branche feat/A
initiée depuis develop
:
C'est la politique de fusion par défaut. Elle crée un nouveau commit ayant pour parent le dernier commit des deux branches :
Un commit de merge sera créé par Git si le
fast-forward
n'est pas possible ou si l'optionno-ff
est explicitement passée augit merge
- Utilisez le commit de merge uniquement pour mettre en évidence l'ajout d'une nouvelle fonctionnalité sur votre
develop
- Utilisez le fast-forward dans tous les autres cas
Le fast-forward
permet d'obtenir un historique linéaire après une fusion. Le fast-forward
est possible si le premier commit pointé par la branche que vous avez fusionnée est directement descendant du commit sur lequel vous vous trouvez avant la fusion.
- Utilisez
git merge --ff-only
ougit config --global merge.ff only
pour vous prémunir d'un commit de merge.- Pour rendre le
fast-forward
possible, utilisez le rebasage sur la branche à fusionner.
- Pour rendre le
- Utilisez le
fast-forward
pour garder un historique de vos branches linéaire, propre et lisible.
- Placez-vous sur la branche qui va recevoir les nouvelles modifications :
git switch <nom de la branche de réception>
- Fusionnez votre branche dessus en privilégiant le
fast-forward
:git merge <type>/<branch description> --ff-only
- Résolvez les conflits si besoin
- Invoquez
git merge --continue
après la résolution
- Invoquez
- Si des branches ont été initiées depuis la mise à jour de la branche :
- Effectuez un rebasage de cette dernière sur les branches en question :
git rebase <nom de votre branche>
- Effectuez un rebasage de cette dernière sur les branches en question :
- Résolvez les conflits si besoin
- Publiez le nouvel état de votre branche sur le dépôt distant :
git push
- et des branches ayant été rebasées si besoin
- Supprimez la branche que vous venez de fusionner :
git branch -d <branch>
- Si elle est également présente sur le dépôt distant :
git push --delete <remote> <branch>
- Si elle est également présente sur le dépôt distant :
Le rebasage (rebase
) permet de synchroniser une branche (par le dessous) avec une autre. Très pratique pour bénéficier des mises à jour introduites depuis l'initiation de votre branche.
Il existe 3 sortes de rebasage de branche :
- Le mode standard : rebaser (synchroniser) une branche par rapport à une autre
- Le mode interactif : permet de réécrire (retravailler) l'historique de la branche courante
- Le mode onto : permet de rattacher le premier commit d'une branche à la
HEAD
d'une autre branche
Considérez que vous travaillez sur la branche feat/A
:
Un commit vient d'être ajouté sur la develop
, ce qui veut dire que la branche feat/A
est en retard.
Il faut donc ici mettre à jour la branche feat/A
par rapport à la develop
grâce à la commande git rebase
. C'est une mise à jour par le dessous : c'est à dire que les nouveaux commits de la develop
vont être joués sur la branche cible. Les commits existants (ceux de la branche feat/A
) sont réécrits puisque leurs commits parents changent.
Le git rebase
peut engendrer des conflits si des modifications sur des fichiers communs entrent en collision. Pour plus de détails sur cette partie consultez le chapitre Gestion des conflits.
Dans votre workflow de versioning, vous serez amené à créer plus de commits (commit de fixup
?) que de tâches à réaliser. A la fin de vos développements, vous devez retravailler l'historique de votre branche pour :
- fusionner les commits qui concernent la même tâche
- réécrire la description de vos commits si elle est incomplète/erronée
- supprimer des commits si besoin
- bref, proposer un historique propre et lisible à votre équipe
C'est pour ce besoin que le rebase interactif est utilisé. Il s'agit d'une option du rebase
classique : git rebase -i
.
Vous devez indiquer au rebase -i
à partir de quel commit parent vous souhaitez réécrire votre historique :
-
en utilisant le SHA-1 du commit parent :
git rebase -i <SHA-1-du-commit>
. -
en utilisant un nombre de commits à réécrire à partir de la
HEAD
:git rebase -i HEAD~<nombre de commits à réécrire>
.Exemples :
git rebase -i 2edb99f
si vous souhaitez retoucher à tous les commits au dessus du commit2edb99f
git rebase -i HEAD~8
si vous souhaitez retoucher à vos 8 derniers commits
Git vous propose une liste d'actions documentées dont voici les principales :
pick
: laisser le commit inchangéreword
: permet de réécrire uniquement le message du commitedit
: permet d'intégrer d'autres modifications au commit (équivaut augit commit --amend
)squash
: permet de fusionner 2 commits et de modifier le message du commit finalfixup
: permet de fusionner le contenu du commit dans le commit parent, sans garder le message de commit.drop
: permet de supprimer un commit et le code associéréorganiser des commits
: vous pouvez réordonner les commits de haut (plus ancien) en bas (plus récent). Indispensable pour lefixup
ou lesquash
notamment, qui s'appliquent à un commit parent
Vous devez positionner les commandes à la place des pick
en fonction de ce que vous voulez faire. Git va ensuite dépiler l'ensemble des commandes et vous demander d'effectuer des actions quand nécessaires (saisie d'un nouveau message, résolution de conflits, etc).
Il est important de noter que tous les commits concernés par le rebase
seront réécrits, même ceux laissés tels quels.
Vous pouvez utiliser git-interactive-rebase-tool pour vous simplifier la vie lors des rebases interactifs.
Lors des phases de développements, il arrive régulièrement que des branches soient initiées depuis d'autres branches en cours de développement comme l'illustre le schéma suivant :
Certaines de ces branches de développement peuvent évoluer indépendamment les unes des autres. Voici un des cas les plus fréquents :
- la branche
develop
évolue. De nouveaux commits sont poussés (correctifs, fonctionnalités fusionnées, etc) - l'équipe en charge de la branche
feat/A
décide de rebaser sa branche avecdevelop
(rappelez-vous, legit rebase
réécrit généralement l'historique)
Cela donne la situation suivante :
- finalement, la branche
feat/B
, initiée depuis le commitA2
de la branchefeat/A
, doit être fusionnée avantfeat/A
et n'a plus besoin des modifications introduites dansfeat/A
Le rebase --onto
permet de rattacher la branche courante à la HEAD
d'une nouvelle branche en déterminant les patchs depuis l'ancêtre commun des branches : git rebase --onto <nouvelle branche> <ancienne branche> <branche courante>
Vous avez normalement l'habitude d'utiliser la commande git add
pour indexer vos fichiers avant d'effectuer un commit. Un des concepts de Git est de regrouper dans un commit l'ensemble des modifications liées à une tâche. Il arrive souvent qu'un fichier abrite des modifications qui ne concernent pas la tâche en cours.
Il est alors nécessaire de n'ajouter qu'une partie des lignes du fichier au prochain commit.
La commande git add -p
permet d'effectuer cette action. Git va itérer sur les fichiers modifiés et va vous proposer d'ajouter, ou non, les lignes (hunks) de chacun des fichiers.
Plusieurs choix vous sont proposés ici : (Stage this hunk [y,n,q,a,d,s,e,?]?
)
Difficile de savoir à quoi correspondent ces lettres.
- Appuyez une fois sur la touche Entrée (ou tapez
?
puis Entrée) pour en découvrir le détail. y (yes)
: permet d'indexer la portion de code proposée puis de passer à la portion suivante.n (no)
: N'indexe pas la portion de code proposée, passe à la portion suivante.s (split)
: découpe la portion de code proposée en une plus petite portion si possibleq (quit)
: n'indexe pas la portion de code proposée, ni celles restantes.
Il arrive parfois que la commande split
du git add -p
ne parvienne pas à diviser les hunks en plus petites portions (généralement quand les modifications se suivent). Il est possible de passer en mode edition (e
) afin de choisir manuellement quelle partie du fichier vous souhaitez indexer.
Voici comment utiliser le mode édition :
L'éditeur Git vous propose l'ensemble des lignes modifiées, préfixées par un symbole (i.e. context
)
-
indique une ligne supprimée- Si vous ne voulez pas que cette ligne supprimée soit indexée, passez le
context
de-
à' '
- Si vous ne voulez pas que cette ligne supprimée soit indexée, passez le
+
indique une ligne ajoutée- Si vous ne voulez pas que cette ligne ajoutée soit indexée, supprimez-la
- une ligne modifiée possède deux lignes : l'ancienne (
-
) et la nouvelle (+
)- Si vous ne voulez pas que cette ligne modifiée soit indexée, supprimez la ligne indiquée par
+
et passez lecontext
de la ligne supprimée de-
à' '
- Si vous ne voulez pas que cette ligne modifiée soit indexée, supprimez la ligne indiquée par
L'idée est de créer une version de vos modifications comme vous souhaitez les voir dans la zone d'index. Si des lignes modifiées ne doivent pas être prises en compte, restaurez leurs états pour ce
add -p
en suivant les explications ci-dessus. P.S : Il est important de ne pas toucher aux lignes du fichier non modifiées !
Git propose une commande git stash
qui vous permet de mettre vos modifications de côté et éviter de les balader dans le WD des autres branches.
Voici un cas d'utilisation où le stash
est utile :
- Vous êtes sur une branche, feat/A, et vous avez fait quelques modifications, encore présentes dans votre WD.
- Vous devez faire un
git pull
ou ungit rebase develop
sur votre branche : Git refusera car vous avez encore des modifications dans votre WD.
- Utilisez la commande
git stash
pour remiser temporairement vos modifications - Une nouvelle entrée du
stash
est créée. Vous pouvez consulter la liste de vosstash
viagit stash list
- Faites ce que vous devez faire (
pull
, travaux sur d'autres branches, etc) - Utilisez
git stash apply
pour appliquer le dernierstash
créé sur votre WD
- Préférez le
git stash apply
augit stash pop
pour conserver vos anciens stashs- Faites le ménage via
git stash drop <stash>
si certainsstash
s ne sont plus utiles- Utilisez
git stash apply <stash>
(exemple :git stash apply stash@{0}
) pour appliquer votrestash
au WD- Utilisez
git stash -p
pour ne remiser qu'une partie de vos modifications.
Un ou plusieurs conflits peuvent apparaître pendant un git merge
, git rebase
ou encore un git cherry-pick
. Cela arrive lorsque la même ligne est modifiée sur les 2 branches concernées par la commande.
Si vous éditez le fichier en conflit, vous découvrirez comment Git gère les modifications :
<<<<<<< HEAD
et=======
encapsulent les modifications présentes initialement=======
et>>>>>>>
encapsulent les nouvelles modifications à intégrer
- A vous de faire votre choix et de supprimer les modifications obsolètes
Fusionner ses modifications via ces marqueurs peut se révéler laborieux. Il existe des outils pour vous aider à gérer les conflits de manière plus visuelle.
- Consultez la liste des outils de merge supportés par défaut par Git
Après avoir téléchargé l'outil de votre choix :
- Indiquer à Git comment l'utiliser :
git config --global merge.tool <tool>
- Vous pouvez avoir plusieurs outils configurés et changer la valeur de
merge.tool
au besoin
- Vous pouvez avoir plusieurs outils configurés et changer la valeur de
- Si cet outil n'est pas déclaré dans votre
$PATH
, utilisez la configurationgit config --global mergetool.<tool>.path <path>
- Vous pouvez ne pas garder les fichiers temporaires générés par Git pendant et après le conflit :
git config --global mergetool.keepBackup false
git config --global mergetool.keepTemporaries false
- Vous êtes prêt, invoquez
git mergetool
lors des phases de conflits pour que Git vous lance l'éditeur visuel !- Utilisez
git commit
et/ougit merge --continue
pour passer à la résolution suivante - Utilisez
git merge --abort
pour annuler une résolution de conflits
- Utilisez
Les logs de référence ou reflogs
constituent un mécanisme utilisé par Git pour enregistrer les mises à jour appliquées aux pointes (HEAD
) des branches et à d'autres références de commit.
Le reflog vous permet de revenir sur les commits même s'ils ne sont pas référencés par une branche ou un tag. Une fois l'historique réécrit, le reflog
contient des informations sur l'ancien état des branches et vous permet d'y revenir si nécessaire.
À chaque mise à jour de la pointe HEAD
de votre branche quelle qu'en soit la raison (en changeant les branches, en faisant un pull de nouveaux changements, en réécrivant l'historique ou simplement en ajoutant de nouveaux commits), une nouvelle entrée est ajoutée au reflog.
- Consultez le
reflog
via :git reflog
pour afficher lereflog
de votreHEAD
git reflog --relative-date
si vous souhaitez avoir une vue horodatéegit reflog --all
pour consulter lereflog
de toutes vos réfsgit reflog <branch>
pour consulter lereflog
d'une branche en particulier
- Revenez en arrière sur l'état de l'historique souhaité
git reset <reflog state>
(exemple :git reset HEAD@{2}
)
Une plateforme de versioning s'appuie sur Git pour vous proposer un hébergement décentralisé de votre code source et bien d'autres fonctionnalités (WYSIWYG, bug tracker, documentation, CI/CD, etc). Ces plateformes proposent des dépôts distants qui interagiront avec votre dépôt local via les commandes fetch
, pull
et push
.
Vous pouvez contacter les serveurs distants de deux façons :
En saisissant votre identifiant et votre mot de passe (à chaque push
ou fetch
)
- Définissez la configuration
git config --global credential.helper cache
pour éviter la re-saisie - Vous pouvez définir un personal-access-token qui sera associé à votre compte et remplacera votre mot de passe lors de la saisie :
Ce personal-access-token doit être utilisé par vos outils de CI/CD afin de ne pas utiliser directement votre mot de passe de compte
- Pour Github : https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line
- Pour Gitlab : https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html
- Pour Bitbucket : https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html
L'authentification entre votre poste et la plateforme sera effectuée grâce à votre clé SSH publique, déclarée sur la plateforme.
- Générez votre clé SSH si vous n'en avez pas déjà une depuis un terminal (
Git Bash
par défaut) :ssh-keygen -t rsa -b 4096 -C "<your email>"
- Laissez le chemin de génération par défaut :
~/.ssh/id_rsa
- Saisissez (ou non) une passphrase (qui vous sera demandée à chaque
push
oufetch
)- Sous Mac, votre passphrase est sauvegardée automatiquement à la première saisie
- Pour les autres systèmes, il est nécessaire d'ajouter votre clé au ssh-agent :
ssh-add ~/.ssh/id_rsa
- Déclarez votre clé SSH publique (
cat ~/.ssh/id_rsa.pub
) sur votre plateforme :
Dépendant de la plateforme que vous utilisez, la terminologie et le workflow seront différents mais les concepts et principes restent les mêmes.
En vous basant sur le chapitre Workflow type d'un développement avec Git :
- Effectuez vos développements sur une branche dédiée en vous assurant que la branche de départ reste toujours synchronisée
- Publiez votre branche sur le dépôt distant
- Créez la demande de fusion depuis la plateforme
- Dépendant du résultat du code review de votre soumission, soit votre branche sera intégrée à
develop
, soit vous devrez la retravailler avant son intégration.
HEAD
est un pointeur sur la référence de la branche actuelle, qui est à son tour un pointeur sur le dernier commit réalisé sur cette branche. Ceci signifie que HEAD
sera le parent du prochain commit à créer. C’est généralement plus simple de penser HEAD
comme l’instantané de votre dernière validation.
Git utilise d'autres références de ce type comme
ORIG_HEAD
: état de laHEAD
avant ungit reset
FETCH_HEAD
: état de la branche que vous venez de mettre à jour (viagit fetch
)MERGE_HEAD
: état de la branche après ungit merge
CHERRY_PICK_HEAD
: état de la branche après ungit cherry-pick
L’index est la zone qui contient les modifications du prochain commit que vous ferez. C'est la « zone de préparation » alimentée par git add
. C’est ce que Git examine lorsque vous lancez git commit
.
Aussi nommé Working Tree
, c'est l'endroit où vous modifiez vos fichiers. Il faut penser le répertoire de travail comme un bac à sable où vous pouvez essayer vos modifications avant de les transférer dans votre index puis les valider dans votre historique, ou les jeter à la poubelle (clean
).
- Documentation officielle de Git
- Cheat Sheet visuelle
- Worflow GitFlow
- Become a git guru - Tutoriels
- Convention de commits
- Merge vs Rebase
- Git Reflog
Ce guide a été écrit par Ludovic Dussart avec l'aide de Gabin Darras en juillet 2019. Dernière mise à jour en juillet 2022.
Merci à nos relecteurs : Kelsey Rider, Antoine Caron, Lucas Declercq, Mathias Deremer-Accettone, Pamela Rossignol, Emmanuel Peru, Clément Poissonnier.
La direction artistique et les illustrations sont l'œuvre de Jean-François Tranchida.
"Je ne suis qu'un sale égocentrique, donc j'appelle tous mes projets d'après ma propre personne. D'abord Linux, puis Git." Linus Torvalds
Git (noun): an unpleasant or contemptible person.