Skip to content
AI Dev Toolkit.
Esc
  • AI Token CounterCount tokens for GPT, Claude, Gemini, DeepSeek, Qwen and more.Tool
  • LLM API Cost CalculatorEstimate per-request, daily and monthly API costs.Tool
  • AI Model ComparisonCompare prices, context windows and features across models.Tool
  • AI Model Pricing PagesSpecs, real costs and cheaper alternatives for popular models.Tool
  • Context Window CheckerSee whether your text fits each model’s context window.Tool
  • Subscription vs API CalculatorFind out whether a chat plan or the API is cheaper for you.Tool
  • GPU / VRAM CalculatorCheck how much VRAM a local model needs and which GPUs fit.Tool
  • Prompt Caching CalculatorEstimate savings from prompt caching.Tool

Prompt template · Git and docs

Commit message prompt from a git diff

Turn a staged diff into a Conventional Commits subject and a body that explains why, not what. Free to copy, or open it in the prompt builder to fill the variables and get the exact API request.

415 tokens unfilled · 526 with the example below · o200k_base (GPT-4o and later)

Template

The prompt

Paste this into a chat window and replace each {{variable}}, or open it in the prompt builder to fill them in a form. Sections are marked with XML tags, which every major model reads well.

Prompt (one message, plain text)
You write clear git commit messages for a team that reads history to understand why code changed.

<context>
Why this change was made, in the author’s words:
<reason>
{{reason}}
</reason>

The staged diff:
<diff>
{{diff}}
</diff>
</context>

<examples>
<example>
<input>
Reason: login failed for emails with uppercase letters. Diff: lower-cases the email in findUserByEmail before the query.
</input>
<output>
fix(auth): match emails case-insensitively at login

Users who signed up as Info@Example.com could not log in as
info@example.com because the lookup compared emails exactly.
Addresses are now lower-cased before the query, matching how
they are stored at sign-up.
</output>
</example>
<example>
<input>
Reason: the nightly export took 40 minutes. Diff: replaces per-row inserts with a single COPY in export.py.
</input>
<output>
perf(export): load the nightly export with COPY

Inserting one row at a time made the export take about 40
minutes. A single COPY keeps it inside the maintenance window
and reduces lock time on the reporting table.
</output>
</example>
</examples>

<constraints>
- Follow Conventional Commits: type(scope): subject. Types: feat, fix, refactor, perf, test, docs, build, ci, chore.
- Subject: imperative mood, lower case after the colon, no full stop, at most 72 characters.
- Body: explain why the change was needed and anything a future reader would not see from the diff. Don’t list the files changed.
- Wrap the body at 72 characters.
- If the diff mixes unrelated changes, say so and suggest how to split it instead of writing one message.
</constraints>

<output_format>
Only the commit message, as plain text: subject line, blank line, body. No code fences or commentary.
</output_format>

<task>
Write the commit message for this diff.
</task>
For an API call: system prompt and user message

With a system prompt, the role, constraints and output format stay fixed across calls (and can be cached), while the context and task go in the user message.

System prompt
You write clear git commit messages for a team that reads history to understand why code changed.

<constraints>
- Follow Conventional Commits: type(scope): subject. Types: feat, fix, refactor, perf, test, docs, build, ci, chore.
- Subject: imperative mood, lower case after the colon, no full stop, at most 72 characters.
- Body: explain why the change was needed and anything a future reader would not see from the diff. Don’t list the files changed.
- Wrap the body at 72 characters.
- If the diff mixes unrelated changes, say so and suggest how to split it instead of writing one message.
</constraints>

<output_format>
Only the commit message, as plain text: subject line, blank line, body. No code fences or commentary.
</output_format>

<examples>
<example>
<input>
Reason: login failed for emails with uppercase letters. Diff: lower-cases the email in findUserByEmail before the query.
</input>
<output>
fix(auth): match emails case-insensitively at login

Users who signed up as Info@Example.com could not log in as
info@example.com because the lookup compared emails exactly.
Addresses are now lower-cased before the query, matching how
they are stored at sign-up.
</output>
</example>
<example>
<input>
Reason: the nightly export took 40 minutes. Diff: replaces per-row inserts with a single COPY in export.py.
</input>
<output>
perf(export): load the nightly export with COPY

Inserting one row at a time made the export take about 40
minutes. A single COPY keeps it inside the maintenance window
and reduces lock time on the reporting table.
</output>
</example>
</examples>
User message
<context>
Why this change was made, in the author’s words:
<reason>
{{reason}}
</reason>

The staged diff:
<diff>
{{diff}}
</diff>
</context>

<task>
Write the commit message for this diff.
</task>

Variables

What to put in each variable

{{reason}}
Why you made the change: the bug report, the ticket or one sentence of your own. The diff shows what changed; only you know why.
{{diff}}
The output of git diff --staged. For a very large diff, the stat summary (git diff --staged --stat) plus the key hunks works better.

Use

When to use it

Use it at commit time, in a git hook, or in an agent that commits for you. It suits teams that read history in git log and git blame, where a subject line people can scan and a body that explains intent save real time months later.

Skip the body for trivial changes such as a typo fix; the subject is enough. And read the message before committing: a fluent message that describes the wrong change is worse than a terse accurate one.

Structure

Why it’s structured this way

The reason variable is the important part. A model can describe what a diff does, but the useful half of a commit message is why, and that isn’t in the diff. Asking for it explicitly is what stops the output from becoming a list of files and functions.

Two examples show the shape faster than rules can: the subject style, the blank line, the body that explains a cause and an effect. Anthropic recommends examples for steering format, and Google’s Gemini guide recommends always including some. The examples differ in type (fix and perf) so the model doesn’t copy one pattern.

The split rule handles the most common real problem: a staged diff that contains two or three unrelated changes. One message can’t describe them well, so the honest output is a suggestion to split the commit.

Example

A filled-in example

{{reason}}
Customers on the annual plan were charged VAT twice when they upgraded mid-cycle.
{{diff}}
--- a/billing/proration.py
+++ b/billing/proration.py
@@ -41,7 +41,7 @@ def prorate(old_plan, new_plan, days_left):
     credit = old_plan.price * days_left / 365
-    charge = with_vat(with_vat(new_plan.price * days_left / 365) - credit)
+    charge = with_vat(new_plan.price * days_left / 365 - credit)
     return max(charge, 0)

What to look for. The diff alone reads as tidying up a nested with_vat call. The reason turns it into a fix(billing) commit whose body explains the customer-facing bug, which is what someone running git blame on this line will need.

The complete filled-in prompt (526 tokens)
Filled-in prompt
You write clear git commit messages for a team that reads history to understand why code changed.

<context>
Why this change was made, in the author’s words:
<reason>
Customers on the annual plan were charged VAT twice when they upgraded mid-cycle.
</reason>

The staged diff:
<diff>
--- a/billing/proration.py
+++ b/billing/proration.py
@@ -41,7 +41,7 @@ def prorate(old_plan, new_plan, days_left):
     credit = old_plan.price * days_left / 365
-    charge = with_vat(with_vat(new_plan.price * days_left / 365) - credit)
+    charge = with_vat(new_plan.price * days_left / 365 - credit)
     return max(charge, 0)
</diff>
</context>

<examples>
<example>
<input>
Reason: login failed for emails with uppercase letters. Diff: lower-cases the email in findUserByEmail before the query.
</input>
<output>
fix(auth): match emails case-insensitively at login

Users who signed up as Info@Example.com could not log in as
info@example.com because the lookup compared emails exactly.
Addresses are now lower-cased before the query, matching how
they are stored at sign-up.
</output>
</example>
<example>
<input>
Reason: the nightly export took 40 minutes. Diff: replaces per-row inserts with a single COPY in export.py.
</input>
<output>
perf(export): load the nightly export with COPY

Inserting one row at a time made the export take about 40
minutes. A single COPY keeps it inside the maintenance window
and reduces lock time on the reporting table.
</output>
</example>
</examples>

<constraints>
- Follow Conventional Commits: type(scope): subject. Types: feat, fix, refactor, perf, test, docs, build, ci, chore.
- Subject: imperative mood, lower case after the colon, no full stop, at most 72 characters.
- Body: explain why the change was needed and anything a future reader would not see from the diff. Don’t list the files changed.
- Wrap the body at 72 characters.
- If the diff mixes unrelated changes, say so and suggest how to split it instead of writing one message.
</constraints>

<output_format>
Only the commit message, as plain text: subject line, blank line, body. No code fences or commentary.
</output_format>

<task>
Write the commit message for this diff.
</task>

Models

Tips by model family

  • All models

    Keep the examples in your own team’s style. If you use a ticket number in the footer or a different type list, change the examples rather than adding more rules; they steer format more reliably.

  • Claude

    Prefilling the assistant turn (starting the reply yourself) isn’t supported on Claude 4.6 models and later and returns a 400 error. To stop preambles such as “Here’s a commit message:”, rely on the output format line, as Anthropic suggests.

  • OpenAI GPT

    With the builder’s “examples as turns” option, the examples become earlier user and assistant messages. That suits the Chat Completions and Responses APIs, and keeps the developer message short.

Related

Edited the template? Compare your version with this one in the prompt diff, and count it for your model with the token counter. In the glossary: few-shot prompting. Browse all 29 prompt templates.