Developer’s guide
Meso-NH is build upon many contribution since 30 years. As the code is growing and shared with increasing models and contributors, a number of coding norms must be followed.
Branch Management Strategy
Version 1.0 — 2026-05-22
1. General principles
Note for end users: this document targets developers who work directly with Git branches. Users who wish to modify the source code for their own simulations without contributing back to the repository could use the
make usermechanism, which provides an isolated working copy without requiring Git knowledge. A documented pathway frommake userto a proper Git branch exists for modifications that mature into shareable contributions.
MNH-masteraccepts direct pushes for minor changes. Substantial changes go through a Merge Request (MR). See section 8 for the distinction.Release branches are protected against direct writes. Any change must go through an MR or a cherry-pick/merge from a validated commit (from master or another release branch).
Every temporary branch is associated with a GitLab issue. The issue is mandatory whenever a branch is created — the issue number is part of the branch name. The only exception is trivial fixes applied directly on
MNH-masterwithout a dedicated branch.Temporary branches are deleted after merge. They have a limited lifespan and do not accumulate. GitLab can handle this automatically via the “Delete source branch” option in the MR, which is recommended. Otherwise the developer or the maintainer who performs the merge is responsible for deleting the branch.
The stability of
MNH-masteris ensured by collective discipline, not by strict technical protection. The basic rule: if a direct push risks breaking the build for everyone, open an MR.A compilation check is automatically run on all branches at every push and before any merge. More advanced CI policies (non-regression tests, validation) are defined in a dedicated document.
2. Permanent branches
MNH-master
The main branch and the sole convergence point for all developments. It must always be in a compilable and functional state. It is recommended (but not mandatory) to branch off MNH-master when creating all temporary branches, except for bugs specific to a release branch.
Rules:
Direct push allowed for minor changes (see section 8).
Substantial changes go through an MR.
Each release is marked by a tag (see section 7).
Release branches MNH-X-Y
A release branch is created at each minor version release (X.Y.0). It is maintained in parallel with MNH-master for a minimum of 2 years after the release of the next minor version, to receive bug fixes only.
Naming: MNH-X-Y (e.g. MNH-6-0, MNH-6-1)
Dots are replaced by hyphens to avoid ambiguities in shell and Git tools.
Rules:
Direct push forbidden — any change goes through an MR or a cherry-pick.
Only bug fixes may be integrated, never new features.
Note: a performance optimisation may be considered a bug fix if it does not modify simulation results and the changes remain minor; otherwise it is a new development and must be integrated into
MNH-masterfor the next minor version.Fixes applied to a release branch are ported to
MNH-masterand other release branches if necessary (see section 6).
Lifecycle:
Release of Meso-NH 6.1.0
→ creation of tag PACK-MNH-V6-1-0
→ creation of branch MNH-6-1
→ 2-year support starting from the release of version 6.2.0 (bug fixes only)
→ at the end of the support period: archiving (branch set read-only for everyone,
including maintainers, via Settings → Repository → Protected branches)
3. Temporary branches
There are only two types of temporary branches: dev and bug. The presence or absence of a version number in the name immediately indicates the target branch.
Development branches — MNH-dev-{issue}-{title}
For any new feature, refactoring, performance improvement, or any substantial code change.
Recommended starting point: MNH-master. It is possible to start from a release tag (e.g. PACK-MNH-V6-1-0) if the developer prefers a validated and immutable starting point. In that case, the final merge into MNH-master will require integrating all commits made on master since that tag — the longer the branch has lived, the harder this becomes. Regardless of the origin, regular resynchronisation with MNH-master (rebase or merge) is strongly recommended to limit drift.
Merged into: MNH-master via MR
Examples:
MNH-dev-42-turb-new-feature
MNH-dev-67-output-hdf5-12
MNH-dev-103-new-machine
Bug branches on master — MNH-bug-{issue}-{title}
For fixing a bug present on MNH-master (and possibly also present on release branches).
Created from: free starting point (MNH-master (recommended), tag, or release as needed)
Merged into: MNH-master via MR or direct push if the fix is trivial
Then ported to: the affected release branches via cherry-pick (if a single commit) or merge (if multiple interdependent commits). Squashing commits at merge time is recommended to simplify porting.
Examples:
MNH-bug-89-crash-restart-mpi
MNH-bug-94-wrong-pressure-output
Bug branches on release — MNH-X-Y-bug-{issue}-{title}
For fixing a bug present on one or more release branches, but absent from MNH-master.
Important note: if the bug also affects MNH-master, refer to the previous section (no version number in the branch name).
Created from: the affected release branch (e.g. MNH-6-0)
Merged into: that same release branch via MR
Then ported to: the affected release branches via cherry-pick (if a single commit) or merge (if multiple interdependent commits). Squashing commits at merge time is recommended to simplify porting.
Examples:
MNH-6-0-bug-112-bad-cherry-pick-radiation
MNH-6-1-bug-118-segfault-nested-domain
The version number in the name is mandatory in this case: it immediately signals that the branch does not target
MNH-masterand avoids any confusion when runninggit branch -a.
4. Naming convention — summary
Type |
Pattern |
Example |
|---|---|---|
Main branch |
|
|
Release branch |
|
|
Development |
|
|
Bug on master |
|
|
Bug on release |
|
|
Format rules:
Separator: hyphen
-only (no dots, no underscores).Short title: 2 to 4 words, lowercase, separated by hyphens.
The issue number is mandatory for all temporary branches.
No special characters, no spaces.
Immediate reading of a branch name:
Starts with
MNH-dev-→ development, targets master.Starts with
MNH-bug-→ bug fix, targets master.Starts with
MNH-X-Y-bug-→ bug fix, targets release X.Y only.
5. Development workflow
1. Open a GitLab issue describing the feature or improvement.
→ A dedicated issue template for development is not yet available at the time
of publication of this document.
2. Create a branch MNH-dev-{issue}-{title} from MNH-master (or a release tag).
3. Develop, commit regularly with clear messages.
4. Open a Merge Request into MNH-master.
→ Mention "Closes #N" in the description to close the issue automatically.
→ Consider using the "Squash commits" option to produce a single clean commit,
which simplifies the history on MNH-master.
5. If possible, review by at least one other developer.
6. Green CI + approved review → merge into MNH-master.
7. Delete the temporary branch.
6. Bug fix workflow
The starting point is free — what determines the naming is the destination, i.e. whether MNH-master is affected by the bug or not.
Case 1 — Bug present on MNH-master and on release branches
This is the most common case.
1. Open an issue using the bug report template (bug_report), identify the affected versions (e.g. master, 6.0.5, 6.1.0).
2. Create MNH-bug-{issue}-{title} from MNH-master, a tag, or an affected release.
3. Fix the bug.
→ If working directly on MNH-master (no bug branch): direct push if trivial, MR otherwise.
→ If working on a bug branch: MR into MNH-master (direct push not applicable).
4. Port the fix to all affected branches (MNH-master if needed, MNH-6-1, MNH-6-0…)
via cherry-pick (single commit) or merge (multiple interdependent commits).
This is the responsibility of the developer who fixed the bug.
5. Document the fixed versions in the issue before closing it.
GitLab provides a “Cherry-pick” button directly on the merged commit, making the porting straightforward and error-free. If the bug branch contains several commits, it is recommended to squash them when merging (into
MNH-masteror into a release branch) using the GitLab “Squash commits” option, to simplify subsequent porting to other branches. If squashing is not desirable, a direct merge is preferable to multiple individual cherry-picks.
Case 2 — Bug present on MNH-master only
Recent regression, not yet present in any release.
1. If the bug is trivial, apply the fix directly on MNH-master (no issue or branch needed).
2. Otherwise, open an issue and create MNH-bug-{issue}-{title} from MNH-master.
→ No version number in the branch name (master-only bug).
3. Fix the bug, MR or direct push depending on complexity.
4. No cherry-pick needed.
Case 3 — Bug present only on one or more release branches
Regression introduced by a cherry-pick, bug in code already removed from master…
1. Open an issue using the bug report template (bug_report), confirm that master is not affected.
2. Create MNH-X-Y-bug-{issue}-{title} from any affected release branch.
3. Fix the bug, MR into that release branch.
4. Port the fix to other affected releases if needed,
via cherry-pick (single commit) or merge (multiple interdependent commits).
This is the responsibility of the developer who fixed the bug.
5. Document in the issue.
Decision table
Bug present on |
Starting point |
Branch name |
Propagation |
|---|---|---|---|
master + releases |
|
|
Cherry-pick or merge to all affected branches |
master only |
|
|
None |
one or more releases, not master |
any affected release branch |
|
Cherry-pick or merge to all affected releases |
Backport tracking in issues
Each bug issue must explicitly mention:
The affected versions.
The fixed versions as cherry-picks or merge are applied.
GitLab labels should list the Meso-NH version numbers affected by the bug.
8. Branch protection rules
MNH-master — relaxed protection
Direct push is allowed for minor changes. The practical rule:
Direct push acceptable |
Merge Request mandatory |
|---|---|
Typo fix, comment |
New feature |
Trivial fix (a few lines, obvious) |
Refactoring |
Changes to interfaces or namelists |
|
Non-trivial bug fix |
Basic rule: when in doubt, open an MR.
Release branches MNH-X-Y — strict protection
Direct push forbidden. Any change goes through an MR or a cherry-pick/merge from a commit already validated (on master or on another release branch). This strictness is justified by the long lifespan of these branches and their users’ dependency on them.
Recommended GitLab configuration
To be configured in Settings → Repository → Protected branches:
Branch |
Direct push |
Who can push |
Merge |
|---|---|---|---|
|
Allowed |
Developers |
All / Maintainers |
|
Forbidden |
— |
Maintainers only |
|
Forbidden |
— |
No one |
When a release branch reaches the end of its support period, update its protection rule to revoke merge rights from maintainers. This effectively makes the branch fully read-only for everyone.
Release branches must be added explicitly by name, one by one, when created. A wildcard pattern cannot reliably distinguish MNH-6-0 (release) from MNH-6-0-bug-test (bug branch on release), which must remain unprotected. Temporary branches (MNH-dev-*, MNH-bug-*, MNH-X-Y-bug-*) require no protection.
Every MR into a release branch must satisfy:
Green CI (compilation at minimum).
At least one approved review (ideally).
No unresolved conflicts.
Continuous integration policy
A compilation check is the minimum CI requirement and applies to all branches without exception. It is the basic safety net that ensures no push silently breaks the build for the rest of the team.
More advanced testing levels — non-regression tests, physical validation — are not yet fully defined. The intended direction is a three-level funnel:
Level |
Content |
Trigger |
Branches |
|---|---|---|---|
1 — Compilation |
Build with standard gfortran |
Every push |
All |
2 — Quick tests |
Short test cases, basic numerical non-regression |
MR open/update |
|
3 — Full validation |
Complete reference test cases, multiple compilers |
Manual or merge on master/release |
|
The detailed CI policy will be described in a dedicated document when finalised.
[!note] At the time of publication of this document, the CI pipeline was not yet in place.
9. Schematic overview
Developments
%%{init: { 'theme': 'base', 'gitGraph': {'mainBranchName': 'MNH-master', 'parallelCommits': true, 'showCommitLabel': true}} }%%
gitGraph
commit
commit id: "PACK-MNH-V6-1-0" tag: "PACK-MNH-V6-1-0"
branch MNH-dev-42
checkout MNH-dev-42
commit id: "dev-42a"
commit id: "dev-42b"
checkout MNH-master
commit
commit
branch MNH-dev-67
checkout MNH-dev-67
commit id: "dev-67a"
commit id: "resync master"
commit id: "dev-67b"
checkout MNH-master
merge MNH-dev-42
merge MNH-dev-67
commit
Bug fix — from MNH-master
Bug present on master, MNH-6-0 and MNH-6-1.
%%{init: { 'theme': 'base', 'gitGraph': {'mainBranchName': 'MNH-master', 'parallelCommits': true, 'showCommitLabel': true}} }%%
gitGraph
commit
branch MNH-6-0
checkout MNH-6-0
commit
checkout MNH-master
commit
branch MNH-6-1
checkout MNH-6-1
commit
checkout MNH-master
commit
branch MNH-bug-89
checkout MNH-bug-89
commit id: "fix bug #89"
checkout MNH-master
merge MNH-bug-89
checkout MNH-6-1
commit id: "cherry-pick fix #89 for 6-1"
checkout MNH-6-0
commit id: "cherry-pick fix #89 for 6-0"
Bug fix — from a release branch
Bug present on master, MNH-6-0 and MNH-6-1, fix made from MNH-6-1.
%%{init: { 'theme': 'base', 'gitGraph': {'mainBranchName': 'MNH-master', 'parallelCommits': true, 'showCommitLabel': true}} }%%
gitGraph
commit
branch MNH-6-0
checkout MNH-6-0
commit
checkout MNH-master
commit
branch MNH-6-1
checkout MNH-6-1
commit
branch MNH-bug-89
checkout MNH-bug-89
commit
commit id: "fix bug #89"
checkout MNH-6-1
merge MNH-bug-89
checkout MNH-master
commit id: "cherry-pick fix #89 for master"
checkout MNH-6-0
commit id: "cherry-pick fix #89 for 6-0"
Bug fix — specific to a release branch
Bug present only on MNH-6-0.
%%{init: { 'theme': 'base', 'gitGraph': {'mainBranchName': 'MNH-master', 'parallelCommits': true, 'showCommitLabel': true}} }%%
gitGraph
commit
branch MNH-6-0
checkout MNH-6-0
commit
branch MNH-6-0-bug-112
checkout MNH-6-0-bug-112
commit id: "fix bug #112"
checkout MNH-6-0
merge MNH-6-0-bug-112
checkout MNH-master
commit
Coding best practices
General
These guidelines apply mostly to every FORTRAN sources in src/ MNH, SURFEX, PHYEX, ACLIB, LIB.
File structure:
Check if the function you code is already coded
Avoid CONTAINS routines, create a new fortran routine file
For new file, keep the common structure with an updated statements for the LICENCE and documentation
Code ergonomy:
Maximum 132 characters per line, use &
Code in CAPITAL characters
Comments in lower-case characters
No blank line, use !
Remove debugging PRINTs and WRITE before committing
Comment your code !
Clean code:
Remove debugging PRINTs and WRITE before committing
Remove unused local variables
Remove unused dummy variables
Remove unused module variables (USE MODD …)
Select the variables used: USE MODD TOTO, ONLY : MYVAR
Variables:
Variables names must be consistent through subroutines (a variable must be easily found with grep)
All variables must be declared, use IMPLICIT NONE
Allocatables must be deallocated
Pointer must be initialized by NULL()
Reproductibility:
Use the parallelizaded version of basic functions (functions ended by ll such as MAX_ll or SUM3D_ll)
Avoid anticipated exit of a loop with EXIT, CYCLE, RETURN statements
Variables names
Variables first letter(s) must follow the DOCTOR norm:
Type/Status |
INTEGER |
REAL |
LOGICAL |
CHARACTER |
TYPE |
|---|---|---|---|---|---|
Global |
N |
X |
L (not LP) |
C |
T (not TP, TS, TZ) |
Dummy argument |
K |
P |
O (not PP) |
H |
TP |
Local |
I |
Z (not IS) |
G (not GS, ZS) |
Y (not YS, YP) |
TZ |
Loop control |
J (not JP) |
/ |
/ |
/ |
/ |
Extra rules for PHYEX
The externalized atmospheric physics PHYEX has extra rules in order to comply with all the models using PHYEX (AROME, HARMONIE-AROME, etc). These rules are more strict in order to transform automatically the code for GPU applications. The general idea behind these rules is that all the physics can be run with arrays written in one physical dimension (the vertical axis). The fortran raw code is written in 2D or 3D in a way that automatic functions (e.g. written in python) can read the fortran code and transform it to another fortran code that can be run on any type of GPUs. The previous general rules applies to PHYEX.
The following extra rules apply on PHYEX/ :
Variables:
Do not use allocatables
Dimensions of dummy argument arrays must be explicit : no (:,:), use the structure D%
No variables from modules can be imported except variables declared with the PARAMETER attribute. Put the variable in a type received by the subroutine interface
Use loop index JIJ for computation on horizontal dimensions
Use loop index JL on KSIZE microphysics computation point
Horizontal dimensions arrays are packed into one dimension : instead of A(D%NIT, D%NJT, D%NKT), use A(D%NIJT, D%NKT) where D%NIT, D%NJT, D%NKT are physical dimensions in x, y, z directions and D%NIJT = D%NIT*D%NJT
Subroutines:
Do not use functions returning arrays, use subroutines
Avoid CONTAINS subroutines, if really needed, the local arrays of the subroutines must have different names than the hosting subroutine or than other contained subroutines Statements
All calculation on arrays must show explicit dimensions. Instead of A = B + C, write : A(:,:) = B(:,:) + C(:,:) even for initialization
Do not use nested WHERE, convert it to DO…IF…
Temporary Do not use ANY, COUNT functions on arrays of horizontal dimensions
Temporary no (:) on TYPE%VAR
Compilation keys must be avoided. If really needed, the statements betwen ifdef and else must not split a statement
Extra rules for ACLIB
ACLIB is shared with other models. Specific rules must be followed:
Use explicit dimensions in variable declaration
Do not add Méso-NH specific modules/variables into ACLIB, but add variables through the interfaces instead. If a new specific module is needed, make sure that this module is Méso-NH agnostic (not dependent of other Méso-NH specific modules that would be incompatible with other host models)
Use dedicated ACLIB custom types as it is implemented (e.g. use CST_ACLIB for constants and not MODD_CST from MesoNH world)
Internal routines in
src/ACLIBmust be agnostic from parallelization as much as possible to ease future use of cross-codes in different host models.
How to contribute to the code ?
Meso-NH packs VX-X-X are divided into two categories :
major release-pack: X and Y of VX-Y (e.g. 5.4, 5.5, 5.6, etc)
bugfix release-pack: Z of VX-Y-Z (e.g. 5.4.1, 6.0.1)
A call of contribution is done for a major release-pack. For bugfixes only, you can contribute anytime.
Clone the git repository
Contributions are merged into the official branches via the official repository. Follow the instructions to clone the repository here. Then:
If you have a JANUS account (CNRS), log in and create a fork of the repository. Code in your own branch.
If you do not have a JANUS account, contact us (mesonhsupport .at. utoulouse.fr) and we will send you a token to be able to create a personal branch in the official repository.
Once your developpement is ready, create a merge-request.
Major release-pack
A major release contains several scientific and technical changes and numerous bugfixes. The time frequency of a major release is about one over 12 to 18 months depending on the amount of contributors. In the case of a major release-pack, please follow these guidelines :
Merge the master’s branch into your work before sharing your branch with
git pull. Resolve conflits if any and test the compilation.New feature: you must share at least one new test case related to your work with python3 plots showing the interesting variables related to your new work.
Major modification of a current part of the code: you must share at least one new test case with python3 plots showing the interests variables related to your new work and to have tested your branch on 2 other cases that is impacted by your development (see the Namelist catalogue)
Provide a contribution to the user’s guide (this website) and scientific guide.
Bugfix release-pack
A bugfix release contains a sufficient number of minor bugfixes to justify a new release, or a hot bugfix that may impact a large number of users. The time frequency of bugfix can vary to a few days up to 12 months depending on the stability of the current pack release (usually a few months). Please follow these guidelines:
Merge your branch on the last version of the master’s branch with
git pull. Resolve conflits if any and test the compilation.only commits with bugfixes are asked. If your bugfixes are in a developpement branch, create a bugfix-branch and cherry-picks only bugfix commits.
Warning
Contributions of branches with major developments would be declined and postponed to the next call of contributions for a major release.