Outils du dev · Tuto

Git : commandes, rebase et travail en équipe
Les commandes de tous les jours, le rebase sans casse, les réparations qui sauvent une journée, puis la façon dont une équipe fait monter une fonctionnalité jusqu'en production. Chaque commande est donnée telle qu'on la tape, avec le moment où elle sert.
Aller plus loin avecLa fiche suit trois temps. Les sections 1 à 5 couvrent ce qu'on tape chaque jour. Les sections 6 à 10 traitent du rebase et des réparations. Les sections 11 à 16 parlent du travail à plusieurs, là où chaque équipe a ses habitudes.
01Ce que Git fait vraiment
Git n'enregistre que ce que vous lui demandez d'enregistrer. Votre travail passe par quatre endroits, et chaque commande le fait passer de l'un à l'autre.
- Le dossier de travail : vos fichiers, tels que vous les modifiez.
- La zone d'attente (l'index) : ce qui partira dans le prochain commit, et rien d'autre.
- L'historique local, rangé dans le dossier caché
.git: la suite de vos commits. - Le serveur, appelé
originpar convention : GitHub, GitLab ou le serveur de l'équipe.
Un commit est une photo complète du projet, repérée par un identifiant appelé hash, par exemple 7c2e1b8. Une branche n'est qu'une étiquette posée sur un commit : en créer une ne coûte rien. HEAD désigne l'endroit où vous êtes en ce moment.
| Passage | Commandes |
|---|---|
| Dossier ↔ zone d'attente | git add pour y mettre, git restore --staged pour en retirer |
| Zone d'attente ↔ historique | git commit pour enregistrer, git reset --soft pour défaire |
| Historique ↔ serveur | git push pour envoyer, git fetch ou git pull pour recevoir |
02Démarrer : git clone ou git init
Une seule fois par machine, donnez votre nom et votre adresse. Prenez l'adresse de votre compte GitHub ou GitLab : vos commits seront rattachés à votre profil.
git config --global user.name "[Prénom Nom]" git config --global user.email "[vous@exemple.fr]" git config --global init.defaultBranch main
git clone [url]Télécharge le projet avec tout son historique et toutes ses branches, et règle origin pour vous.
QuandLe projet existe déjà sur un serveur.
git initCrée le dossier .git dans le dossier courant. Rien n'existe encore sur un serveur : il faut le relier ensuite.
QuandVous partez de zéro.
git init
git add .gitignore
git commit -m "Premier commit"
git remote add origin [url-du-depot]
git push -u origin mainÉcrivez le fichier .gitignore avant tout le reste. Il liste ce que Git doit ignorer : les dépendances (node_modules/), les fichiers générés (dist/) et surtout les secrets (.env).
Un secret envoyé une fois reste dans l'historique. Supprimer le fichier ensuite ne l'efface pas des commits passés, ni des copies déjà clonées. Changez le mot de passe ou la clé tout de suite.
Depuis le 13 août 2021, GitHub n'accepte plus le mot de passe du compte pour les opérations Git. Utilisez une clé SSH, avec une adresse du type git@github.com:…, ou un jeton d'accès personnel en HTTPS (annonce de GitHub).
03Le cycle de tous les jours
git statusDit ce qui a changé, ce qui attend dans la zone d'attente et sur quelle branche vous êtes. Tapez-le avant et après chaque commande, au début.
git diffMontre les lignes modifiées qui ne sont pas encore dans la zone d'attente. git diff --staged montre celles qui y sont.
git add -pPropose chaque bloc modifié un par un : vous répondez y pour le garder, n pour le laisser.
QuandPour ne pas embarquer un console.log oublié ou un fichier de test.
git commit -m "…"Enregistre le contenu de la zone d'attente. Un commit porte une seule idée.
git log --oneline --graphAffiche l'historique, un commit par ligne, avec le dessin des branches.
Écrivez le message à l'impératif, comme une consigne : « Corrige le calcul de la TVA ». Si la raison du changement n'est pas évidente, ajoutez-la. Avant votre premier commit dans une équipe, lisez git log --oneline -20 : vous verrez si elle met un numéro de ticket ou un préfixe comme feat: et fix: (la convention Conventional Commits).
Évitez git add . tant que vous n'avez pas l'habitude. Il ajoute tout le dossier, y compris ce que vous n'aviez pas prévu d'envoyer.
04Parler au serveur : fetch, pull, push
git fetchTélécharge les nouveautés du serveur sans toucher à vos fichiers ni à vos branches. Sans risque, à faire souvent.
git pullFait un fetch, puis intègre les nouveautés dans votre branche. Si vous n'avez rien commité de votre côté, la branche avance simplement.
Quand le serveur et vous avez chacun des commits nouveaux, les deux historiques ont divergé. Sans réglage, une version récente de Git s'arrête alors sur le message Need to specify how to reconcile divergent branches et vous demande de choisir. git pull --rebase rejoue vos commits par-dessus ceux du serveur. git pull --no-rebase fait une fusion. Pour fixer votre choix une fois pour toutes, réglez pull.rebase (documentation de git pull).
git config --global pull.rebase true
git push -u origin [branche]Envoie une branche pour la première fois et la relie à sa copie sur le serveur. Ensuite, git push seul suffit.
git remote -vAffiche l'adresse du serveur relié au projet.
Un push refusé avec « fetch first » veut dire qu'un collègue a poussé avant vous. Faites git pull --rebase, réglez les conflits s'il y en a, puis poussez à nouveau. Forcer le push effacerait son travail.
05Les branches : créer, changer, fusionner
Un sujet, une branche, même quand vous travaillez seul. main reste propre et vous pouvez abandonner une piste sans rien défaire.
git switch -c [branche]Crée une branche et s'y place. git switch main revient sur main.
git merge [branche]Fusionne la branche indiquée dans celle où vous êtes.
git branch -d [branche]Supprime une branche locale déjà fusionnée. git push origin --delete [branche] la supprime sur le serveur.
git switch et git restore sont arrivés avec Git 2.23, en 2019, pour séparer les deux métiers de git checkout. L'ancienne commande marche toujours, et vous la croiserez dans beaucoup de tutoriels.
Un conflit arrive quand deux branches modifient les mêmes lignes. Git écrit les deux versions dans le fichier, entre des marqueurs <<<<<<<, ======= et >>>>>>>. Gardez la bonne version, supprimez les marqueurs, puis git add et git commit. git merge --abort annule la fusion et remet tout comme avant.
06Le rebase, ce qu'il fait
Pendant que vous travaillez sur une branche, main avance. Il y a deux façons de récupérer ses nouveautés.
Le merge ajoute un commit de fusion. Rien n'est réécrit, mais l'historique se ramifie. Le rebase met vos commits de côté, déplace le départ de votre branche au bout de main et rejoue vos commits un par un. L'historique devient une ligne droite. Les commits rejoués sont des copies : même contenu, nouveaux hashes.
git switch
git fetch
git rebase origin/mainLes conflits arrivent commit par commit. Après chaque correction, git add puis git rebase --continue. git rebase --skip abandonne le commit en cours, git rebase --abort annule tout le rebase. Rebaser souvent garde les conflits petits.
07La règle d'or, et le push d'après
Ne rebasez que les branches qui n'appartiennent qu'à vous. Jamais main, dev, develop, ni la branche d'un collègue : leurs commits changeraient d'identité sous les pieds de toute l'équipe.
Une branche déjà poussée puis rebasée ne correspond plus à sa copie sur le serveur, et un push normal est refusé. Utilisez alors la version prudente du push forcé.
git push --force-with-leaseÉcrase la branche sur le serveur, sauf si quelqu'un y a poussé depuis votre dernier fetch. Dans ce cas, le push est refusé.
Le simple git push --force n'a pas ce garde-fou. Beaucoup d'équipes protègent d'ailleurs main et les branches partagées : le serveur y refuse tout push forcé.
08Le rebase interactif : nettoyer avant de montrer
Avant d'ouvrir une demande de fusion (pull request ou merge request), vous pouvez réécrire vos propres commits : regrouper les « wip », corriger un message, en supprimer un.
git rebase -i origin/main
Git ouvre la liste de vos commits dans l'éditeur. Remplacez le mot en début de ligne, enregistrez, fermez. Changer l'ordre des lignes change l'ordre des commits.
| Mot | Effet |
|---|---|
pick | Garde le commit tel quel. |
reword | Garde le commit et vous laisse modifier son message. |
squash | Fond le commit dans le précédent et réunit les deux messages. |
fixup | Fond le commit dans le précédent et jette son message. |
drop | Supprime le commit. |
edit | S'arrête sur le commit pour que vous le modifiiez. |
Pour le seul dernier commit, git commit --amend suffit. Pour corriger un commit plus ancien, marquez la correction avec git commit --fixup [hash], puis lancez git rebase -i --autosquash origin/main : Git range et fond tout seul.
Regardez comment l'équipe fusionne les demandes. Si elle les fusionne en un seul commit (squash merge), votre nettoyage disparaît à la fusion, et c'est le titre de la demande qui compte.
09Merge ou rebase : qui choisit
| Méthode | Ce qu'elle donne |
|---|---|
| Merge | Historique ramifié avec des commits de fusion. Les conflits se règlent une fois. Rien n'est réécrit. Pour retirer la fonctionnalité, un seul git revert sur le commit de fusion. |
| Rebase | Historique en ligne droite. Les conflits se règlent commit par commit. L'historique est réécrit, donc jamais sur une branche partagée. Retirer la fonctionnalité demande un revert par commit. |
| Squash merge | Fait au moment de la demande de fusion : un seul commit par fonctionnalité sur main. Les commits de la branche n'y figurent plus. Un seul revert suffit à la retirer. |
Une pratique répandue : rebaser sa branche chaque jour sur la branche de départ pour rester à jour, et laisser l'outil de demande de fusion appliquer la règle de l'équipe. Si l'équipe en a fixé une autre, c'est la sienne qui compte.
10Réparer : les commandes qui sauvent
| Vous voulez | Tapez |
|---|---|
| Annuler vos modifications d'un fichier | git restore [fichier] |
| Retirer un fichier de la zone d'attente | git restore --staged [fichier] |
| Corriger le message du dernier commit | git commit --amend -m "…" |
| Ajouter un oubli au dernier commit | git add [fichier] puis git commit --amend --no-edit |
| Défaire le dernier commit et garder le travail | git reset --soft HEAD~1 |
| Tout jeter jusqu'au dernier commit | git reset --hard, le travail non commité est perdu |
| Annuler un commit déjà poussé | git revert [hash], qui ajoute un commit inverse |
| Changer de branche avec du travail en cours | git stash, puis git stash pop au retour |
| Revenir avant une fausse manœuvre | git reflog, puis git reset --hard HEAD@{n} |
git reset a trois niveaux. --soft défait le commit et laisse les changements dans la zone d'attente. --mixed, le niveau par défaut, les laisse dans le dossier. --hard les supprime.
Le reflog est le journal local de tous les endroits où HEAD est passé. Un commit qui n'apparaît plus dans aucune branche y reste 30 jours par défaut, les autres entrées 90 jours (documentation de git reflog). Avant une opération risquée, posez une étiquette de secours avec git branch sauvegarde, et supprimez-la une fois tranquille.
11Chaque équipe a son workflow
Un workflow répond à deux questions : de quelle branche part la vôtre, et par où une fonctionnalité arrive en production. Quatre familles reviennent souvent.
| Famille | Principe |
|---|---|
| Trunk-based | Des branches très courtes, fusionnées dans main le jour même. Ce qui n'est pas fini reste caché derrière un interrupteur (feature flag). Courant quand on déploie plusieurs fois par jour. |
| GitHub flow | Une branche par sujet, une demande de fusion relue, la fusion dans main, puis le déploiement. Courant en startup et en open source. |
| Git flow | Les branches main et develop, plus feature/…, release/… et hotfix/…, avec des tags de version. Adapté aux logiciels livrés par versions. |
| Branches d'environnement | dev, int, main : une branche par serveur, et les fonctionnalités montent d'étage en étage. Fréquent dans les grandes entreprises et les ESN. |
Pour aller plus loin : l'article d'origine de Git flow, dont l'auteur conseille depuis un modèle plus simple pour les applications web déployées en continu, la page de GitHub sur GitHub flow et trunkbaseddevelopment.com.
12main, int, dev : faire monter une fonctionnalité
Avec des branches d'environnement, dev reçoit tout ce qui est en cours et sert à l'intégration, souvent instable. int sert à la recette. main est la production. Les noms changent d'une équipe à l'autre : develop, recette, staging, preprod, master ou prod.
Votre branche part en général de dev. Avant la demande de fusion vers dev, rebasez-la sur origin/dev. Le passage de dev à int, puis à main, se fait le plus souvent par demande de fusion ou par la chaîne d'intégration continue.
git switch dev git pull git switch -c feature/[JIRA-123-panier] # … commits … git fetch git rebase origin/dev git push -u origin feature/[JIRA-123-panier]
13Le cherry-pick : faire passer une seule fonctionnalité
La recette n'a validé qu'une fonctionnalité sur trois présentes dans dev. Fusionner dev dans int emporterait les trois. git cherry-pick recopie les changements d'un commit sur la branche où vous êtes, sous la forme d'un nouveau commit.
git fetch git log origin/dev --oneline --grep="[JIRA-123]" git switch int git pull git cherry-pick -x [hash] git push
L'option -x ajoute au message la référence du commit d'origine : gardez-la toujours. Pour une suite de commits, git cherry-pick -x [A]^..[B] copie de A à B inclus, du plus ancien au plus récent. En cas de conflit : corrigez, git add, puis git cherry-pick --continue, ou --abort pour renoncer.
Si int est protégée, créez une branche à partir d'elle, par exemple pick/JIRA-123-vers-int, faites-y le cherry-pick et ouvrez une demande de fusion. Une fonctionnalité fusionnée en un seul commit (squash) se copie bien plus facilement qu'une série.
Le commit existe désormais deux fois, avec deux hashes. Si le même code change ensuite des deux côtés, une fusion future peut donner un conflit. Notez dans le ticket les commits copiés et leur destination.
14Le hotfix : réparer la production sans embarquer dev
Un bug bloque la production. Partez de main, pas de dev : sinon le correctif emporte avec lui des fonctionnalités pas encore validées.
git switch main git pull git switch -c hotfix/[paiement-en-double] # … correction, commit … git push -u origin hotfix/[paiement-en-double]
Ouvrez ensuite la demande de fusion vers main. Une fois le correctif en production, redescendez-le dans dev, avec git cherry-pick -x [hash] ou en fusionnant origin/main. Si vous l'oubliez, le bug revient à la livraison suivante. En Git flow, le hotfix est fusionné dans main et dans develop.
15Marquer une version : les tags
Un tag est une étiquette fixe sur un commit, par exemple v1.4.0. La convention la plus courante, le versionnage sémantique, suit la forme vMAJEUR.MINEUR.CORRECTIF.
git tag -a v1.4.0 -m "Version 1.4.0" git push origin v1.4.0
Un git push ordinaire n'envoie pas les tags : il faut les nommer, ou ajouter --tags pour tous les envoyer (documentation de git push). git tag les liste. git switch --detach v1.3.2 vous place sur une ancienne version pour la consulter. Pour y corriger un bug, créez une branche à cet endroit avec git switch -c.
16Premier jour dans une équipe : huit questions
- De quelle branche part une nouvelle fonctionnalité ?
- Comment nomme-t-on les branches ?
- Les messages de commit suivent-ils un format ?
- Les demandes de fusion sont-elles fusionnées en merge, en rebase ou en squash ?
- Pour me mettre à jour, je rebase ma branche ou j'y fusionne la base ?
- Qui fait monter dev vers int puis main, et à quel moment ?
- Quelles branches sont protégées, et où puis-je pousser directement ?
- Comment se passe un hotfix, et qui le redescend ?
Une partie des réponses se lit dans le dépôt lui-même. Posez les autres la première semaine et gardez-les dans un fichier.
git branch -r git log --oneline --graph --all -30 git log origin/main --oneline -15
17Les pièges
- Un
git add .sans regarder. Un.envou un dossier de build part sur le serveur. Nommez les fichiers, passez pargit add -pet écrivez le.gitignoreen premier. - Forcer un push refusé. Le travail d'un collègue disparaît du serveur. Faites
git pull --rebase, puis poussez. - Rebaser une branche partagée. Toute l'équipe se retrouve avec un historique qui ne correspond plus. Le rebase se limite à vos branches.
- Croire qu'un
reset --hardest sans retour. Ce qui a été commité reste dans le reflog. Ce qui ne l'a jamais été est perdu : commitez souvent. - Travailler directement sur
main. Une branche par sujet, même pour une petite correction. - Garder une branche ouverte des semaines. Les conflits grossissent chaque jour. Rebasez quotidiennement et gardez des demandes de fusion courtes.
- Effacer un secret de l'historique et s'arrêter là. Il a pu être cloné entre-temps. Changez-le immédiatement.
18L'antisèche
| Moment | Commandes |
|---|---|
| Démarrer | git clone [url] · git init · git remote add origin [url] · git config --global user.email … |
| Tous les jours | git status · git diff · git diff --staged · git add -p · git commit -m "…" · git log --oneline --graph |
| Serveur | git fetch · git pull --rebase · git push -u origin [branche] · git push --force-with-lease |
| Branches | git switch -c [branche] · git switch [branche] · git merge [branche] · git branch -d [branche] |
| Rebase | git rebase origin/main · git rebase -i origin/main · git rebase --continue · git rebase --abort · git commit --fixup [hash] |
| Réparer | git restore [fichier] · git commit --amend · git reset --soft HEAD~1 · git revert [hash] · git stash · git reflog |
| Équipe | git cherry-pick -x [hash] · git cherry-pick -x A^..B · git tag -a v1.4.0 -m "…" · git push origin v1.4.0 |
Cette fiche reprend le plan de la masterclass Git de DeviensDev. La référence complète de chaque commande se trouve dans la documentation officielle de Git.
Les autres ressources
Envie d'un parcours structuré ?
Ces ressources montrent notre façon de travailler. Pour apprendre étape par étape et appliquer à vos propres projets, Flow Buster propose des formations professionnelles à Bordeaux, en présentiel ou à distance.