🎯 Ce que cet article apprend
- Structurer un dépôt Odoo type avec submodules OCA et
.gitignorecomplet - Maîtriser le workflow quotidien : branches feature,
stash,rebase, résolution de conflit sur__manifest__.py - Contribuer à un dépôt OCA via fork, draft PR et
ghCLI
Cet article est l'épisode 2/5 de la série S01 — Boîte à outils Linux du dev Odoo. L'épisode précédent a posé les fondamentaux Linux. La présente section enchaîne sur Git et GitHub. Les commandes présentées sont valables sur la version finale Odoo 19 (release 2025-10), aucun breaking change Git n'ayant été introduit avec la v19.
1. Premier clone — sources Odoo et addons custom
Une sandbox Odoo 19 se structure en trois dépôts distincts : le cœur Odoo, les addons custom de l'intégrateur, et la collection OCA. Trois commandes suffisent à amorcer la machine.
# Clone shallow d'Odoo 19 (--depth=1 = 1 seul commit, gain ~3 Go vs full)
git clone --depth=1 -b 19.0 git@github.com:odoo/odoo.git odoo
# Clone du dépôt addons custom propre à l'intégrateur
git clone git@github.com:adicops/addons-custom.git addons-custom
# Création du répertoire dédié aux submodules OCA (vide pour l'instant)
mkdir -p addons-oca
Le drapeau --depth=1 est essentiel pour le cœur Odoo : un clone complet remonte à 2010 et pèse plus de 3 Go d'historique. Le shallow clone ramène cette taille à quelques centaines de mégaoctets, parfaitement utilisable pour développer. En cas de besoin d'historique complet (bisect, régression), git fetch --unshallow rapatrie le reste à la demande. L'addons_path du odoo.conf énumère ensuite ces trois racines, séparées par des virgules sans espace.
2. Submodules OCA — la mécanique propre
Les modules OCA (Odoo Community Association) se déclarent en submodules Git plutôt qu'en clones séparés. Trois avantages : reproductibilité totale (le commit parent fige un pointeur sur un commit OCA précis), mise à jour explicite, collaboration équipe synchrone. Quatre commandes couvrent le cycle de vie complet.
# Ajouter un submodule OCA sur la branche 19.0
git submodule add -b 19.0 git@github.com:OCA/account-financial-tools.git \
addons-oca/account-financial-tools
# Initialiser tous les submodules après un clone frais (récursif)
git submodule update --init --recursive
# Mettre à jour tous les submodules vers la dernière version de leur branche suivie
git submodule update --remote --merge
# Vérifier les commits actuellement pointés par chaque submodule
git submodule status
L'option -b 19.0 est obligatoire : sans elle, le submodule pointe en detached HEAD sur la branche par défaut (souvent l'avant-dernière version stable). Le drapeau --recursive gère les submodules imbriqués. La commande --remote --merge est celle à lancer en début de session pour rapatrier les fixes upstream de tous les OCA configurés.
📖 Définition — Submodule Git
Un submodule Git n'est pas une copie d'un autre dépôt : c'est un pointeur sur un commit précis d'un dépôt externe, enregistré dans .gitmodules. git submodule status affiche le SHA pointé, ex. 2cb7cce5 addons-oca/account-financial-tools (heads/19.0). Quand le parent est cloné, c'est ce SHA qui est rapatrié — pas la branche flottante. Mécanisme qui garantit qu'à un commit du parent correspond une combinaison reproductible de versions des submodules.
Le fichier .gitmodules généré, versionné dans le dépôt parent :
[submodule "addons-oca/account-financial-tools"]
path = addons-oca/account-financial-tools
url = git@github.com:OCA/account-financial-tools.git
branch = 19.0
⚠️ Piège — Toujours pousser le submodule avant le parent
Quand un fix est appliqué dans un submodule, le pousser en premier, puis seulement ensuite pousser le dépôt parent. L'ordre inverse provoque un échec silencieux : le remote parent référence un commit submodule inexistant côté GitHub, et la CI/CD échoue au git submodule update de déploiement. Réflexe à acquérir : (cd addons-oca/account-financial-tools && git push) puis git push dans le parent. Source : Odoo Docs 19.0 — Submodules.
3. Workflow quotidien — feature branch et commits
Règle d'or : jamais de commit direct sur main ou 19.0. Chaque correctif vit sur une branche dédiée, nommée par préfixe sémantique. Cinq commandes structurent la journée type.
# Créer et basculer sur une branche feature dédiée
git checkout -b feature/sale-discount-fix
# Ajout interactif ligne par ligne — éviter le 'git add .' aveugle
git add -p
# Commit avec préfixe sémantique OCA-style
git commit -m "[FIX] sale: discount applied twice on confirmation"
# Pousser la branche avec tracking remote (-u définit la cible une fois pour toutes)
git push -u origin feature/sale-discount-fix
# Récupérer 19.0 sans polluer l'historique avec des merge commits parasites
git pull --rebase origin 19.0
L'option -p (forme abrégée de --patch) est l'outil le plus sous-utilisé du workflow. Elle propose chaque modification hunk par hunk avec validation interactive (y valider, n ignorer, s découper, q quitter). Bénéfice direct : un commit ne contient que les modifications voulues, jamais une ligne print() de debug ou un fichier .idea/ oublié.
Le préfixe [FIX], [ADD], [IMP], [REF], [REM] est la convention OCA. Structure recommandée : [PREFIX] module_name: courte description impérative en première ligne (50 caractères max), ligne vide puis corps explicatif si nécessaire. Convention obligatoire pour l'acceptation des PR sur les dépôts OCA officiels.
Sur la dernière commande, --rebase est crucial : un simple git pull crée un merge commit à chaque synchronisation, polluant l'historique linéaire. Le rebase rejoue les commits locaux par-dessus la pointe distante — qualité attendue pour une PR mergeable proprement.
4. Stash, log, diff — naviguer dans l'historique
Le développeur Odoo bascule régulièrement entre branches pour traiter un fix urgent au milieu d'une feature. Le stash sert à cela. Quatre commandes complètent l'arsenal d'inspection.
# Mettre de côté un work-in-progress (working tree + index)
git stash
# Reprendre le stash le plus récent et le retirer de la pile
git stash pop
# Visualisation propre du graph de tous les branches/refs
git log --oneline --graph --decorate --all
# Delta entre HEAD et son parent immédiat (utile en revue de commit)
git diff HEAD~1
# Inspection complète d'un commit donné (message + stat + patch)
git show 042ec33
Séquence type : git stash sauvegarde le WIP → bascule sur la branche de fix → application du correctif → retour sur la feature → git stash pop restaure le travail. git stash list liste les sauvegardes empilées (stash@{0}, stash@{1}, etc.).
git log --oneline --graph --decorate --all affiche l'arborescence complète des branches d'un dépôt Odoo. La colonne de gauche dessine le graphe, le SHA court vient ensuite, puis les pointeurs (HEAD, branches locales et distantes) entre parenthèses, et enfin le message. Visualisation indispensable avant tout rebase ou merge non trivial.L'expression HEAD~1 désigne le parent immédiat ; HEAD~3 remonte trois commits. git diff HEAD~1 est précieuse en fin de session pour relire le dernier commit avant de pousser. git show <SHA> accepte sept caractères du SHA — quatre suffisent en l'absence d'ambiguïté.
💡 Astuce — Une commande pour synchroniser tous les OCA
git submodule update --remote --merge met à jour tous les submodules en une passe, en rapatriant les derniers commits de la branche suivie. À combiner avec un alias Bash (alias ocaup='git submodule update --remote --merge') pour en faire un réflexe matinal. Pour limiter à un seul submodule, ajouter le chemin en argument.
5. Résoudre un conflit basique
Le conflit Git le plus fréquent côté Odoo intervient sur __manifest__.py, quand deux développeurs incrémentent simultanément la version sur deux branches. La résolution se déroule en quatre étapes.
# Tentative de merge qui échoue
$ git merge feature/a
Fusion automatique de __manifest__.py
CONFLIT (contenu) : Conflit de fusion dans __manifest__.py
La fusion automatique a échoué ; réglez les conflits et validez le résultat.
# 1. Identifier le ou les fichiers en conflit
$ git status
fichiers non fusionnés :
les deux modifiés : __manifest__.py
L'ouverture du fichier en conflit révèle les marqueurs Git qui encadrent chacune des deux versions divergentes :
{
'name': 'Adi Sale Discount',
<<<<<<< HEAD
'version': '19.0.2.0.0',
=======
'version': '19.0.1.1.0',
>>>>>>> feature/a
'depends': ['sale'],
}
La zone entre <<<<<<< HEAD et ======= contient la version de la branche courante ; celle entre ======= et >>>>>>> feature/a contient la version fusionnée. La résolution consiste à choisir la version correcte (ou fusionner manuellement) puis à supprimer les trois marqueurs. Une fois le fichier propre :
# 2. Marquer le conflit comme résolu
git add __manifest__.py
# 3. Finaliser le merge avec un commit
git commit -m "[MRG] Resolve manifest version conflict"
# 4. (Optionnel) Vérifier qu'aucun marqueur ne subsiste ailleurs
grep -rn "<<<<<<<" .
Le grep final est un garde-fou essentiel : un marqueur oublié dans un fichier Python casse l'import du module au démarrage d'Odoo, avec une SyntaxError parfois difficile à diagnostiquer. En cas de doute en cours de résolution, git merge --abort annule la fusion et revient à l'état d'avant git merge.
6. GitHub — fork, PR, draft, review
La contribution à un dépôt OCA suit la mécanique standard fork → branch → PR, accélérée par le gh CLI officiel. Une fois gh auth login exécuté une fois pour toutes, quatre commandes couvrent le parcours complet.
# Authentification one-time (token stocké chiffré dans ~/.config/gh/)
gh auth login
# Fork du dépôt OCA dans son propre compte GitHub
gh repo fork OCA/account-financial-tools --clone=false
# Création d'une pull request en mode draft (= non prête pour review)
gh pr create --draft -t "[FIX] account: discount applied twice" \
-b "Closes #1234. Fix discount calculation in confirmation flow."
# Inspection de l'état des checks CI sur sa PR
gh pr checks
# Approuver une PR ouverte par un autre contributeur
gh pr review --approve
Le mode --draft est la norme OCA : signale un code encore en cours, ne sollicite pas les mainteneurs, mais lance la CI. Une fois les tests verts, gh pr ready bascule en ready for review et notifie les codeowners. Discipline explicitement attendue par les guidelines de contribution OCA pour ne pas saturer les reviewers.
🔧 Encadré pratique — gh repo clone, la voie la plus rapide
gh repo clone OCA/account-financial-tools -- -b 19.0 est la forme la plus rapide pour cloner une branche précise d'un dépôt OCA. Avantages par rapport au git clone classique : aucune configuration SSH (le gh CLI utilise le token GitHub déjà authentifié), branche pré-sélectionnée via -- qui transmet le drapeau au git clone sous-jacent, complétion automatique du nom. Utilisable aussi sur les forks personnels et dépôts privés d'organisation.
7. .gitignore Odoo type
Un .gitignore mal calibré laisse traîner caches Python, credentials, filestore et configs IDE dans le dépôt. Le bloc ci-dessous est la base minimale pour un projet Odoo 19, compatible avec les conventions Odoo.sh.
# Odoo runtime
__pycache__/
*.pyc
*.pyo
.odoorc
# Filestore (jamais versionné — sauvegardé séparément)
filestore/
sessions/
# Logs
*.log
# Secrets (credentials DB, clés SMTP, tokens)
.env*
odoo.conf
# Cœur Odoo cloné séparément
/odoo/
# IDE
.idea/
.vscode/
*.swp
# Bases locales (rare en Odoo mais possible)
*.sqlite
# OS
.DS_Store
Thumbs.db
Trois entrées méritent justification. odoo.conf contient le mot de passe PostgreSQL et l'admin_passwd : sa présence en dépôt public est une fuite de credentials majeure. /odoo/ (avec slash initial) cible le cœur Odoo cloné à la racine du projet — il vit dans son propre clone. Quant à filestore/, son volume (plusieurs gigaoctets) et sa nature binaire le rendent incompatible avec Git.
8. Bonus — cinq alias .gitconfig productifs
Les alias Git se déclarent dans ~/.gitconfig sous la section [alias]. Cinq alias suffisent à transformer le confort quotidien d'un dev Odoo.
# ~/.gitconfig
[alias]
lg = log --oneline --graph --decorate --all
st = status -sb
co = checkout
br = branch -vv
amend = commit --amend --no-edit
lg remplace quatre options par deux lettres ; st affiche un statut compact avec branche et tracking remote sur la première ligne ; co raccourcit git checkout (couvre aussi le détachement de fichiers, là où git switch ne le fait pas) ; br liste les branches avec leur tracking distant ; amend ajoute l'index au dernier commit sans rouvrir l'éditeur — précieux pour les détails oubliés juste après un commit.
9. Les 20 commandes en synthèse
Table récapitulative des vingt commandes Git et GitHub plus des cinq alias bonus. Mémoriser le cas d'usage permet de retrouver la commande sans hésiter.
| # | Cas d'usage | Commande |
|---|---|---|
| 1 | Clone shallow d'Odoo 19 | git clone --depth=1 -b 19.0 git@github.com:odoo/odoo.git |
| 2 | Clone d'un dépôt addons custom | git clone git@github.com:adicops/addons-custom.git |
| 3 | Ajouter un submodule OCA | git submodule add -b 19.0 git@github.com:OCA/account-financial-tools.git addons-oca/account-financial-tools |
| 4 | Initialiser tous les submodules | git submodule update --init --recursive |
| 5 | Mettre à jour tous les submodules | git submodule update --remote --merge |
| 6 | Vérifier les commits submodules | git submodule status |
| 7 | Créer une branche feature | git checkout -b feature/sale-discount-fix |
| 8 | Ajout interactif ligne par ligne | git add -p |
| 9 | Commit avec préfixe OCA | git commit -m "[FIX] sale: ..." |
| 10 | Pousser avec tracking remote | git push -u origin feature/... |
| 11 | Pull rebasé sans merge commit | git pull --rebase origin 19.0 |
| 12 | Mettre de côté un WIP | git stash |
| 13 | Reprendre le stash récent | git stash pop |
| 14 | Visualiser le graph des branches | git log --oneline --graph --decorate --all |
| 15 | Delta avec le commit précédent | git diff HEAD~1 |
| 16 | Inspection complète d'un commit | git show <SHA> |
| 17 | Authentification GitHub CLI | gh auth login |
| 18 | Forker un dépôt OCA | gh repo fork OCA/account-financial-tools |
| 19 | Créer une PR en mode draft | gh pr create --draft -t "..." -b "..." |
| 20 | État des checks CI sur sa PR | gh pr checks |
| B1 | Alias graph complet | lg = log --oneline --graph --decorate --all |
| B2 | Alias statut court | st = status -sb |
| B3 | Alias checkout | co = checkout |
| B4 | Alias branches verboses | br = branch -vv |
| B5 | Alias amend silencieux | amend = commit --amend --no-edit |
Pour ancrer ces commandes en mémoire musculaire : créer dès maintenant le fichier ~/odoo-cheatsheet.md (cf. recommandation finale de l'épisode S01 Linux), y coller cette table, et installer les cinq alias .gitconfig. Au bout de deux semaines, les douze plus utilisées passent en réflexe. L'épisode S03 — Bash enchaîne sur l'automatisation : cinq scripts qui transforment ces commandes Git en routines déclenchées en un mot.
Voir aussi dans la série
S01 — Linux : 30 commandes pour la sandbox
logs, processus, ports, permissions, systemd, alias .bashrc.
S02 — Git & GitHub : 20 commandes pour cloner, brancher, contribuer
clone shallow, submodules OCA, workflow feature-branch, PR via gh.
S03 — Bash : 5 scripts qui font gagner 1 heure par jour
start-odoo.sh, restore-db.sh, dump-and-clean.sh, install-and-test.sh, update-all-addons.sh.
S04 — odoo-bin shell : 15 patterns ORM essentiels
env, search_fetch v19, Domain, flush_model / invalidate_model.
S05 — PostgreSQL : psql, SELECT, dump propre
Requêtes psql, EXPLAIN ANALYZE, garde-fous UPDATE / DELETE, CTA E3.
Articles complémentaires
#54 — Configurer l'environnement de développement Odoo 19
Setup de la sandbox — avant le premier git clone sur Odoo.
#90 — Sécuriser Odoo 19 en production
Déploiement Nginx, SSL, VPS — l'aval du workflow Git côté production.