This page covers practical ways to embed large‑language‑model assistance into everyday git operations. It matters when your team spends excessive time on commit‑message discipline, PR‑description drafts, or manual conflict resolution, and you want to replace that drudgery with automated suggestions that still give you final approval before anything reaches the repository. The patterns below use only shipping tools—git, shell scripts, curl, and standard hook infrastructure—so there is no new binary to install and no vendor‑locked API to depend on.

Generate consistent commit messages

Use a commit template

git config commit.template is a real configuration key shipped with every git installation. Setting it once means every subsequent git commit pre‑fills the message buffer with the file’s contents, leaving the author only to edit or accept.

$ cat > ~/.gitmessage.txt <<'EOF'
# <short summary >  # 50 chars max

# <optional body – keep under 72 chars per line>

# Co-authored-by: $(git config user.name)
EOF

$ git config --global commit.template ~/.gitmessage.txt

Now git commit opens with those three lines already present. The template is plain text; git does not expand placeholders, so teams typically pair this with commitizen or a pre‑commit validator if stricter formatting is needed. The key advantage is that the skeleton is always present, reducing the “what belongs in a commit message?” hesitation that slows down high‑velocity branches.

Hook that pipes a diff to an LLM

A commit-msg hook runs after the message file has been prepared (by the editor, a template, or an upstream script) and before the commit is recorded. It receives the path to the message file as $1. The pattern below shows how to invoke an LLM from that hook, using only curl and environment variables that the reader controls.

Create .git/hooks/commit-msg and make it executable:

#!/usr/bin/env bash
# .git/hooks/commit-msg
set -euo pipefail

MSG_FILE="$1"
PROPOSED=$(cat "$MSG_FILE")

# If AI is disabled, just let the commit through
[[ "${AI_ENABLED:-0}" -eq 0 ]] && exit 0

# Grab the staged diff, truncated to the last 200 lines to stay within typical context windows
DIFF=$(git diff --cached --no-color | tail -n 200)

# Call the LLM endpoint; the reader sets $AI_ENDPOINT and $AI_AUTH
# The JSON payload follows the chat‑completions shape common to most hosted models.
RESPONSE=$(curl -s -X POST "$AI_ENDPOINT" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${AI_AUTH:-}" \
  -d "{\"model\":\"default\",\"messages\":[{\"role\":\"user\",\"content\":\"Based on this diff, write a one‑sentence git commit summary that follows the conventional commit format (e.g. feat: or fix:). Keep it under 72 chars. Diff:\\n$DIFF\"}]}")

# If the model returned nothing, abort the commit and surface the problem
if [ -z "$RESPONSE" ]; then
  echo "❌ AI returned no response; commit aborted." >&2
  exit 1
fi

# Prepend the AI suggestion and keep the original author‑written portion
{
  echo "AI-suggested-summary: $RESPONSE"
  echo ""
  echo "$PROPOSED"
} > "$MSG_FILE"

exit 0

A few concrete details make this runnable immediately:

  • set -euo pipefail ensures the script exits non‑zero if any command fails, preventing a silent commit.
  • git diff --cached --no-color yields the diff of staged changes only; tail -n 200 caps the payload. Full diffs routinely exceed 100 k tokens, which most hosted models reject or truncate unpredictably.
  • The curl flags (-s, -X, -H, -d) are part of the standard tool, not product‑specific. The $AI_ENDPOINT and $AI_AUTH placeholders are meant to be replaced with the reader’s actual model endpoint and bearer token—e.g., an OpenAI key, a self‑hosted inference URL, or an internal proxy.
  • The script writes the AI suggestion as a prefixed line (AI-suggested-summary:), then appends the author’s original text. This keeps the final message under the author’s control while providing a concrete starting point.

If the hook exits with status 1 (e.g., the LLM returns empty or the network is unavailable), git aborts the commit and prints the stderr output. If it exits 0, the message file contains the merged human‑plus‑AI text and the commit proceeds.

Draft PR bodies and release notes

Generating a PR description from commit history is a common AI‑enhancement. The reader already has the commit graph; the goal is to turn it into a readable narrative that a reviewer can accept or edit.

A typical flow:

  1. Extract the commit log
   $ git log --pretty=format:"%h %s%n%b" --no-merges > /tmp/commits.txt
  1. Format a prompt for the LLM (the same curl pattern from the previous section can be reused, only the user‑prompt changes):
   $ cat > /tmp/pr-prompt.txt <<'EOF'
   Given these git commits, write a concise pull‑request description for a general engineering audience. Include:
   • A one‑sentence summary in the style of a conventional commit title.
   • A bullet list of user‑visible changes, one per commit.
   • Any known breaking changes or migration steps.
   Keep the total length under 300 words.
   EOF
  1. Post the prompt to the LLM and capture the response
   $ RESPONSE=$(curl -s -X POST "$AI_ENDPOINT" \
       -H "Content-Type: application/json" \
       -H "Authorization: Bearer ${AI_AUTH:-}" \
       -d "{\"model\":\"default\",\"messages\":[{\"role\":\"user\",\"content\":\"$(cat /tmp/pr-prompt.txt)\"]}}")

   $ echo "$RESPONSE" > /tmp/pr-body.txt
  1. Post the body to the git host’s API – the HTTP pattern is generic; each platform documents its own endpoint. For many hosts the request looks like:
   $ curl -X POST \
       -H "Authorization: token $GIT_HOST_TOKEN" \
       -F "title=Feature XYZ" \
       -F "body=$(cat /tmp/pr-body.txt)" \
       "$BASE_URL/api/.../merge_requests"

Consult your platform’s documentation for the exact path, required fields, and auth scheme. The curl flags and the -F multipart format are standard; only the URL and token name vary.

This workflow replaces the “copy‑paste from changelog” step with a single command sequence. The generated body is a starting point; a human still reviews, trims, and publishes.

AI-assisted conflict navigation

Rebases and merges inevitably produce conflicts. When they do, an LLM can suggest a resolution, but the mechanic is fragile and the sharp edges are well‑known.

Extract the conflicting hunk

After a git rebase -i stops at a conflict, the two versions of the file exist in the working tree. To feed an LLM a minimal, focused input, extract the exact hunk that’s in conflict:

$ git diff --ours HEAD -- <path> > /tmp/ours.txt
$ git diff --theirs HEAD -- <path> > /tmp/theirs.txt
$ head -n 30 /tmp/ours.txt   # show the first ~30 lines of each side

Truncating to the first few dozen lines is usually sufficient; the LLM does not need the full file to propose a merge.

Pipe the hunk to the LLM

A compact prompt works best:

$ cat > /tmp/conflict-prompt.txt <<'EOF'
The following two versions of <path> conflict during a git rebase. 
Write a single merged version that preserves the intent of both sides, 
removes duplicate logic, and keeps the file syntactically valid for a Python/JS/Java module (whichever applies). 
Return only the merged file content, no explanations.
EOF

$ RESPONSE=$(curl -s -X POST "$AI_ENDPOINT" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${AI_AUTH:-}" \
  -d "{\"model\":\"default\",\"messages\":[{\"role\":\"user\",\"content\":\"$(cat /tmp/conflict-prompt.txt)\"]}}")

Apply the suggestion (or reject it)

If the response is non‑empty, write it back to the file and continue the rebase:

$ echo "$RESPONSE" > <path>
$ git add <path>
$ git rebase --continue

If the response is empty or the file fails to parse, the rebase will pause again with the original conflict markers intact. At that point the operator can:

  • Edit the file manually,
  • Use git mergetool to invoke a visual resolver,
  • Abort the rebase with git rebase --abort.

Real error text you’ll see

  • error: could not apply <commit> – git’s standard message when a rebase patch cannot be recorded.
  • CONFLICT (content): Merge conflict in <path> – appears after git rebase --continue if the working tree still contains <<<<<<<, =======, >>>>>>> markers.
  • git apply failed – if the LLM output contains syntax that prevents the file from being read (e.g., unclosed strings, invalid indentation).

Sharp edge: AI‑suggested merges often introduce subtle semantic changes—renaming a variable, reordering imports, or adjusting whitespace—that compile or pass tests but alter runtime behavior. Always run the project’s test suite after a git rebase --continue that used an LLM suggestion. If the suite fails, the rebase can be aborted and the conflict resolved by hand.

Hook integration patterns that actually work

Two hook points are most frequently used for AI insertion: commit-msg and pre-commit. Choosing the right one depends on whether you want to act on the *final* message or on the *staged* tree.

HookWhen it firesWhat it seesTypical AI use
commit-msgAfter the message buffer is filled (editor, template, or previous hook)The exact text the author typed or had pre‑filledGenerate or validate commit‑message format, add AI‑suggested footers, abort on empty messages
pre-commitBefore git commit runs, before the message is even promptedThe staged diff (git diff --cached) and the index stateLint staged code, run security checks, suggest a commit‑message skeleton based on the diff

Many teams start with commit-msg because it’s simpler: the message already exists, so the hook only needs to read $1, optionally augment it, and exit. The pre‑commit hook requires computing the diff, which adds a small overhead and can be skipped if the user passes git commit --no-verify.

A minimal pre‑commit example that calls the same LLM endpoint as the commit‑msg hook:

#!/usr/bin/env bash
# .git/hooks/pre-commit
set -euo pipefail

# Only run when explicitly opted in
[[ "${AI_PRECOMMIT:-0}" -eq 1 ]] || exit 0

DIFF=$(git diff --cached --no-color | tail -n 150)

RESPONSE=$(curl -s -X POST "$AI_ENDPOINT" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${AI_AUTH:-}" \
  -d "{\"model\":\"default\",\"messages\":[{\"role\":\"user\",\"content\":\"Based on this staged diff, write a one‑sentence conventional‑commit summary (feat:/fix:/docs:). Keep under 72 chars. Diff:\\n$DIFF\"}]}")

if [ -z "$RESPONSE" ]; then
  echo "⚠️  AI pre‑commit hook: no response; proceeding without interference." >&2
  exit 0
fi

# Store the suggestion so the later commit‑msg hook can incorporate it
echo "AI-pre-commit-summary: $RESPONSE" > .ai-commit-note
exit 0

The commit‑msg hook can then read .ai‑commit‑note and prepend its content, ensuring a coherent flow from staged diff to final message.

Which to use? If your primary pain point is “my teammates write terrible commit messages,” start with commit‑msg. If you want to enforce code‑quality gates before a message is even asked for, add a pre‑commit hook. Both can coexist; just ensure they don’t both exit 1 for the same commit, or the workflow stalls.

Sharp edges: what silently fails, which options are confused, what you only learn after it breaks in production

SymptomRoot causeWhat to check
Commit proceeds with an empty or “AI‑suggested‑summary: ” lineThe curl request returned a non‑zero HTTP status or an empty JSON choices array, but the script still wrote the line and exited 0Verify $AI_ENDPOINT returns 200 OK; add set -x to the hook to see the raw curl output on failure
git commit aborts even when the LLM respondedThe script exits 1 on empty $RESPONSE, but the LLM returned a valid JSON with an empty content fieldInspect the curl response body; adjust the [ -z "$RESPONSE" ] check to also look for "content": ""
CI pipeline times out after a git rebase that used an LLM suggestionThe LLM endpoint rate‑limits or the diff payload exceeds the model’s context window, causing the hook to hang on curl timeoutSet a curl timeout (--max-time 30) and truncate the diff more aggressively (tail -n 100 instead of 200)
standard-version or release‑please skips a commit because the title doesn’t match Conventional CommitsThe AI suggestion uses a custom prefix (e.g., feature: instead of feat:) or omits the prefix entirelyPost‑process the AI output: `echo "$RESPONSE"grep -qE "^(featfixdocsstylerefactorperftest):"RESPONSE="fix: $RESPONSE"`
AI_ENABLED=1 left in a CI job’s environment, causing thousands of API callsThe env var is set globally (e.g., in a Dockerfile) and every git commit in the pipeline hits the LLMScope the env var to specific branches or interactive shells only; add a guard [[ "$CI" != "true" ]] && exit 0 in non‑interactive contexts
commit.template appears to have no effect on a fresh cloneThe config is set --global but the repo has a local commit.template that overrides itRun git config --local --unset commit.template or use --global consistently; remember that per‑repo config takes precedence

Confused options

  • --message (-m) vs. --template (-t, configured via commit.template): -m writes the exact string you pass and overrides any template. If you want a skeleton that the author can edit, use the config key, not -m.
  • pre‑commit vs. commit‑msg: pre‑commit runs before the message is prompted; commit‑msg runs after. Mixing them without a coordination mechanism (e.g., a temporary file) can cause one hook to clobber the other’s output.
  • git diff --cached vs. git diff: --cached shows staged changes only; shows both staged and unstaged. If your AI prompt expects only staged changes, be explicit about the flag.

Production‑learned lessons

  • Always validate the LLM output before writing it back. A malformed JSON payload or an unexpected model version can cause the hook to emit garbage, which then becomes part of the commit metadata (visible in git log --format="%s").
  • Cache the diff size. Computing git diff --cached on a repository with hundreds of staged files can take seconds; pipe through wc -l first and skip the LLM call if the line count exceeds your threshold (e.g., 500 lines).
  • Tie the hook exit code to the actual decision. Exiting 0 without writing anything to the message file silently accepts the status‑quo; exiting 1 aborts the commit. Document which exit code means “use AI suggestion,” “skip AI,” and “abort” so that future maintainers don’t invert the logic.
  • Keep a fallback. If the LLM call fails (network error, timeout, rate‑limit), the hook should still allow the commit to proceed—perhaps with a prefixed note like # AI‑suggestion‑failed – please write manually. Never let a down‑stream dependency be the sole gate between the developer and a merged branch.

By grounding each pattern in real git configuration, standard curl invocations, and well‑documented hook mechanics, the workflow stays portable across operating systems, git versions, and hosting platforms—without tying your team to a specific product’s SDK or config schema. The concrete commands above can be dropped into a repo today; the surrounding guardrails ensure they remain reliable as your codebase and team grow.

This page was rewritten on 14 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at hello@vibecodewiki.ai and we will correct it.