Démarrage

Installation et configuration initiale

Bonjour, je suis Gitou, je vais t'accompagner dans ta découverte de Git, outil exceptionnel de gestion de projets pour Mac OS et Windows.
La première chose à faire après l'installation de Git est de renseigner ton identité. Cette information sera attachée à tous tes commits.
# Renseigner nom et e-mail (une seule fois par machine)
$ git config --global user.name "Jean Dupont"
$ git config --global user.email jean@example.com

# Définir l'éditeur de texte (ex : nano, vim, notepad++)
$ git config --global core.editor nano

# Définir le nom de branche par défaut (Git 2.28+)
$ git config --global init.defaultBranch main

# Vérifier tous les paramètres et leurs sources
$ git config --list --show-origin

# Vérifier une valeur spécifique
$ git config user.name
Jean Dupont
L'option --global écrit dans ~/.gitconfig et s'applique à tous tes dépôts. Sans option de niveau, Git écrit dans .git/config du dépôt courant. Attention, le dossier .git est et doit rester un dossier caché.

Créer ou cloner un dépôt

Deux points d'entrée possibles : initialiser un dépôt dans un répertoire existant, ou cloner un dépôt distant depuis le site Web de GitHub (https://github.com/).
# Initialiser un dépôt dans le répertoire courant
$ cd mon_projet
$ git init
Dépôt Git vide initialisé dans /home/user/mon_projet/.git/

# Ajouter les fichiers existants et faire le premier commit
$ git add .
$ git commit -m "initial commit"

# Cloner un dépôt distant (crée le répertoire libgit2/)
$ git clone https://github.com/libgit2/libgit2

# Cloner dans un répertoire nommé différemment
$ git clone https://github.com/libgit2/libgit2 monlibgit2

# Créer un dépôt nu (pour serveur)
$ git clone --bare mon_projet mon_projet.git
Travail quotidien

Vérifier l'état de la copie de travail

# Affichage complet (verbeux)
$ git status
Sur la branche master
Votre branche est à jour avec 'origin/master'.
Modifications qui seront validées :
  nouveau fichier : LISEZMOI
Modifications qui ne seront pas validées :
  modifié : CONTRIBUTING.md
Fichiers non suivis :
  notes.txt

# Affichage court : deux colonnes (index / copie de travail)
$ git status -s
A  LISEZMOI
 M CONTRIBUTING.md
?? notes.txt
Légende du format court : A = nouveau fichier indexé, M = modifié, ?? = non suivi. La colonne de gauche représente l'index, la colonne de droite la copie de travail.

Indexer des modifications (git add)

# Indexer un fichier spécifique
$ git add LISEZMOI

# Indexer tous les fichiers modifiés et nouveaux de l'arbre
$ git add .

# Indexer par patron glob
$ git add *.c

# Indexation interactive hunk par hunk (sélection partielle)
$ git add -p fichier.py
@@ -10,6 +10,8 @@ def traiter():
...
Indexer ce hunk [y,n,q,a,d,/,e,?]?
Si tu modifies un fichier après git add, il faut relancer git add pour que les nouvelles modifications soient incluses dans le prochain commit. Git indexe l'état du fichier au moment de l'appel.

Inspecter les différences (git diff)

# Voir les modifications NON indexées (copie de travail vs index)
$ git diff

# Voir les modifications INDEXÉES (index vs dernier commit)
$ git diff --staged

# Vérifier les erreurs d'espacement avant de committer
$ git diff --check

# Diff entre deux commits
$ git diff abc1234 def5678

# Résumé statistique
$ git diff --stat HEAD~3

# Utiliser un outil graphique externe
$ git difftool

Valider des modifications (git commit)

# Committer en ouvrant l'éditeur pour le message
$ git commit

# Committer avec un message en ligne
$ git commit -m "Corrige le bug de calcul du sous-réseau"
[master 463dc4f] Corrige le bug de calcul du sous-réseau
 2 files changed, 4 insertions(+), 1 deletion(-)

# Indexer automatiquement les fichiers suivis ET committer
$ git commit -a -m "Mise à jour du module réseau"

# Inclure le diff dans l'éditeur de message pour référence
$ git commit -v
Bonne pratique : message sur une ligne courte (50 car. max), ligne vide, puis description détaillée. Utiliser l'impératif : « Corrige… », « Ajoute… », « Supprime… ».

Parcourir l'historique (git log)

# Historique complet (ordre inverse)
$ git log

# Une ligne par commit
$ git log --oneline

# Graphe des branches avec décoration
$ git log --oneline --decorate --graph --all

# Voir les 2 derniers commits avec leur diff
$ git log -p -2

# Statistiques par commit
$ git log --stat

# Format personnalisé : SHA court, auteur, date relative, titre
$ git log --pretty=format:"%h - %an, %ar : %s"

# Filtrer par auteur, depuis 2 semaines, hors fusions
$ git log --author="Jean" --since="2.weeks" --no-merges

# Rechercher les commits ayant ajouté ou retiré une chaîne
$ git log -S "nom_de_fonction"

# Limiter aux commits modifiant un fichier précis
$ git log -- src/network.py

Supprimer et déplacer des fichiers

# Supprimer un fichier et indexer la suppression
$ git rm PROJECTS.md

# Forcer la suppression d'un fichier modifié ou indexé
$ git rm -f fichier_modifie.txt

# Retirer de l'index sans supprimer de la copie de travail
# (utile pour un fichier oublié dans .gitignore)
$ git rm --cached log/app.log

# Supprimer par patron (échapper * pour éviter l'expansion shell)
$ git rm log/\*.log

# Renommer / déplacer un fichier
$ git mv ancien_nom.py nouveau_nom.py
Annulation

Corriger le dernier commit (--amend)

# Corriger le message du dernier commit
$ git commit --amend

# Ajouter un fichier oublié au dernier commit
$ git add fichier_oublie.py
$ git commit --amend --no-edit
# --no-edit conserve le message existant
Ne jamais utiliser --amend sur un commit déjà poussé vers un dépôt partagé. Il réécrit le SHA-1 et force les collaborateurs à re-fusionner leur travail.

Désindexer et réinitialiser des fichiers (git restore)

# Désindexer un fichier (le retirer de la zone d'index)
$ git restore --staged CONTRIBUTING.md

# Annuler les modifications d'un fichier dans la copie de travail
# (ramène à l'état du dernier commit)
$ git restore CONTRIBUTING.md
git restore <fichier> écrase définitivement les modifications locales non commitées. À n'utiliser qu'avec certitude absolue.
Sur les versions antérieures à Git 2.25, utiliser : git reset HEAD <fichier> pour désindexer, et git checkout -- <fichier> pour réinitialiser la copie de travail.

git reset — déplacer HEAD et modifier l'état

# Mode --soft : annule le commit mais garde l'index et la copie de travail
# (les modifications restent indexées, prêtes à être revalidées)
$ git reset --soft HEAD~1

# Mode --mixed (défaut) : annule le commit et désindexe
# (les modifications restent dans la copie de travail, non indexées)
$ git reset HEAD~1

# Mode --hard : annule le commit, désindexe ET réinitialise la copie de travail
# (DESTRUCTION des modifications non commitées)
$ git reset --hard HEAD~1

# Désindexer un fichier spécifique (ancienne syntaxe)
$ git reset HEAD CONTRIBUTING.md
Scénario typique Tu as validé trois commits de debug que tu veux condenser en un seul commit propre avant de pousser :
git reset --soft HEAD~3 — les trois commits disparaissent, mais toutes les modifications restent indexées. Tu peux alors faire git commit -m "Implémentation complète du module X".
Branches

Créer et basculer entre les branches

# Lister les branches locales
$ git branch
  iss53
* master
  testing

# Créer une branche sans basculer dessus
$ git branch nouvelle-fonction

# Créer ET basculer sur la nouvelle branche (méthode classique)
$ git checkout -b nouvelle-fonction

# Même chose avec git switch (Git 2.23+)
$ git switch -c nouvelle-fonction

# Basculer sur une branche existante
$ git checkout master
$ git switch master

# Revenir à la branche précédente
$ git switch -

# Supprimer une branche fusionnée
$ git branch -d hotfix

# Renommer une branche locale
$ git branch --move ancien-nom nouveau-nom

# Voir toutes les branches avec leur dernier commit et upstream
$ git branch -vv

# Voir les branches non encore fusionnées
$ git branch --no-merged

Fusionner des branches (git merge)

# Fusionner la branche hotfix dans master (fast-forward si possible)
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

# Fusionner iss53 dans master (crée un commit de fusion à 3 sources)
$ git merge iss53
Merge made by the 'recursive' strategy.
 README | 1 +
 1 file changed, 1 insertion(+)

# Forcer un commit de fusion même quand l'avance rapide serait possible
$ git merge --no-ff hotfix

# Abandonner une fusion en cours (en cas de conflit non gérable)
$ git merge --abort

Résoudre des conflits de fusion

Quand deux branches ont modifié la même zone d'un fichier, Git ne peut pas fusionner automatiquement. Le fichier en conflit contient des marqueurs que tu dois résoudre manuellement.
# Voir quels fichiers sont en conflit
$ git status
Unmerged paths:
  both modified: index.html
Le fichier en conflit contient les marqueurs suivants :
<<<<<<< HEAD
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
  please contact us at support@github.com
</div>
>>>>>>> iss53
Tu édites le fichier, tu supprimes les marqueurs et tu conserves la version voulue (ou tu combines les deux). Ensuite :
# Marquer le conflit comme résolu
$ git add index.html

# Finaliser le commit de fusion
$ git commit

# Alternative : utiliser un outil graphique de fusion
$ git mergetool

Rebaser une branche (git rebase)

# Rebaser la branche experiment sur master (historique linéaire)
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

# Ensuite, avance rapide de master
$ git checkout master
$ git merge experiment

# Rebaser client sur master sans toucher à server
# (transplanter uniquement les commits propres à client)
$ git rebase --onto master server client

# Rebase interactif : réécrire les 3 derniers commits
$ git rebase -i HEAD~3
# L'éditeur s'ouvre avec la liste des commits
# Actions : pick, reword, edit, squash, fixup, drop

# En cas de conflit pendant un rebase
$ git add fichier_resolu.py
$ git rebase --continue
# Ou abandonner complètement
$ git rebase --abort
Ne rebaser que des commits locaux non encore partagés. Rebaser des commits publiés oblige tes collaborateurs à re-fusionner leur travail.

Remiser du travail en cours (git stash)

# Remiser les modifications en cours (copie de travail + index)
$ git stash
Saved working directory and index state WIP on master: 049d078 added the index file

# Lister les remisages
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"

# Réappliquer le dernier remisage et le supprimer de la pile
$ git stash pop

# Réappliquer un remisage spécifique sans le supprimer
$ git stash apply stash@{1}

# Créer une branche à partir d'un remisage
$ git stash branch testbranch

# Supprimer un remisage
$ git stash drop stash@{0}
Dépôts distants

Gérer les dépôts distants (git remote)

# Lister les dépôts distants
$ git remote
origin

# Lister avec les URLs
$ git remote -v
origin  https://github.com/user/project (fetch)
origin  https://github.com/user/project (push)

# Ajouter un dépôt distant
$ git remote add pb https://github.com/paulboone/ticgit

# Afficher les détails d'un dépôt distant
$ git remote show origin

# Renommer un dépôt distant
$ git remote rename pb paul

# Supprimer un dépôt distant
$ git remote remove paul

Récupérer depuis un dépôt distant (fetch / pull)

# Récupérer toutes les nouvelles données depuis origin
# (met à jour origin/master, etc. mais NE fusionne PAS)
$ git fetch origin

# Récupérer depuis tous les distants
$ git fetch --all

# Récupérer un dépôt distant spécifique non nommé origin
$ git fetch equipeun

# Récupérer ET fusionner dans la branche courante (fetch + merge)
$ git pull

# Récupérer et rebaser plutôt que fusionner
$ git pull --rebase

# Configurer pull.rebase par défaut
$ git config --global pull.rebase true

Pousser vers un dépôt distant (git push)

# Pousser la branche master vers origin
$ git push origin master

# Pousser ET définir la branche distante comme upstream
$ git push -u origin ma-branche

# Pousser avec une refspec locale:distante
$ git push origin fonctionB:fonctionBee

# Pousser toutes les étiquettes annotées
$ git push origin --follow-tags

# Supprimer une branche distante
$ git push origin --delete branche-obsolete

# La poussée est rejetée si l'historique distant a divergé
! [rejected] master -> master (non-fast forward)
# Solution : récupérer et fusionner d'abord
$ git pull
$ git push origin master

Branches de suivi à distance

# Créer une branche locale qui suit une branche distante
$ git checkout -b correctionserveur origin/correctionserveur
# Raccourci :
$ git checkout --track origin/correctionserveur
# Plus court encore (si le nom est unique) :
$ git checkout correctionserveur

# Associer une branche locale existante à une branche distante
$ git branch -u origin/correctionserveur

# Voir le statut de toutes les branches de suivi
$ git branch -vv
  iss53       7e424c3 [origin/iss53: ahead 2] forgot the brackets
* master      1ae2a45 [origin/master] deploying index fix

# Supprimer une branche distante
$ git push origin --delete correctionserveur
Étiquettes (Tags)

Créer, lister et partager des étiquettes

# Lister toutes les étiquettes
$ git tag
v0.1
v1.3
v1.4

# Lister avec un filtre
$ git tag -l 'v1.8.5*'

# Créer une étiquette annotée (recommandée pour les versions)
$ git tag -a v1.4 -m "version 1.4"

# Créer une étiquette légère (simple pointeur)
$ git tag v1.4-lw

# Étiqueter un commit passé
$ git tag -a v1.2 9fceb02

# Voir les données d'une étiquette annotée
$ git show v1.4

# Pousser une étiquette spécifique sur le distant
$ git push origin v1.5

# Pousser toutes les étiquettes annotées liées aux commits poussés
$ git push origin --follow-tags

# Supprimer une étiquette locale
$ git tag -d v1.4-lw

# Supprimer une étiquette sur le distant
$ git push origin --delete v1.4-lw

# Extraire le contenu d'une étiquette (crée un HEAD détaché)
$ git checkout v2.29.2
# Pour travailler dessus, créer une branche
$ git checkout -b v2.29.X
Utilitaires

Localiser un bug par recherche binaire (git bisect)

# Démarrer une session de bisect
$ git bisect start

# Marquer le commit courant comme défectueux
$ git bisect bad

# Marquer un commit connu comme correct
$ git bisect good v2.1
Bisecting: 6 revisions left to test after this (roughly 3 steps)

# Git extrait un commit intermédiaire. Tu testes, puis :
$ git bisect bad   # ou
$ git bisect good

# Automatiser avec un script de test (exit 0 = bon, exit 1 = mauvais)
$ git bisect run python tests/test_feature.py

# Terminer la session et revenir à la branche d'origine
$ git bisect reset

Identifier l'auteur d'une ligne (git blame)

# Annoter un fichier ligne par ligne
$ git blame network.py
^4832fe2 (Jean Dupont 2025-01-15 10:23:11) def connect():
a8f4c13b (Marie Martin 2025-02-03 14:12:55)     host = resolve_dns(name)

# Limiter à une plage de lignes
$ git blame -L 25,40 network.py

Créer des alias Git

# Alias classiques
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status

# Alias pour désindexer un fichier
$ git config --global alias.unstage 'restore --staged'

# Alias pour voir le dernier commit
$ git config --global alias.last 'log -1 HEAD'

# Alias pour un log graphique complet
$ git config --global alias.lg 'log --oneline --decorate --graph --all'

# Alias lançant une commande externe (préfixe !)
$ git config --global alias.visual '!gitk'

# Utilisation
$ git st
$ git last

Ignorer des fichiers (.gitignore)

Le fichier .gitignore à la racine du dépôt liste les patrons de fichiers que Git doit ignorer. Il s'applique récursivement. Des .gitignore supplémentaires peuvent exister dans les sous-répertoires.
# Exemple de .gitignore
# Ignorer tous les fichiers .a et .o
*.a
*.o

# Mais suivre lib.a malgré la règle précédente
!lib.a

# Ignorer uniquement TODO à la racine
/TODO

# Ignorer tout le répertoire build/
build/

# Ignorer doc/notes.txt mais pas doc/server/arch.txt
doc/*.txt

# Ignorer tous les .txt sous doc/ récursivement
doc/**/*.txt
GitHub maintient des modèles .gitignore pour de nombreux langages et frameworks sur github.com/github/gitignore.
Avancé

Gérer les sous-modules (git submodule)

# Ajouter un sous-module dans un dépôt existant
$ git submodule add https://github.com/user/lib.git libs/lib

# Cloner un dépôt avec ses sous-modules
$ git clone --recurse-submodules https://github.com/user/projet.git

# Initialiser et mettre à jour les sous-modules après un clone classique
$ git submodule init
$ git submodule update

# Mettre à jour les sous-modules vers la dernière version distante
$ git submodule update --remote

# Exécuter une commande dans chaque sous-module
$ git submodule foreach 'git fetch'

# Voir l'état de tous les sous-modules
$ git submodule status

Transférer des données sans réseau (git bundle)

# Créer un bundle de toute la branche master
$ git bundle create repo.bundle master

# Créer un bundle des commits récents uniquement
$ git bundle create recent.bundle HEAD~10..HEAD

# Vérifier un bundle reçu
$ git bundle verify repo.bundle

# Utiliser un bundle comme dépôt distant
$ git clone repo.bundle repo-cible
$ git fetch ../repo.bundle master

Récupérer du travail perdu (reflog)

Le reflog enregistre localement tous les mouvements de HEAD, même après un git reset --hard. Tout commit atteint par le reflog peut être récupéré.
# Voir l'historique des positions de HEAD
$ git reflog
a41df0b HEAD@{0}: commit: Ajout de la fonction réseau
310154e HEAD@{1}: reset: moving to 310154e
a8f4c13 HEAD@{2}: commit: Mise à jour README

# Récupérer un commit supprimé par reset --hard
# (le commit existe encore pendant 30 jours par défaut)
$ git checkout a41df0b
# Ou créer une branche de récupération
$ git branch recovery a41df0b

# Vérifier les objets orphelins (dangling commits)
$ git fsck --lost-found

# Inspecter un objet dangling trouvé
$ git show sha1_du_commit_dangling
Git ne supprime les objets orphelins qu'après 30 jours par défaut (via git gc). Le travail perdu est presque toujours récupérable tant que le dépôt n'a pas subi un gc --prune=now.