Aller au contenu

Git avancé : sécurité et configuration

Un commit porte un nom et un e-mail déclaratifs : n’importe qui peut en écrire d’autres. Une signature prouve que le commit vient bien de la personne qui détient la clé.

Fenêtre de terminal
ssh-keygen -t ed25519 -f ~/.ssh/id_signature -C "signature git" # voir « SSH : clés »
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_signature.pub
git config --global commit.gpgsign true
git config --global tag.gpgSign true

Pour vérifier localement les signatures SSH, un fichier des signataires autorisés :

Fenêtre de terminal
echo "alice@exemple.com $(cat ~/.ssh/id_signature.pub)" >> ~/.config/git/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.config/git/allowed_signers
git log --show-signature -3
git verify-commit HEAD

Ajouter ensuite la clé publique de signature dans le profil du serveur (Gitea : paramètres du compte, clés SSH/GPG, usage « signature ») pour obtenir la mention Vérifié sur les commits. Voir SSH : clés.

Fenêtre de terminal
sudo apt install gnupg
gpg --full-generate-key # ed25519 recommandé, durée de validité
gpg --list-secret-keys --keyid-format=long
git config --global user.signingkey <IDENTIFIANT_DE_CLE>
git config --global commit.gpgsign true
git commit -S -m "feat: signé"
export GPG_TTY=$(tty) # nécessaire pour la saisie de la phrase secrète dans un terminal
SSH GPG
Mise en place Réutilise l’outillage SSH Installation et gestion d’un trousseau
Révocation, expiration Limitées Complètes
Pour un usage individuel ou d’équipe réduite Recommandé Si l’organisation l’exige

La signature n’est utile que si elle est vérifiée (serveur, politique de branche) ; sinon c’est un simple décor.

Retirer un fichier de tout l’historique avec git filter-repo (outil officiellement recommandé, plus sûr que filter-branch) :

Fenêtre de terminal
sudo apt install git-filter-repo
git clone --mirror https://git.exemple.com/depot.git depot-nettoyage.git # copie de travail
cd depot-nettoyage.git
git filter-repo --invert-paths --path config/secrets.env # supprimer un fichier de l'historique
git filter-repo --replace-text <(printf 'MonMotDePasse==>***SUPPRIME***\n') # remplacer un texte partout
git filter-repo --path-glob '*.pem' --invert-paths # tous les fichiers .pem
git push --force --mirror # réécrit le dépôt distant

Conséquences à gérer :

Point Action
Tous les commits changent d’identifiant Chaque contributeur doit reclonner (ne pas fusionner l’ancien historique, qui réintroduirait le secret)
Demandes de fusion ouvertes À recréer
Cache du serveur Demander la purge (Gitea : gitea admin / ramasse-miettes ; plateformes en ligne : support)
Étiquettes Réécrites aussi
Copies existantes Considérer le secret comme compromis

Éviter le problème : hooks de détection de secrets, .gitignore pour .env, analyse en intégration continue.

Fenêtre de terminal
sudo apt install gitleaks # si disponible, sinon binaire officiel
gitleaks detect --source . --redact # analyse l'historique
gitleaks protect --staged --redact # analyse l'index (hook pre-commit)
git log -p | grep -iE "(password|secret|token|api[_-]?key)\s*[:=]" # recherche sommaire
Niveau Fichier Portée
Système /etc/gitconfig Tous les utilisateurs
Global ~/.gitconfig (ou ~/.config/git/config) Un utilisateur
Local .git/config Un dépôt
Fenêtre de terminal
git config --list --show-origin
git config --global --edit
git config user.email # valeur effective
git config --unset user.email

Le niveau le plus précis l’emporte (local > global > système).

Fenêtre de terminal
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global fetch.prune true
git config --global push.autoSetupRemote true
git config --global rebase.autoStash true
git config --global rebase.autoSquash true
git config --global rebase.updateRefs true
git config --global merge.conflictStyle zdiff3
git config --global rerere.enabled true
git config --global diff.algorithm histogram
git config --global diff.colorMoved default
git config --global commit.verbose true
git config --global branch.sort -committerdate
git config --global tag.sort version:refname
git config --global help.autocorrect prompt
git config --global core.editor "nano"
git config --global core.pager "less -FRX"
git config --global column.ui auto

Certains réglages dépendent de la version de Git : git config ne signale pas toujours une clé inconnue ; vérifier avec git config --get <clé> et la documentation de la version installée.

Utiliser une identité différente selon le dossier (personnel et professionnel) :

~/.gitconfig
[user]
name = Alice Martin
email = alice@exemple.com
[includeIf "gitdir:~/projets/travail/"]
path = ~/.gitconfig-travail
[includeIf "hasconfig:remote.*.url:git@git.entreprise.example:**"]
path = ~/.gitconfig-travail
~/.gitconfig-travail
[user]
email = alice.martin@entreprise.example
signingkey = ~/.ssh/id_travail.pub

La première règle s’applique aux dépôts situés sous ~/projets/travail/, la seconde à ceux dont l’adresse distante correspond (selon la version de Git). Évite d’utiliser par erreur une adresse e-mail personnelle sur un projet professionnel.

Fenêtre de terminal
git config --global alias.st "status -sb"
git config --global alias.co "switch"
git config --global alias.br "branch -vv"
git config --global alias.lg "log --graph --oneline --decorate --all -30"
git config --global alias.dernier "log -1 --stat"
git config --global alias.annuler "reset --soft HEAD~1"
git config --global alias.fixup "commit --fixup"
git config --global alias.nettoyer '!git fetch --prune && git branch --merged main | grep -v "main" | xargs -r git branch -d'

Un alias commençant par ! exécute une commande shell. Choisir des alias qui ne masquent pas les noms des commandes habituelles : un alias dangereux (git config alias.push "push --force") cause des accidents.

* text=auto eol=lf
*.sh text eol=lf
*.bat text eol=crlf
*.png *.jpg *.pdf binary
package-lock.json -diff merge=binary
*.min.js -diff
docs/** linguist-documentation
CHANGELOG.md merge=union
Attribut Rôle
text=auto eol=lf Fins de ligne normalisées (lf) : plus de fichiers « modifiés » à cause de crlf
binary Ne pas comparer ni fusionner comme du texte
-diff Ne pas afficher le contenu dans git diff (fichiers générés)
merge=union Fusion en conservant les lignes des deux côtés
export-ignore Exclure de git archive
filter=lfs Git LFS (Gros dépôts et sous-projets)

Après modification : git add --renormalize ..

Fenêtre de terminal
git config --global credential.helper cache --timeout=3600 # mémoire pendant 1 h
git config --global credential.helper store # fichier en CLAIR (déconseillé)
git config --global credential.helper libsecret # trousseau du système (bureau)
git remote set-url origin git@git.exemple.com:equipe/projet.git # passer en SSH
Méthode Conseil
Clé SSH Recommandé : pas de mot de passe réutilisable (SSH : clés)
Jeton d’accès (HTTPS) Droits minimaux, durée limitée, stocké par un assistant d’identifiants (pas dans l’URL)
credential.helper store Mot de passe en clair dans ~/.git-credentials : à éviter

Ne jamais mettre un jeton dans l’adresse distante (https://jeton@…) : il resterait dans .git/config et l’historique du shell.

Sujet Réglage
fatal: detected dubious ownership in repository Le dépôt appartient à un autre utilisateur : git config --global --add safe.directory /chemin/du/depot (seulement pour un dépôt de confiance)
Exécution de code par un dépôt cloné Les hooks et les filtres d’un dépôt inconnu peuvent exécuter des commandes : ne pas lancer git de confiance dans un dépôt non vérifié avec des droits élevés
transfer.fsckObjects git config --global transfer.fsckObjects true : vérifier l’intégrité à la réception
Protocoles protocol.file.allow user : limiter les protocoles de sous-modules
Poussées forcées Branches protégées sur le serveur

Les hooks locaux (pre-commit, commit-msg, pre-push) se gèrent avec Husky ou core.hooksPath :

Fenêtre de terminal
git config core.hooksPath .githooks

Voir Husky : installation et Husky : hooks Git natifs. Côté serveur, les protections de branche et les vérifications de la CI font autorité.

Symptôme Piste
error: gpg failed to sign the data GPG_TTY non défini, agent GPG arrêté (gpgconf --kill gpg-agent), clé introuvable
Commits « Non vérifié » sur le serveur Clé de signature absente du profil, ou adresse e-mail différente de celle de la clé
error: Load key … invalid format (signature SSH) Mauvais chemin : user.signingkey doit pointer vers la clé publique .pub
filter-repo : Refusing to destructively overwrite repo history Travailler sur un clone frais (--mirror) ou ajouter --force en connaissance de cause
Le secret réapparaît après la réécriture Un collègue a repoussé l’ancien historique : reclonage obligatoire
Une option de configuration est ignorée Version de Git trop ancienne ; git config --get <clé> ; orthographe
Fins de ligne qui changent .gitattributes (* text=auto eol=lf), git add --renormalize .
Permission denied (publickey) Clé SSH non chargée (ssh-add -l) ou non enregistrée sur le serveur

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Les versions de Git diffèrent : certains réglages récents (zdiff3, rebase.updateRefs, push.autoSetupRemote, branch.sort) demandent des versions récentes ; git --version et git config --get <clé> permettent de vérifier. Les paquets git-lfs, git-filter-repo et gnupg sont disponibles dans les dépôts d’Ubuntu. Sur 26.04, sudo est fourni par sudo-rs (sans effet sur Git).