# git log --pretty=format: Custom Output in CI

> git log --pretty=format:"..." emits exactly the fields a pipeline needs (SHA, author, subject), with -z for safe parsing. Reference for placeholders and pager pitfalls.

Source: https://latchkey.dev/learn/command-reference/git-log-pretty-format  
Updated: 2026-06-30

git log --pretty=format:"%H %an %s" prints only the fields you name using placeholders, the right way to get machine-readable commit data instead of parsing the default layout.

Pipelines that build changelogs or extract commit metadata should never parse the human git log output. --pretty=format with explicit placeholders gives a stable, scriptable result; -z and %x00 make it safe to split.

## What it does

git log --pretty=format:<string> renders each commit using placeholders: %H full SHA, %h short SHA, %an/%ae author name/email, %ad author date, %s subject, %b body, %d ref names. %x00 inserts a NUL for unambiguous field splitting. Combined with --no-merges, range args, and -n it produces exactly the slice a job needs.

## Common usage

```Terminal
git log --pretty=format:'%h %an %s' -n 20
# changelog since the last tag
git log --pretty=format:'- %s (%an)' v1.4.0..HEAD --no-merges
# NUL-separated fields for safe parsing
git log --pretty=format:'%H%x00%an%x00%s' -z
# ISO dates
git log --pretty=format:'%h %ad %s' --date=short
```

## Options

| Placeholder / flag | What it does |
| --- | --- |
| %H / %h | Full / abbreviated commit SHA |
| %an / %ae | Author name / email |
| %ad / %cd | Author / committer date (see --date) |
| %s / %b | Subject / body of the message |
| %x00 | Insert a NUL byte as a field separator |
| --date=<fmt> | Format dates (short, iso, unix, relative) |

## In CI

git log starts a pager when attached to a terminal; in CI it is not, so it runs straight through, but add --no-pager (or set GIT_PAGER=cat) if a wrapper allocates a TTY and the job hangs. Use %x00 with -z and split on NUL so commit subjects containing spaces or quotes do not corrupt your parser. A range like v1.4.0..HEAD needs that tag present (not shallow).

## Common errors in CI

"fatal: your current branch 'main' does not have any commits yet" means an empty repo. "fatal: ambiguous argument 'v1.4.0..HEAD'" means the tag is missing (shallow clone, tags not fetched). A hang with no output is almost always a pager on an allocated TTY; use --no-pager.

## Using this in CI

CI checkouts are shallow and detached by default, which changes the answer this command gives you. Commands that read history, branch names, or tags need the checkout configured for it.

```.github/workflows/ci.yml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0   # history, tags, and git describe all need this

- run: |
    git rev-parse --is-shallow-repository   # expect false
    git rev-parse --abbrev-ref HEAD          # prints HEAD when detached
```

> `git rev-parse --abbrev-ref HEAD` returns the literal string `HEAD` on a detached checkout rather than a branch name. On GitHub Actions read `github.ref_name` instead; the git command cannot know what it was checked out for.

## FAQ

### git log --pretty=format: Custom Output in CI?

Pipelines that build changelogs or extract commit metadata should never parse the human git log output. --pretty=format with explicit placeholders gives a stable, scriptable result; -z and %x00 make it safe to split.

### What it does?

git log --pretty=format:<string> renders each commit using placeholders: %H full SHA, %h short SHA, %an/%ae author name/email, %ad author date, %s subject, %b body, %d ref names. %x00 inserts a NUL for unambiguous field splitting. Combined with --no-merges, range args, and -n it produces exactly the slice a job needs.

### In CI?

git log starts a pager when attached to a terminal; in CI it is not, so it runs straight through, but add --no-pager (or set GIT_PAGER=cat) if a wrapper allocates a TTY and the job hangs. Use %x00 with -z and split on NUL so commit subjects containing spaces or quotes do not corrupt your parser.

### Common errors in CI?

"fatal: your current branch 'main' does not have any commits yet" means an empty repo. "fatal: ambiguous argument 'v1.4.0..HEAD'" means the tag is missing (shallow clone, tags not fetched). A hang with no output is almost always a pager on an allocated TTY; use --no-pager.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
