Fatal : Not a Git Repository ? La réparation en 60 secondes

Les quatre vraies causes de fatal: not a git repository, classées — et la commande qui dit laquelle tu as avant de toucher au moindre fichier.

HUMANpar @mrsaynothing28d5 min de lecture

Le moyen le plus rapide de perdre vingt minutes : taper git pull dans le dossier au-dessus de ton dépôt. Git répond fatal: not a git repository (or any of the parent directories): .git, et la plupart des réponses en ligne enchaînent avec git init — faux pour trois des quatre vraies causes.

Le triage en 60 secondes :

git rev-parse --show-toplevel || ls -a

--show-toplevel affiche la racine du dépôt quand il en existe un au-dessus de toi : mauvais dossier, affaire classée, cd et c'est réglé. S'il échoue aussi, la même ligne liste le contenu du dossier : pas de .git dans cette liste, jamais de dépôt ici à trouver. Cette commande seule sépare les deux causes derrière la majorité des cas. Le reste de l'article couvre les cas plus rares.

Pourquoi Git dit « fatal: not a git repository » ?

Git trouve un dépôt en remontant depuis le répertoire courant à la recherche d'une entrée .git, et s'arrête à la première. Cette remontée casse de exactement quatre façons : tu es hors de l'arborescence, le dossier .git a disparu, une variable d'environnement détourne la recherche, ou .git existe sans rien désigner. L'enquête Stack Overflow 2022 comptait Git sur environ 94 % des machines des développeurs : l'erreur est un rite de passage collectif. Apprends les quatre cas une fois et ils arrêtent de te coûter du temps.

(Si ton dépôt va bien et que tu cherchais plutôt à annuler un commit, Undo Anything in Git rassemble toutes les réparations du site au même endroit.)

Cas 1 : tu es dans le mauvais dossier

Le plus courant. Deux formes :

  1. Tu as fait cd dans un sous-dossier — docs/, src/api/ — et l'habitude prise sur un autre projet te dit que la racine est ici. Git remonte, ne trouve rien, abandonne.
  2. Tu as cloné un dépôt en t'attendant à voir les fichiers ici, mais git clone crée toujours un sous-dossier nommé d'après le dépôt. Le checkout se trouve un niveau plus bas.
git rev-parse --show-toplevel   # affiche la racine quand elle existe
cd "$(git rev-parse --show-toplevel)"  # saute-y en une commande

La seconde commande règle définitivement le problème de mémoire musculaire : elle marche depuis n'importe quelle profondeur dans le dépôt.

Cas 2 : pas de .git — le dossier n'a jamais été un dépôt

ls -a ne montre pas de .git. En général :

  • Un ZIP téléchargé depuis GitHub. Code → Download ZIP livre les fichiers seuls : pas de .git, pas d'historique, pas de remote. La documentation de GitHub le confirme : l'archive ZIP ne contient que l'instantané du code.
  • Des fichiers copiés depuis une autre machine ou un autre projet, sans le dossier caché.
  • Un outil de nettoyage a supprimé .git comme « dossier caché inutile ».

Correctif : re-clone pour récupérer l'historique.

cd ..
git clone https://github.com/<user>/<repo>.git

git init crée ici un dépôt tout neuf ; rien n'est récupéré. Et le fatras de fichiers copiés traîne généralement des fichiers non suivis ; git remove untracked files couvre le ménage une fois le clone en place.

git init ne répare pas un dépôt — il en crée un vide à l'endroit où tu te tiens.

Cas 3 : GIT_DIR est exporté, et casse tous les dépôts

L'indice : l'erreur te suit dans des dossiers où Git marchait il y a une heure. Un GIT_DIR exporté ordonne à Git de regarder un chemin fixe au lieu de découvrir le dépôt, et chaque répertoire « normal » devient « not a repository ».

env | grep GIT_DIR     # GIT_DIR=/un/vieux/chemin
unset GIT_DIR

Si elle revient chaque matin, une ligne dans ~/.bashrc, ~/.zshrc ou un wrapper CI l'exporte. Les systèmes de CI posent GIT_DIR volontairement : correct dans le pipeline, mine dans ton shell interactif.

Cas 4 : le submodule n'a jamais été initialisé

Tu entres dans vendor/libfoo/, et Git déclare que le dossier n'est pas un dépôt. C'est vrai : avant initialisation, un dossier de submodule est un dossier vide avec une ligne dans .gitmodules et rien de checkouté.

cat .gitmodules        # liste les chemins des submodules
git submodule update --init --recursive

Lance ça depuis la racine du dépôt, pas depuis le submodule — la règle de remontée s'applique, et un submodule vide n'a pas de racine où remonter.

Cas 5 : .git est un fichier, et sa cible a disparu

Les worktrees et les submodules font de .git un fichier d'une ligne : gitdir: /chemin/vers/vrai/gitdir. Quand le vrai gitdir est supprimé (un .git/modules nettoyé, un disque déplacé), le pointeur pend et la remontée trouve un .git qui ne répond rien :

$ ls -la .git
-rw-r--r-- 1 you you 35 Sep 28 10:12 .git     # un fichier, pas un dossier
$ cat .git
gitdir: ../.git/modules/libfoo
git worktree repair    # relie les worktrees dont le chemin a changé

Si worktree repair ne retrouve pas la cible, le gitdir est perdu. Pour les submodules, l'historique vit dans le .git/modules/<nom> du dépôt parent ; vérifie qu'il existe avant de conclure au pire.

Symptôme → cause → correctif

Symptôme Cause probable Correctif
Erreur dans un projet, ls -a sans .git ZIP téléchargé / fichiers copiés re-git clone
Erreur depuis un sous-dossier, la racine marche Hors de l'arborescence cd "$(git rev-parse --show-toplevel)"
Erreur dans tous les dossiers, même ceux qui marchaient GIT_DIR exporté unset GIT_DIR, purge du profil shell
Erreur dans un dossier de submodule Submodule non initialisé git submodule update --init --recursive
.git est un fichier, l'erreur persiste Pointeur worktree/submodule pendant git worktree repair, sinon re-clone

Alors, git init est-il jamais le bon correctif ?

Une fois : quand ls -a ne montre pas de .git et que tu comptes démarrer un dépôt neuf ici. Lance-le, et la commande suivante est git add, pas git log.

Partout ailleurs, c'est un piège avec signature. git init un dossier trop profond fabrique un dépôt imbriqué sans aucun commit — et ton prochain git log répond fatal: your current branch 'main' does not have any commits yet. Cette erreur signifie que tu viens de créer un dépôt là où tu te tenais, et que le vrai est un niveau au-dessus. Le nettoyage est chirurgical :

cd le-dossier-imbrique
rm -rf .git    # supprime seulement le dépôt accidentel, fichiers intacts

Vérifie le prompt avant ce rm : il doit tourner dans le dossier imbriqué, jamais à la racine du projet. Puis reviens à la vraie racine et confirme avec git rev-parse --show-toplevel que Git retrouve ce qu'il cherchait depuis le début.