# How to Write Commit Messages for Viral Genomics Data

By the end of this guide you will be able to write git commit messages for viral genomics data that record what changed, which samples were involved, which reference genome and pipeline versions produced the outputs, and who contributed to the work. You will set up a reusable commit template, commit a batch of consensus genomes with full provenance, credit collaborators with the Co-Authored-By trailer, and audit your history with log searches. You will also learn the mistakes that turn a version history into an unusable folder of mystery files.

You need git installed (version 2.30 or later is comfortable for everything here), a terminal, and a text editor. You do not need any specific viral genomics pipeline installed to follow along, because the commands work the same whether your commit adds a consensus FASTA, an updated metadata table, or a Nextflow config.

## Why Commit Messages Carry Extra Weight in Viral Genomics

In ordinary software projects, a commit message mainly helps a developer understand a code change. In viral genomics, the commit message often doubles as a laboratory notebook entry. A single commit can represent a sequencing run, a batch of clinical samples, a reassignment of lineages, or a correction to a consensus genome that has already been shared. Six months later, nobody on the team will remember why a sample was resequenced or which version of the lineage assignment tool produced a given call. The commit history is frequently the only place that context survives.

Git for scientists works best when you treat every commit as an answerable question. A message like "update files" forces whoever reads it later to reconstruct the answer from diffs. A message like "Add October 2025 H1N1pdm consensus genomes, 21 of 24 passed QC, resequence MSP-03-0147" answers the question before it is asked.

Collaboration patterns matter here too. Large software projects have studied how people actually work together in git histories, and one analysis of roughly one million commits across 1,804 OpenStack repositories over nine years documented micro-collaboration, the practice of multiple contributors sharing credit on a single commit through trailers such as Co-Authored-By in the commit message [1]. That same mechanism works in a genomics repository when a bioinformatician commits a batch that a virologist curated and a technician generated. The trailer is native to GitHub and GitLab, so the credit shows up in the platform interface, not just the raw history [1].

There is also a humbler reason to write carefully. Research that documents knowledge for people who were not present when the work happened, such as narrative studies that record elder wisdom in written form for the coming generation, shows that secondhand readers need the context spelled out rather than assumed [2]. Your future self is a secondhand reader. Commit messages are how you leave yourself the context.

## The Anatomy of a Commit Message

![Three cards in order: the subject line, the body and the trailers, each with its rule for length and placement.](/article-images/illustrations/git-commit-messages-viral-genomics-commit-anatomy.webp)

Every git commit message has three parts: a subject line, an optional body, and optional trailers. Git enforces almost none of this structure, which is why conventions matter.

### The Subject Line

The subject line is the first line of the message. Keep it under about 50 characters, use the imperative mood, and do not end it with a period. The imperative mood reads naturally in the git log. "Add October consensus genomes" reads as a sentence fragment that completes the phrase "this commit will".

Compare these subject lines for the same change:

```
update files
Add 21 H1N1pdm consensus genomes for October batch
```

The second line tells a reader scanning the log what landed and roughly how much. It fits in 50 characters and survives truncation in branch views and pull request lists.

### The Body

The body starts after one blank line, explains what changed and why, and is wrapped at roughly 72 characters so it stays readable in terminal tools. In viral genomics, the body is where provenance lives. The provenance fields that matter most are covered in the next section, but the principle is simple: anyone reading the body should be able to trace the commit back to the sequencing run, the pipeline version, and the quality control decision without emailing you.

### Trailers

Trailers are key-value lines at the end of the message. The one you will use most is Co-Authored-By, which attributes work to people who did not run the commit command:

```
Add HA clade assignment table for October batch

Batch: flu-2025-10-runA, 24 samples
Tool: nextclade v3.9.1 against H1N1pdm09 reference set

Co-Authored-By: Priya Raman <praman@example.org>
```

The trailing empty line before the trailer matters. Git parses trailers only when they sit in a trailing block. The Co-Authored-By convention is supported directly by GitHub and GitLab, and research on large collaborative projects shows it is the standard mechanism for recording shared authorship of a single commit [1].

## What Viral Genomics Commits Must Record

![Four cards listing what changed, which samples, what produced the outputs, what QC said and what a human decided.](/article-images/illustrations/git-commit-messages-viral-genomics-five-provenance-questions.webp)

A good commit message for virus genomic data answers five questions. Write them into the body of every data commit, even when the answers feel obvious at the time.

1. **What changed.** New consensus genomes, a metadata table update, a corrected sequence, a reassignment of lineages, a pipeline version bump, or a configuration change. Name the direction of the change in the subject line.
2. **Which samples.** The batch or run identifier, the number of samples, and where the full sample list lives. Do not paste hundreds of sample identifiers into the message. Put the list in a manifest file and reference its path and checksum.
3. **What produced the outputs.** The workflow name and version, the tool versions that affect results (consensus caller, lineage assignment tool, read mapper), and the reference genome or alignment used.
4. **What the quality control said.** The pass and fail counts and the rule applied. A one-line QC summary in the commit message saves an enormous amount of archaeology later.
5. **What a human decided.** Manual exclusions, ambiguous bases flagged for review, reasons a sample was resequenced, and any departure from the standard workflow. This is the information that exists nowhere else.

The fifth point deserves emphasis. Pipeline versions and file checksums can often be recovered from logs. Human decisions cannot. If you dropped a sample because the hemagglutinin amplicon failed twice, that fact lives only in your head and, if you write it down, in the commit message.

## A Step-by-Step Walkthrough

This walkthrough builds a small surveillance repository and commits a batch of consensus genomes with complete provenance. The example uses influenza A H1N1pdm09 surveillance data, but every command works identically for SARS-CoV-2, RSV, rabies, or any other virus.

### Step 1. Confirm git and identify yourself

```
git --version
```

Expected output:

```
git version 2.45.2
```

Set the identity that git attaches to every commit. Use the email associated with your GitHub or institutional account so contribution graphs and Co-Authored-By attributions resolve to real people.

```
git config --global user.name "Zubair Khalid"
git config --global user.email "zk@example.org"
git config --global user.name
```

Expected output of the last command:

```
Zubair Khalid
```

### Step 2. Create the repository and exclude raw reads

```
mkdir h1n1-surveillance && cd h1n1-surveillance
git init
```

Expected output:

```
Initialized empty Git repository in /home/zk/h1n1-surveillance/.git/
```

Before anything else, create a `.gitignore` file that keeps raw reads, large intermediates, and credentials out of version control:

```
# .gitignore
data/raw/
results/bam/
results/intermediates/
*.fastq.gz
*.fq.gz
*.bam
*.cram
.env
credentials*
```

Commit this file first, with its own message:

```
git add .gitignore
git commit -m "Add gitignore excluding raw reads and credentials"
```

This first commit matters because anything you stage later is filtered through these rules automatically.

### Step 3. Create a reusable commit message template

Create a file named `.gitmessage` in your home directory. Lines beginning with a hash are comments and git strips them automatically, so they function as an on-screen checklist when you commit.

```
# Subject: imperative, 50 characters or fewer, no trailing period
#
# <what changed and why>
#
# Batch: <run or batch identifier>
# Samples: <count and assay>
# Reference: <genome name and version>
# Pipeline: <workflow and tool versions>
# Inputs: <paths and checksum manifest>
# Outputs: <paths>
# QC: <pass/fail counts and the rule applied>
# Notes: <human decisions, flags, deviations>
#
# Co-Authored-By: Full Name <email> (only when others contributed)
```

Point git at the template:

```
git config --global commit.template ~/.gitmessage
```

From now on, every `git commit` without `-m` opens your editor pre-filled with this checklist.

### Step 4. Stage the data commit

Assume the repository now contains a batch of consensus FASTA files, a metadata table, and a checksum manifest produced by your workflow. Stage deliberately rather than with a blanket add:

```
git add results/consensus/2025-10/
git add results/qc/2025-10_qc_summary.csv
git add metadata/2025-10_samples.tsv
git add manifests/2025-10.sha256
git status
```

Expected output (abbreviated):

```
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   manifests/2025-10.sha256
        new file:   metadata/2025-10_samples.tsv
        new file:   results/consensus/2025-10/MSP-03-0131.consensus.fa
        new file:   results/consensus/2025-10/MSP-03-0132.consensus.fa
        ... (19 more)
        new file:   results/qc/2025-10_qc_summary.csv
```

Staging in deliberate groups is one of the most useful git tips for scientists. If you later need to revert one batch without touching the metadata, deliberate staging makes that possible.

### Step 5. Commit with the template

Run `git commit` with no flags. Your editor opens with the template comments visible. Delete the comment lines and write the message:

```
Add October 2025 H1N1pdm consensus genomes

Batch: flu-2025-10-runA (site MSP-03)
Samples: 24 nasal swabs, multiplex [amplicon sequencing](/blog/guides/amplicon-sequencing)
Reference: A/California/07/2009 (H1N1pdm09), as listed in
  data/ref_manifest.tsv
Pipeline: flu-consensus v2.3.0 on Nextflow 24.04.2,
  nextclade v3.9.1 for clade assignment
Inputs: data/raw/2025-10/run_A, checksums in
  manifests/2025-10.sha256
Outputs: results/consensus/2025-10/, results/qc/2025-10_qc_summary.csv
QC: 21 of 24 passed, mean depth 1,842x, rule = at least 20x
  across 95 percent of each segment
Notes: MSP-03-0147 has 3 ambiguous bases in the HA stem region,
  flagged for manual review. MSP-03-0152 and MSP-03-0159 failed
  the breadth rule and are queued for resequencing.

Co-Authored-By: Priya Raman <praman@example.org>
```

Save and close the editor. The numbers here are an illustrative worked example of the format, not a claim about any particular dataset. The point is the shape of the message: a scannable subject, a body that answers the five provenance questions, and a trailer crediting the collaborator who curated the batch.

An alternative for scripted or pipeline contexts is a heredoc commit, which keeps the multi-line message out of the shell history in fragments:

```
git commit -m "$(cat <<'EOF'
Add October 2025 H1N1pdm consensus genomes

Batch: flu-2025-10-runA (site MSP-03)
Samples: 24 nasal swabs, multiplex amplicon sequencing
Pipeline: flu-consensus v2.3.0 on Nextflow 24.04.2
QC: 21 of 24 passed, rule = at least 20x across 95 percent
  of each segment
EOF
)"
```

### Step 6. Verify the commit

```
git log -1 --stat
```

Expected output (abbreviated):

```
commit 9f3c1a2b4d5e6f708192a3b4c5d6e7f8091a2b3c
Author: Zubair Khalid <zk@example.org>
Date:   Mon Nov 11 09:42:17 2025 -0600

    Add October 2025 H1N1pdm consensus genomes

    Batch: flu-2025-10-runA (site MSP-03)
    ...

Co-Authored-By: Priya Raman <praman@example.org>

 manifests/2025-10.sha256              |  24 +
 metadata/2025-10_samples.tsv          |  25 +
 results/consensus/2025-10/MSP-03-0131.consensus.fa | 8 +
 ... (20 more files)
 results/qc/2025-10_qc_summary.csv     |  25 +
 25 files changed, 612 insertions(+)
```

Check three things: the subject reads cleanly in the log, the trailer survived on its own line, and the file list matches what you intended to stage. If you spot a typo immediately, `git commit, amend` rewrites the most recent commit before you push it. Never amend a commit that colleagues have already pulled.

### Step 7. Search the history later

The value of structured messages compounds over time. Six months later, when a reviewer asks about sample MSP-03-0147, the answer is one search away:

```
git log --oneline --grep="MSP-03-0147"
```

Expected output:

```
9f3c1a2 Add October 2025 H1N1pdm consensus genomes
```

Then inspect exactly what changed in that commit:

```
git show 9f3c1a2 --stat
git show 9f3c1a2 -- results/qc/2025-10_qc_summary.csv
```

Because the commit body flagged the ambiguous bases and the QC rule, you can answer the reviewer with a citation to your own history instead of a guess.

## Keeping Raw Reads Out of Git

Viral genomics produces files that git was never designed to store. A single paired-end sequencing run can easily exceed tens of gigabytes, and GitHub rejects pushes containing any file larger than 100 megabytes. The policy that works in practice is a three-tier split.

1. **Code, configs, small metadata tables, QC summaries, and reference manifests** go in git directly. These files are small, text-based, and change in reviewable diffs.
2. **Large binary or compressed files that must be versioned with the code**, such as a curated consensus FASTA set you want to tag alongside a release, go in Git Large File Storage (LFS), an extension that stores file contents on a separate server and keeps lightweight pointer files in the repository. Install it, then track the relevant patterns:

```
git lfs install
git lfs track "*.consensus.fa"
git add .gitattributes
```

3. **Raw reads** stay on lab storage, an institutional server, or a dedicated archive, with a checksum manifest in git recording exactly which files belonged to which batch. The commit message references the manifest path, which is what step 5 above did.

If you accidentally commit a multi-gigabyte FASTQ, do not simply delete the file and commit again. The large object remains in history and the push still fails. Remove it with `git rm, cached data/raw/run_A_R1.fastq.gz`, commit, and if the object is already in local history, either rewrite the unpushed history with an interactive rebase or start from a fresh clone before pushing. Teams that hit this repeatedly should treat it as a signal to strengthen `.gitignore` at repository creation rather than to fix each incident.

## Automating Consistency

Manual discipline fades during an outbreak response or a busy sequencing week. Two low-effort mechanisms keep message quality stable.

**Commit templates.** The `commit.template` setting from step 3 is the single highest-value automation. Because the checklist appears in every editor session, reviewers can reject a data commit that lacks a batch identifier without arguing about taste. For teams, commit the `.gitmessage` file to the repository and have each member run `git config commit.template .gitmessage` inside the clone, which scopes the template to that repository only.

**Pre-commit and commit-msg hooks.** A `commit-msg` hook can reject messages that fail your minimum standard, for example a subject line longer than 72 characters or a data commit missing a Batch line. A minimal hook is a script saved as `.git/hooks/commit-msg` and made executable:

```
#!/bin/sh
subject=$(head -n 1 "$1")
length=${#subject}
if [ "$length" -gt 72 ]
then
  echo "Subject line is $length characters, limit is 72" >&2
  exit 1
fi
```

Exit code 1 blocks the commit and prints your message to the terminal. Teams using shared hosting can enforce the same rules server-side with protected branches and required status checks, which GitHub for researchers exposes through repository settings without any special tooling.

## Writing Messages People Will Act On

Commit messages are a form of technical communication, and the evidence on message design in other domains reinforces a simple rule: tailor the message to its reader. In health communication research, personalized messages outperformed other framings in shareability when tested for promoting COVID-19 vaccination on social media [3], and a large randomized trial tested whether tailored patient portal reminders, built on behavioral strategies, could raise influenza vaccination rates compared with standard reminders [4]. The specific contexts differ entirely from version control, but the underlying finding is consistent: generic messages get ignored, while messages that speak to a specific situation get acted on.

For commit messages, the reader you are tailoring for is a colleague at 11 p.m. during a variant investigation, or yourself in eight months. "Update data" is the generic message that gets ignored. "Add 21 October H1N1pdm consensus genomes, 3 QC failures queued for resequencing" is the specific one that gets acted on. Writing in full sentences with the batch identifier up front costs about ninety seconds per commit and eliminates most follow-up questions.

## Quick Reference Table

| Element or command | Rule or effect | Example |
|--|--|--|
| Subject line | Imperative mood, 50 characters or fewer, no period | Add October 2025 H1N1pdm consensus genomes |
| Body | Starts after one blank line, wrapped near 72 characters, records provenance | Batch, Samples, Reference, Pipeline, QC, Notes |
| Co-Authored-By trailer | Final block of the message, credits contributors to one commit [1] | Co-Authored-By: Priya Raman \<praman@example.org\> |
| `git commit` (no flags) | Opens editor pre-filled with your `commit.template` checklist | Recommended for all data commits |
| `git commit, amend` | Rewrites the most recent commit, safe only before others pull | Fix a typo in the last subject line |
| `git log, grep="text"` | Searches commit messages by pattern | `git log, grep="flu-2025-10"` |
| `git show HASH, stat` | Lists files changed in one commit | Verify a batch commit before sharing |
| `git rm, cached FILE` | Untracks a file without deleting it from disk | Recover from an accidental large-file commit |
| `git lfs track "PATTERN"` | Routes matching files through Large File Storage | `git lfs track "*.consensus.fa"` |

## Common Mistakes and Limitations

**Vague subjects.** "Update files", "fix", and "final version 2" are the most common failure mode and the cheapest to fix. If you cannot write a specific subject, you probably have combined several unrelated changes into one commit, which is its own problem worth fixing by staging in smaller groups.

**Committing raw reads.** Raw FASTQ and BAM files bloat repositories, get rejected by hosting platforms, and are the wrong place for primary data anyway. Keep them on lab storage and reference the checksum manifest. Every team that has inherited a clone of a repository stuffed with reads remembers the experience.

**Committing patient or participant identifiers.** Surveillance metadata frequently contains collection dates fine enough to re-identify individuals, or direct identifiers copied in from a spreadsheet. Filter metadata to the minimum fields needed before staging, and treat an accidental commit of sensitive data as an incident to remediate, not merely a line to delete in the next commit, because the object remains in history and on every clone.

**Mixing data and code in one commit.** A commit that adds a pipeline version bump, new consensus files, and an unrelated README edit cannot be reverted selectively. Split by purpose: one commit per logical change.

**Treating the commit message as the metadata system.** The message records decisions and pointers. The sample sheet, reference manifest, and QC tables are the structured record. Neither substitutes for the other.

**Rewriting shared history.** Amending, rebasing, or force-pushing branches that colleagues have pulled destroys their local state and, in an audit-relevant setting, destroys the provenance you were writing messages to preserve. Rewrite only unpushed work.

**Trailing trailers.** A Co-Authored-By line placed in the middle of the body, or without a blank line before it, is not parsed as a trailer and the attribution will not display on the platform. Put it last, after a blank line.

**Relying on memory for human decisions.** Exclusions, resequencing decisions, and deviations from protocol have no log file. If you did not write them in the commit body, assume they are gone.

One limitation applies to this guide as a whole. Conventions here are practice recommendations drawn from standard git documentation, platform behavior, and published research on collaboration in version-controlled projects [1]. Individual laboratories and consortia may have their own required message formats, and where a funder or a public archive specifies a data standard, that requirement takes precedence over anything here.

## Frequently Asked Questions

### Should I commit raw FASTQ files to git?

No. Raw reads are far too large for git, hosting platforms reject files over 100 megabytes, and primary data belongs on dedicated storage with checksums recorded in git. Keep reads outside the repository and reference their checksum manifest in the commit message.

### How long should a commit message be for genomic data?

The subject line should stay around 50 characters, and the body should be as long as needed to record batch, samples, reference, pipeline versions, and QC. A data commit with a five-line body is normal, and a correction to a published consensus genome may justify more.

### Can commit messages replace a sample metadata table?

No. Commit messages are free text meant for human decisions and pointers, while sample metadata needs structured, machine-readable files that can feed analyses and public archive submissions. Use the commit message to point at the metadata file and checksum.

### How do I credit a colleague who contributed to a commit?

Add a Co-Authored-By trailer as the final block of the message, formatted as Co-Authored-By: Full Name \<email\>, with a blank line before it. GitHub and GitLab parse this trailer natively and display the attribution alongside yours [1].

### What should I do if I already committed sensitive patient data?

Treat it as an incident. Remove the data, rewrite the affected history if it has not been widely pulled, notify everyone with clones, and recognize that the object may persist in forks and caches. If the data left your institution, follow your data governance process.

### Do these conventions matter for a private institutional repository?

Yes, and arguably more. Private repositories lack external reviewers as a forcing function, so internal history quality is the only safeguard. Provenance requirements from funders and institutions apply regardless of repository visibility.

### How do I find the commit where a specific sample batch was added?

Run `git log, oneline, grep="batch-identifier"` to search messages, then inspect the result with `git show HASH, stat`. This is the main payoff of writing batch identifiers into every data commit.

### Where should lineage and clade assignments go, in the message or in files?

Both, in different forms. The structured assignments belong in versioned table files that pipelines can consume, and the commit body should summarize the run, for example the tool version and how many samples received which lineage group, so the history reads as a narrative record.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Should I commit raw FASTQ files to git?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Raw reads are far too large for git, hosting platforms reject files over 100 megabytes, and primary data belongs on dedicated storage with checksums recorded in git. Keep reads outside the repository and reference their checksum manifest in the commit message."
      }
    },
    {
      "@type": "Question",
      "name": "How long should a commit message be for genomic data?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The subject line should stay around 50 characters, and the body should be as long as needed to record batch, samples, reference, pipeline versions, and QC. A data commit with a five-line body is normal, and a correction to a published consensus genome may justify more."
      }
    },
    {
      "@type": "Question",
      "name": "Can commit messages replace a sample metadata table?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Commit messages are free text meant for human decisions and pointers, while sample metadata needs structured, machine-readable files. Use the commit message to point at the metadata file and checksum."
      }
    },
    {
      "@type": "Question",
      "name": "How do I credit a colleague who contributed to a commit?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Add a Co-Authored-By trailer as the final block of the message, formatted as Co-Authored-By: Full Name followed by an email in angle brackets, with a blank line before it. GitHub and GitLab parse this trailer natively and display the attribution alongside yours."
      }
    },
    {
      "@type": "Question",
      "name": "What should I do if I already committed sensitive patient data?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Treat it as an incident. Remove the data, rewrite the affected history if it has not been widely pulled, notify everyone with clones, and recognize that the object may persist in forks and caches. If the data left your institution, follow your data governance process."
      }
    },
    {
      "@type": "Question",
      "name": "Do these conventions matter for a private institutional repository?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, and arguably more. Private repositories lack external reviewers as a forcing function, so internal history quality is the only safeguard, and funder or institutional provenance requirements apply regardless of repository visibility."
      }
    },
    {
      "@type": "Question",
      "name": "How do I find the commit where a specific sample batch was added?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Run git log, oneline, grep with the batch identifier to search commit messages, then inspect the result with git show followed by the commit hash and the, stat flag."
      }
    },
    {
      "@type": "Question",
      "name": "Where should lineage and clade assignments go, in the message or in files?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Both, in different forms. The structured assignments belong in versioned table files that pipelines can consume, and the commit body should summarize the run, such as the tool version and how many samples received which lineage group."
      }
    }
  ]
}
</script>

## Sources

1. [A mixed-methods analysis of micro-collaborative coding practices in OpenStack.](https://pubmed.ncbi.nlm.nih.gov/35757446/)
2. [Telling our history: a narrative study with Indigenous elders, wisdom for the coming generation.](https://pubmed.ncbi.nlm.nih.gov/42395305/)
3. [The Social Contagion Potential of Pro-Vaccine Messages on Black Twitter.](https://pubmed.ncbi.nlm.nih.gov/37994402/)
4. [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/)