# Managing the changelog from GitHub

You can keep a changelog's entries in a GitHub repository, one Markdown file per entry. Merging to the connected branch publishes, deleting a file unpublishes, and, if you choose, changes made in the EvoHub console go back to the repository as pull requests. It works the same way as [GitHub sync for Docs](https://docs-dev.evohub.io/github-sync.md).

## The repository layout

EvoHub reads one folder of one branch, `changelog/` unless you choose another (or the repository root). Every Markdown file in it is one entry:

```text
changelog/
├── 2026-10-10-faster-search.md
├── 2026-10-02-dark-mode.md
├── 2026/                       subfolders are fine
│   └── 2026-01-15-sso.md
├── images/
│   └── search.png              linked from entries by relative path
├── _drafts/
│   └── ideas.md                skipped: the name starts with _
└── README.md                   skipped
```

- Every `.md` or `.markdown` file in the folder or its subfolders is an entry.
- Skipped: `README.md`, `index.md`, and any file or folder whose name starts with `_` or `.`. Use a `_drafts/` folder for notes that are not entries yet.
- A file's **address** (slug) is its `slug` in the front matter, else its file name without the extension and without a leading date: `2026-10-10-faster-search.md` is `/faster-search`. Slugs are unique within a changelog.

### Front matter

A YAML block between two `---` lines at the top of the file, then the body in Markdown:

```markdown
---
title: Faster search
date: 2026-10-10
categories: [Improved]
tags: [search, performance]
version: 2.4.0
cover: ./images/search.png
author: Ada Lovelace
summary: Search answers in half the time.
pinned: false
draft: false
notify: false
slug: faster-search
---

Search now answers in half the time. ![Results](./images/search.png)
```

| Key | What it does |
| --- | --- |
| `title` | The entry's title. Without it, a first line `# Heading` is the title (and is left out of the body). |
| `date` (or `published_at`) | The date shown on the entry. A date in the future **schedules** the entry for that moment. `2026-10-10` means midnight UTC; add a time (`2026-10-10T09:00:00Z`) to be exact. Without a date, the entry shows when it was published. |
| `categories` | Category names or slugs, as a list or comma-separated. A category the changelog does not have yet is created. At most 5. |
| `tags` | Free tags, as a list or comma-separated. At most 10. |
| `version` | The release it belongs to, kept exactly as written. |
| `cover` | A cover image: a path relative to the file, or an `https` address. |
| `author` | The author name shown on the entry. |
| `summary` | One or two sentences for lists, feeds and email. |
| `pinned` | `true` keeps the entry at the top of the changelog. |
| `draft` | `true` keeps the entry off the changelog. Setting it on a published entry unpublishes it. |
| `notify` | `true` emails subscribers and calls your webhooks when the entry is published for the first time. **Off unless the file says so.** |
| `slug` | The entry's address. |

Unknown keys are ignored and listed as warnings. Quote values that contain a colon: `title: "Search: twice as fast"`.

### Images

Link images relative to the file (`./images/search.png`, `../shared/logo.svg`) or from the repository root (`/assets/logo.png`). A sync uploads them to the changelog's files — PNG, JPEG, WebP, GIF or SVG, up to 5 MB each, the same checks as an upload in the editor — and the entry points at the uploaded copy. Images already on the web (`https://…`) are left as they are.

## One branch per changelog

Each changelog follows one branch. Keep the same `changelog/` folder on each branch and give each environment its own changelog:

| Branch | Changelog |
| --- | --- |
| `dev` | the changelog on your staging or development domain |
| `main` | the production changelog |

Work on a branch from `dev`, merge to `dev` to see the entry on the development changelog, then merge `dev` into `main` to publish it in production — the same flow as code.

## Connect a repository

You need permission to manage changelogs (`changelog:site:write`), you must be signed in as a person, and you need to be able to install a GitHub app on the repository.

:::steps
### Start from the changelog
Open the changelog's **Settings**, **GitHub** and choose **Connect GitHub**.

### Install the EvoHub app on GitHub
GitHub opens. Install the EvoHub app on your account or organization and give it access to the repository. If your GitHub organization requires an owner's approval, connect again once it is approved.

### Choose what to sync
Back in EvoHub, choose the **Repository**, the **Branch** and the **Folder** (`changelog` by default; leave it empty for the repository root).

### Decide about pull requests
Turn on **Open a pull request with changes made in EvoHub** if what you publish in the console should go back to the repository. You can change this later.

### Save
Save. The first sync starts right away.
:::

The GitHub tab then shows the repository, branch and folder, the result of the **last sync** (how many entries were created, updated, published, scheduled, sent to review or unpublished) and the **last push**, and any errors or warnings for individual files, with the line they are on. **Sync now** reads every file again.

## What a sync does

A sync runs after every push to the connected branch, usually within a minute.

- **A new or changed file** updates its entry's draft and publishes it. A future `date` schedules it instead, and `draft: true` keeps it off the changelog.
- **A deleted file** unpublishes its entry. The entry stays in EvoHub (delete it there if you want it gone) and is no longer tied to a file.
- **A renamed or moved file** keeps its entry, as long as its slug stays the same.
- **A file with an error** (no title, a date that is not a date, more than five categories) is skipped and listed with its line number; the rest of the changelog still syncs.
- **If the folder is empty or missing**, nothing is unpublished: the sync stops with an error instead.
- If a file's slug is already used by another entry, the entry gets the next free one (`faster-search-2`) and the sync lists a warning.
- In the console, **GitHub** is shown as whoever created or last changed an entry through a sync.

### With review turned on

If the changelog requires review (see [Writing entries](https://docs-dev.evohub.io/writing-entries.md)), a sync never publishes or schedules. New and changed entries go to **In review**, and a reviewer publishes them in EvoHub as usual. Merging to the branch is then "ready for review", not "live".

## Editing in EvoHub

You can still edit entries in the console. What happens next depends on **Open a pull request with changes made in EvoHub**:

- **Off**: console edits stay in EvoHub. The next time the file changes on GitHub, you are asked which version to keep (see Conflicts).
- **On**: publishing, unpublishing and deleting in EvoHub — and scheduled entries going live — write back to the repository. Commits go to a branch named `evohub/changelog-<changelog address>` and a pull request titled "Changelog edits from EvoHub" is opened; later changes join the same pull request while it is open. A new entry gets a file named `<folder>/<date>-<slug>.md`, an unpublished entry is written with `draft: true`, and a deleted entry's file is deleted. Your connected branch and the repository's default branch are never written to directly. When you merge the pull request, the next sync recognises the files as its own and changes nothing.

## Conflicts

If the same entry changed both in EvoHub and in its file on GitHub since they last matched — or its file was deleted after it was edited in EvoHub — nothing is overwritten. The entry is flagged in the editor and listed in the GitHub tab. For each one choose:

- **Keep EvoHub's**: the entry stays as it is in EvoHub. With pull requests on, the next push replaces the file.
- **Keep GitHub's**: the file replaces the entry's draft on the next sync (and publishes it, unless the changelog requires review). Your EvoHub edits to it are lost.

Resolving a conflict needs permission to publish entries.

## Disconnect

**Disconnect** in the GitHub tab removes the link between entries and files. The entries stay as they are. If the app is uninstalled or loses access to the repository on GitHub, the connection shows as disconnected and **Reconnect** picks up where it left off.

## Related

- [Writing entries](https://docs-dev.evohub.io/writing-entries.md)
- [Reaching readers](https://docs-dev.evohub.io/reaching-readers.md)
- [Changelog settings](https://docs-dev.evohub.io/changelog-settings.md)
- [GitHub sync for Docs](https://docs-dev.evohub.io/github-sync.md)
