# How to Write Commit Messages for Earth Science Models

By the end of this guide you will be able to write git commit messages for earth science models that record what changed, why it changed, who contributed, and which experiment the change belongs to. You will learn a step by step workflow built on standard git commands, a house style adapted to model code such as CESM, WRF, MOM6, and CICE, and how to recover from the errors that trip up scientists new to git for scientists workflows.

To follow along you need git 2.x installed on your workstation or cluster login node, a clone of a model repository or any small test repository you can safely commit to, and access to a terminal. If your team hosts the repository on GitHub, you will also want a GitHub account so you can open pull requests and see how commit messages render there.

## Why Commit Messages Matter in Earth Science Modeling

A commit is a permanent snapshot of the repository at one moment, and the commit message is the only human readable record of why that snapshot exists. In model development the stakes are higher than in many other software domains because the artifact is not just code. A single commit can change the physical behavior of a simulation that runs for weeks on an HPC cluster and produces hundreds of gigabytes of output that feed a published figure.

Three properties make commit messages unusually valuable in this field.

**Provenance.** When a reviewer or colleague asks which code produced the ocean temperatures in Figure 3, the answer should be a commit hash and a message that explains the change. A message like "update" forces you to re-derive the change from the diff months later, which is exactly the work you hoped to avoid.

**Reproducibility.** Model results depend on code state, compiler, and input data. The commit message is the right place to record the experiment or case name that used this code state, so anyone can connect a result to the exact source version. This habit also serves studies in other domains where researchers document how recorded messages encode context, a principle shown in work on Indigenous oral history where stories are deliberately preserved with their context so the next generation can interpret them correctly [1]. A commit message is a small written record serving the same purpose for a model.

**Collaboration.** Model repositories attract contributions from atmospherics scientists, oceanographers, software engineers, and students across institutions. Messages that follow a shared pattern let a reviewer scan a week of history and understand it without opening a single diff.

There is also a practical collaboration layer built into git itself. GitLab and GitHub both support the "Co-Authored-By:" trailer in commit messages, which records multiple authors on a single commit. Research on the OpenStack ecosystem, which analyzed roughly one million commits across 1,804 repositories, examined exactly these micro-collaboration practices where several people contribute to one commit [2]. The mechanism transfers directly to earth science teams, and this guide shows how to use it.

## The Anatomy of a Model Commit Message

![Three steps in order: the subject line, a blank line, the body wrapped at 72 characters, and the trailer block at the end.](/article-images/illustrations/git-commit-messages-earth-science-models-commit-anatomy.webp)

A well formed commit message has three parts, separated by a blank line.

### The subject line

The subject is the first line, ideally 50 characters or fewer and never longer than 72. It is written in the imperative mood, as if completing the sentence "If applied, this commit will". No trailing period. For model code, a component prefix at the start of the subject is common practice in large earth system model repositories and makes history scanning trivial.

Good subjects:

- `ocn: reduce diapycnal mixing in Southern Ocean case`
- `atm: fix sign error in shortwave cloud forcing`
- `lnd: add flux output variable to CLM history files`
- `docs: document new spinup procedure in README`

Weak subjects:

- `changes`
- `fix`
- `update code`
- `stuff from yesterday`

### The body

The body, separated from the subject by one blank line, explains the what and the why. Wrap lines at 72 characters so the message reads cleanly in terminals, `git log` output, and code review tools. For a physics or numerics change, answer three questions:

1. What was wrong or missing? Describe the symptom in physical terms, not just code terms.
2. What did you change? Name the parameter, scheme, file, or data source.
3. What is the evidence? Reference the experiment, diagnostic, or test that motivated the change.

### The trailers

Trailers are structured key-value lines at the end of the message. Git and GitHub recognize several:

| Trailer | Purpose | Example |
|--|--|--|
| `Co-authored-by:` | Credits a second contributor on the same commit | `Co-authored-by: J. Rivera <j.rivera@example.edu>` |
| `Refs:` | Points at an experiment, case, or issue without closing it | `Refs: exp/SO1deg-kappa-sweep` |
| `Fixes:` or `Closes:` | Links and auto-closes a GitHub issue | `Fixes: #412` |
| `Signed-off-by:` | Certifies you wrote or approved the change, added by `git commit -s` | `Signed-off-by: P. Chen <p.chen@example.edu>` |
| `Data:` | Names input datasets or their identifiers | `Data: ERA5, Copernicus CDS` |

GitHub renders `Co-authored-by` trailers as co-author profiles on the commit page, which is the mechanism the OpenStack study relied on to detect micro-collaboration at scale [2].

## Writing Git Commit Messages for Earth Science Models: Step by Step

This walkthrough assumes you are in your repository working directory on a Linux or macOS terminal. Every command is safe to run on a scratch copy of your repo.

### Step 1: Check the state of the working tree

```
git status
```

Expected output:

```
On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  modified:   src/ice/cice_sbc.F90

Untracked files:
  diagnostics/kappa_sweep.py

no changes added to commit
```

Two things need attention. The modified file `src/ice/cice_sbc.F90` is code. The untracked file `diagnostics/kappa_sweep.py` is a diagnostic script you may want to version alongside the change. Deciding what belongs in this commit is the first editorial decision of every commit message.

### Step 2: Review the actual changes

Before writing anything, look at the diff:

```
git diff src/ice/cice_sbc.F90
```

Expected output (abbreviated):

```
-  hmix = 1.0e-5
+  hmix = 2.0e-6
```

If the diff surprises you, or contains leftover debug prints and commented out code, clean those up now. A commit message cannot rescue a messy diff.

### Step 3: Stage exactly the files this commit should contain

```
git add src/ice/cice_sbc.F90 diagnostics/kappa_sweep.py
git status
```

Expected output:

```
Changes to be committed:
  modified:   src/ice/cice_sbc.F90
  new file:   diagnostics/kappa_sweep.py
```

Small, single purpose commits produce small, single purpose messages. If you find yourself staging fifteen unrelated files, split the commit.

### Step 4: Write the subject line

Open the commit with an editor rather than cramming everything onto one command line, because you need the blank line between subject and body:

```
git commit
```

Your editor opens, by default vim on most HPC systems. Write the first line:

```
ice: lower lateral mixing coefficient for SO1deg case
```

This subject carries the component prefix `ice`, states the action in the imperative, and names the case. It is 52 characters, within the 50 character guideline.

If you prefer not to open an editor, you can pass the subject and body as separate paragraphs with repeated `-m` flags, which git turns into correctly separated paragraphs:

```
git commit -m "ice: lower lateral mixing coefficient for SO1deg case"
```

### Step 5: Write the body

Below the subject, leave one blank line, then write the explanation wrapped at 72 characters:

```
ice: lower lateral mixing coefficient for SO1deg case

The previous hmix value of 1.0e-5 m2 s-1 produced excessive
horizontal mixing in the 1 degree Southern Ocean configuration,
smearing the Antarctic Circumpolar Current front structure.

Reduce hmix to 2.0e-6 m2 s-1. The kappa_sweep diagnostic script
in diagnostics/ reproduces the before and after front sharpness
metrics used to select the new value.

Refs: exp/SO1deg-hmix-sweep-2026
```

The body answers what was wrong, what changed, and how you know. It names the experiment directory so the result can be traced later.

### Step 6: Add trailers for collaborators and issues

If a colleague suggested the fix in a discussion but did not type the code, credit them in the message. This is the micro-collaboration practice that GitHub and GitLab support natively, and large open source communities rely on it to attribute shared work accurately [2]. Add a trailer line at the very end of the message:

```
Co-authored-by: J. Rivera <j.rivera@example.edu>
```

If the change resolves a tracked issue, add:

```
Fixes: #412
```

When you push to GitHub, the commit page will list J. Rivera as a co-author, and the `Fixes: #412` line will close the issue when the commit reaches the default branch.

Save and close the editor. Git commits immediately.

### Step 7: Verify the result

```
git log -1
```

Expected output:

```
commit 3f9c1a2b7d4e...
Author: P. Chen <p.chen@example.edu>
Date:   Wed Mar 11 14:22:07 2026 -0600

    ice: lower lateral mixing coefficient for SO1deg case

    The previous hmix value of 1.0e-5 m2 s-1 produced excessive
    horizontal mixing in the 1 degree Southern Ocean configuration,
    smearing the Antarctic Circumpolar Current front structure.

    Reduce hmix to 2.0e-6 m2 s-1. The kappa_sweep diagnostic script
    in diagnostics/ reproduces the before and after front sharpness
    metrics used to select the new value.

    Refs: exp/SO1deg-hmix-sweep-2026
    Fixes: #412
    Co-authored-by: J. Rivera <j.rivera@example.edu>
```

Check three things: a blank line separates subject from body, the subject is one line, and the trailers are the final block.

### Step 8: Fix a mistake before pushing

![A decision path asking if the commit was pushed and if colleagues pulled it, ending in amend the message or make a new commit.](/article-images/illustrations/git-commit-messages-earth-science-models-amend-or-new.webp)

If you spot a typo or forgot a trailer, and the commit has not been pushed, rewrite it:

```
git commit --amend
```

Your editor opens with the existing message. Edit it, save, and close. Git replaces the last commit with a corrected one. Never amend a commit that colleagues may have already pulled, because that rewrites shared history.

### Step 9: Push and confirm how it renders

```
git push origin main
```

On GitHub, open the commit page. You should see the co-author listed beside the commit, the linked issue highlighted, and the full message rendered with line breaks preserved. If anything looks wrong, GitHub for researchers workflows usually catch it here, before the commit becomes part of a tagged release.

## A House Style for Model Repositories

Individual good messages help less than a convention the whole team follows. Adopt a short written style guide and enforce it with a commit-msg hook. The following pattern works well for earth system model groups and can be adapted in one team meeting.

**Component prefixes.** Use short prefixes matching the coupled model components: `atm`, `ocn`, `ice`, `lnd`, `cpl` for the coupler, `drv` for the driver, `tools` and `docs` for everything else. A history line like `cpl: fix time averaging bug at year boundaries` tells a reader instantly where to look.

**Case and experiment identifiers.** Every commit tied to a production or sensitivity experiment should carry a `Refs:` trailer pointing at the experiment directory, a wiki page, or an issue. When a paper reports a result, the paper's methods section can state "run X at commit 3f9c1a2", and the message closes the loop back to the motivation.

**Data provenance.** When a change depends on new forcing data, initial conditions, or a updated observational dataset, name it in the body and in a `Data:` trailer. Include the dataset version or identifier if one exists, because the same named dataset often has many versions.

**Scope discipline.** One commit should do one thing. A commit that changes a physics parameter and reformats forty files makes both changes harder to review and harder to revert. Reformatting belongs in its own commit with a subject like `style: reformat ice module, no functional changes`.

**Signed-off commits.** For repositories with formal contribution rules, `git commit -s` appends a `Signed-off-by:` trailer certifying the change's origin. Many large model projects require this on every patch.

A useful enforcement tool is a commit-msg hook, a small script stored in `.git/hooks/commit-msg` that git runs before the commit is created. The hook can reject a subject longer than 72 characters, a missing component prefix, or a missing blank line after the subject, and print your team's rules to the author. Teams that host on GitHub for researchers workflows can additionally enforce conventions on pull requests, where reviewers see every message before merge.

## Documenting Physics, Numerics, and Data Changes

Commit messages in model code need a slightly different vocabulary than typical application code, because the interesting "behavior" is physical behavior.

When you change a parameterization, say what physical effect you expected. Compare:

Weak: `modified boundary layer scheme`.

Strong: `atm: switch surface layer to form drag formulation`.

```
atm: switch surface layer to form drag formulation

The previous roughness length treatment overestimated surface
stress over sea ice ridges. Switch to the form drag formulation
and keep the old code behind a namelist flag for one release so
the two formulations can be compared.

Refs: atm-ridge-drag-test
```

When you change numerics, name the affected variable, grid, or timestep, and state the stability or accuracy concern:

```
ocn: reduce baroclinic timestep in eddying config

Model became unstable (blowup inSSH) after 40 days in the
1/10 degree Gulf Stream configuration. Halve the baroclinic
timestep from 1200 s to 600 s.
```

When you change data, the message is the only place the dataset decision can live if the data itself is not versioned. Name the source, the version, the spatial or temporal subset, and the reason for the change.

Notice that none of these messages quote large result numbers or claim validation. A commit message records intent and evidence pointers. Validation numbers belong in experiment logs, notebooks, and papers, all of which the message links to.

## Git for Scientists: Keeping History Readable Over Years

Model development timelines are long. A graduate student who writes good messages today is writing notes for the scientist who inherits the code in five years, quite possibly themselves. Two habits keep long histories readable.

First, keep the subject line truthful as a summary of the diff, and push detail into the body. Tooling rewards this: `git log -1` renders the subject, `git log` renders subjects only in compact views, and code review interfaces show subjects in lists. A subject that says `update` is invisible in all of them.

Second, use tags to mark code states that matter, such as the commit used for a published result. Tagging is complementary to the message: the message explains the change, the tag names the milestone.

```
git tag -a paper2026-southern-ocean -m "Code state for Souza et al. 2026 Southern Ocean runs"
git push origin paper2026-southern-ocean
```

Years later, `git log paper2026-southern-ocean` drops you into the exact history around the publication, with every change explained in place.

## Common Errors and Their Exact Messages

These are the failures you will actually see, with the exact text git prints and the fix for each.

**Empty message.** If you close the editor without saving, or write only whitespace, git refuses:

```
Aborting commit due to empty commit message.
```

Nothing was committed. Run `git commit` again and write the message, or cancel cleanly with `git reset` if the staging is wrong.

**Nothing staged.**

```
nothing to commit, working tree clean
```

means you forgot `git add` or the changes were already committed. Run `git status` and `git log -1` to see which.

**Wrong repository.**

```
fatal: not a git repository (or any of the parent directories): .git
```

means your terminal is outside the model checkout. `cd` into the repository root, or clone it.

**Editor trap.** On HPC systems the default editor is often vim, and new users panic when a full screen editor appears. Press `Esc`, type `:wq`, and press `Enter` to save and commit. To choose a different editor permanently, set `git config, global core.editor "nano"` once per machine.

**Amend after push.** If you amend and force push a commit others have pulled, they see:

```
error: failed to push some refs
hint: Updates were rejected because the tip of your current branch is behind
```

or they see conflicting history on their side. The fix is coordination: do not amend pushed commits, and make a new commit instead. If you must rewrite shared history, use `git pull, rebase` locally and communicate clearly with the team.

**Hook rejection.** If your team installs a commit-msg hook, a bad message fails with the hook's own text, for example a warning that the subject exceeds the length limit. The commit did not happen. Edit the message and commit again. Read the hook script in `.git/hooks/` to learn the exact rules.

**Merge conflict message.** When git stops with `Automatic merge failed; fix conflicts and then commit the result.`, resolve the marked files, `git add` them, and commit. Write a message explaining how you resolved the conflict, because future readers will want to know which behavior survived.

## Common Mistakes and Limitations

**Writing the diff in prose.** A message that restates the diff ("changed three lines in m2") adds nothing, because the diff is right there. Explain what the diff cannot: why the change was made and how you know it works.

**One commit, many topics.** Bundling a physics change, a build fix, and a documentation update into one commit makes every future bisect and revert a mess. Split them. The commit messages then stay short and specific.

**Vague subjects on large changes.** "Improve model" on a commit touching hundreds of files is worse than no message. If a change is genuinely enormous, say so in the body and summarize its parts.

**Ignoring trailers.** Teams that skip `Co-authored-by` systematically misattribute shared work. The empirical work on OpenStack showed that these trailers are the mechanism platforms use to recognize multi-author commits, and that micro-collaboration is a real and measurable pattern in large projects [2]. Modeling groups with rotating student contributions benefit the most.

**Storing results instead of references.** A commit message is not a [lab notebook](/knowledge/molecular-biology/lab-notebook). Do not paste tables of diagnostics into it. Link to the experiment directory, notebook, or issue that holds the numbers.

**Assuming the message substitutes for documentation.** A commit message explains a change in context. Design decisions that span many commits belong in the repository's documentation, with the commits referencing the design doc.

**Amending pushed history.** Rewriting commits that collaborators have already built on breaks their clones and creates confusion that no message style can repair.

One limitation applies to all of this: conventions only work when the team agrees on them, and the exact house style, prefix set, and hook rules vary by project. Treat the pattern above as a starting template to adapt in your team's contributing guide rather than a universal standard.

## Checking That Your History Is Right

Periodically audit your own history the way a reviewer would. Three commands cover it:

```
git log -1                # inspect the newest message in full
git log -5                # scan the last five subjects
git show -1               # message and diff together
```

For a longer view, `git log, oneline -20` prints the last twenty subjects in one column. Read them as a story. If you cannot reconstruct what happened from the subjects alone, the messages are too thin. `git blame src/ice/cice_sbc.F90` attaches a message and author to every line of a file, which is exactly how a colleague will audit your parameter change two years from now.

Sensible next steps: write your team's style guide into a `CONTRIBUTING.md` file at the repository root, install a commit-msg hook that enforces it, add `Co-authored-by` credits as a matter of routine, and tag the commit hash of every published result so your paper's methods section can point at an exact, explained state of the model.

## Frequently Asked Questions

### How long should the subject line of a model commit message be?

Aim for 50 characters or fewer and treat 72 as the hard limit. Use a component prefix like `atm` or `ocn`, write in the imperative mood, and skip the trailing period. A subject like `ocn: reduce diapycnal mixing in Southern Ocean case` fits comfortably and reads as a summary.

### Should I include experiment results in the commit message?

No. Put the experiment identifier and motivation in the message with a `Refs:` trailer, and keep diagnostic tables, plots, and numeric results in the experiment directory or a notebook the message points to. Commit messages record intent and evidence pointers, not result dumps.

### How do I credit a collaborator who suggested the fix but did not write the code?

Add a `Co-authored-by: Name <email>` trailer at the end of the message. GitHub recognizes it and lists the person as a co-author on the commit, which is the same mechanism large open source projects use to attribute shared work.

### What is the difference between a commit message and a tag?

The commit message explains a single change, why it was made and who contributed. A tag is a named pointer to a specific commit, such as the code state used for a published run. Use messages for explanation and tags for milestones like `paper2026-southern-ocean`.

### How do I fix a typo in my last commit message?

Run `git commit, amend`, edit the message in your editor, and save. Do this only before pushing. If the commit is already pushed and shared, make a new commit with the correction instead of rewriting history your colleagues may have pulled.

### Do these conventions work for analysis scripts and Jupyter notebooks too?

Yes. Use the same subject line discipline and body structure. For notebooks, mention in the body which figure or diagnostic the notebook produces, and keep the notebook's data sources documented either in the message body or in a `Data:` trailer.

### Should data files such as forcing datasets be committed with the model code?

Usually no, because forcing and initial condition files are large and poorly handled by git. Commit the code, commit small configuration and namelist changes, and record the dataset name, version, and subset in the commit message body or a `Data:` trailer so the provenance is captured even though the data lives elsewhere.

### What if my team already uses a different commit message style?

Follow your team's convention first, because a consistent imperfect style beats an inconsistent perfect one. If you want to improve it, propose the pattern in this article as a small addition, such as component prefixes or `Co-authored-by` credits, and codify it in the contributing guide rather than quietly breaking the existing rules.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "How long should the subject line of a model commit message be?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Aim for 50 characters or fewer and treat 72 as the hard limit. Use a component prefix like atm or ocn, write in the imperative mood, and skip the trailing period."
      }
    },
    {
      "@type": "Question",
      "name": "Should I include experiment results in the commit message?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Put the experiment identifier and motivation in the message with a Refs trailer, and keep diagnostic tables, plots, and numeric results in the experiment directory or a notebook the message points to."
      }
    },
    {
      "@type": "Question",
      "name": "How do I credit a collaborator who suggested the fix but did not write the code?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Add a Co-authored-by: Name <email> trailer at the end of the message. GitHub recognizes it and lists the person as a co-author on the commit."
      }
    },
    {
      "@type": "Question",
      "name": "What is the difference between a commit message and a tag?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The commit message explains a single change, why it was made and who contributed. A tag is a named pointer to a specific commit, such as the code state used for a published run."
      }
    },
    {
      "@type": "Question",
      "name": "How do I fix a typo in my last commit message?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Run git commit with the amend option, edit the message in your editor, and save. Do this only before pushing. If the commit is already shared, make a new commit with the correction instead."
      }
    },
    {
      "@type": "Question",
      "name": "Do these conventions work for analysis scripts and Jupyter notebooks too?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes. Use the same subject line discipline and body structure, and mention in the body which figure or diagnostic the notebook produces."
      }
    },
    {
      "@type": "Question",
      "name": "Should data files such as forcing datasets be committed with the model code?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Usually no, because forcing and initial condition files are large. Commit the code and configuration, and record the dataset name, version, and subset in the commit message so the provenance is captured."
      }
    },
    {
      "@type": "Question",
      "name": "What if my team already uses a different commit message style?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Follow your team's convention first, because a consistent imperfect style beats an inconsistent perfect one. Propose improvements such as component prefixes or co-author credits in the contributing guide rather than quietly breaking existing rules."
      }
    }
  ]
}
</script>

## Further Reading

- [The Social Contagion Potential of Pro-Vaccine Messages on Black Twitter.](https://pubmed.ncbi.nlm.nih.gov/37994402/)
- [Effect of Personalized Messages Sent by a Health System's Patient Portal on Influenza Vaccination Rates: a Randomized Clinical Trial.](https://pubmed.ncbi.nlm.nih.gov/34472020/)

## Sources

1. [Telling our history: a narrative study with Indigenous elders, wisdom for the coming generation.](https://pubmed.ncbi.nlm.nih.gov/42395305/)
2. [A mixed-methods analysis of micro-collaborative coding practices in OpenStack.](https://pubmed.ncbi.nlm.nih.gov/35757446/)