# Git graphs

> Page: https://docs.plotwork.dev/git-graphs. Index of every page: https://docs.plotwork.dev/llms.txt

A git graph draws a repository history as lanes: one lane for each branch, with the commits along the lanes and the merges, tags, and cherry-picks marked on them. It is for anyone who explains a branching strategy, a release process, or the story of a hotfix, in a README, a pull request, or a handbook. You write the history, so the picture shows the history you mean and not whatever a repository happens to hold.

## TL;DR

| Question | Answer |
|---|---|
| What is it for? | Showing how branches, commits, merges, tags, and cherry-picks fit together, such as a release flow or a trunk-based workflow. |
| What does the header look like? | `git "Title"`, with the optional `direction=`, `main=`, and `desc=`. |
| How is time read? | The order the statements are written is the order in time. There are no dates. |
| Which way does it run? | `direction=auto` (the default) draws left to right when that fits a Markdown column and top to bottom when it does not. `right` and `down` are taken as written. |
| What are the limits? | At most 300 commits and 24 branches (error E140). Warnings start at 40 commits and 7 branches (W200). |
| How is it colored? | Each branch takes a tone from the theme, in the order the branches are made. No color is written in the source. |
| Does Mermaid convert? | Yes: `gitGraph` becomes a git graph. See [From Mermaid](#from-mermaid). |

## Ask your agent

```text
Use Plotwork to draw a git graph of our release process. Features branch from develop and merge back into it. Develop is merged into main for release 1.0 and tagged v1.0. A hotfix branches from main, is merged back and tagged v1.0.1, and its fix is cherry-picked onto develop.
```

```text
Use Plotwork to draw a git graph of trunk-based development. Main is the only long-lived branch. Three short branches each get two or three commits and are merged back into main. Draw it top to bottom, and tag the last merge v2.0.
```

## Example

A feature is merged into develop, develop is released as v1.0, and a hotfix is tagged and picked back.

**Diagram source**

```diagram
git "Release and hotfix" desc="A feature is merged into develop, develop is released as v1.0, and a hotfix is tagged and picked back."

commit "Initial commit"
branch develop order=2
commit "Set up CI"
branch "feature/search" from=develop
commit "Add search box"
commit "Index the docs"
checkout develop
merge "feature/search" "Add search"
checkout main
merge develop "Release 1.0" tag="v1.0" type=highlight
branch hotfix order=1
commit "Fix null check" id=fix
checkout main
merge hotfix tag="v1.0.1"
checkout develop
cherry-pick fix
commit "Revert flaky test" type=reverse
```

*Picture: Release and hotfix: 10 commits on 4 branches, 3 merges, 1 cherry-pick, 2 tags. A feature is merged into develop, develop is released as v1.0, and a hotfix is tagged and picked back.*

**Text description**

**Branches, in lane order:**

- main is the default branch
- hotfix was made from main at "Release 1.0"
- develop was made from main at "Initial commit"
- feature/search was made from develop at "Set up CI"

**History, oldest first:**

**1. On main: commit "Initial commit"**

- develop was made from main at "Initial commit"

**2. On develop: commit "Set up CI"**

- feature/search was made from develop at "Set up CI"

**3. On feature/search: commit "Add search box"**

**4. On feature/search: commit "Index the docs"**

**5. On develop: merge of feature/search into develop ("Add search")**

**6. On main: merge of develop into main ("Release 1.0"), highlighted, tagged v1.0**

- hotfix was made from main at "Release 1.0"

**7. On hotfix: commit "Fix null check", id fix**

**8. On main: merge of hotfix into main, tagged v1.0.1**

**9. On develop: cherry-pick of fix ("Fix null check")**

**10. On develop: commit "Revert flaky test", a revert**

## The language

Everything is `key=value`, text is in double quotes, and a `#` starts a comment. Statements work like the commands they are named after: `commit` adds to the branch you are on, `branch` makes a branch at the newest commit and switches to it, and `checkout` switches to another.

### The header

| Part | Meaning |
|---|---|
| `git "Title"` | The first line. The title becomes the accessible name of the picture. |
| `direction=` | `auto` (the default), `right`, or `down`. |
| `main=` | The name of the default branch, which is `main` unless you rename it. |
| `desc="Summary"` | A one- or two-sentence summary. It is the alt text of the picture, so write what the history shows. |

```plotwork
git "Release flow" direction=down main=trunk
```

### Statements

| Statement | Meaning | Copyable example |
|---|---|---|
| `commit "message" id=c1 tag="v1.0" type=highlight` | A commit on the current branch. Every part is optional: with no message it is a bare dot. `id` is a name for `cherry-pick` and `from=`. `tag` may repeat, or list names with commas, up to 3. `type` is `normal`, `highlight`, or `reverse`. | `commit "Add search" id=c2 tag="v0.2"` |
| `branch name from=x order=n tone=t` | Makes a branch at the newest commit of the current branch, or of `from=` (a branch, or a commit id), and switches to it. | `branch "feature/search" from=develop order=2` |
| `checkout name` or `switch name` | New commits go on that branch. | `checkout develop` |
| `merge name "message" id=m1 tag="v1" type=t` | A merge commit on the current branch that brings in the newest commit of `name`. | `merge develop "Release 1.0" tag="v1.0"` |
| `cherry-pick id "message" tag="v1" type=t` | A copy of one commit, made on the current branch. With no message it keeps the message of the commit it copies. | `cherry-pick c3` |
| `desc "text"` | The plain-language summary, written as a statement instead of on the header. | `desc "Hotfix 1.0.1 is picked back onto main."` |

A branch name that holds a slash goes in double quotes, because a bare word cannot hold one. Writing it bare is error E100, and the hint gives the line to write.

```plotwork
branch "feature/search" from=develop
```

### Names and ids

Branch names and commit ids share one set of names, so `from=x`, `merge x`, and `cherry-pick x` mean one thing. Using a name twice is error E130. An id is letters, digits, `_` and `-`, starting with a letter. The message is what the picture shows, so put words there and keep the id short.

### Lane order

The lowest `order=` is the first lane: the top lane when the graph is drawn left to right, and the left one when it is drawn top to bottom. A branch with no `order=` takes the number of branches made before it, so the default is the order they were made in. Where two branches share a number, the one that asked for it goes first, so `order=1` is the second lane and `order=0` goes above the default branch. A branch keeps its tone when its lane moves.

Put the lanes that exchange commits next to each other. Warning W303 appears when a fork or a merge passes two or more other lanes, and its hint suggests the `order=` to write.

```plotwork
branch develop order=2
branch hotfix order=1
```

### Tones

`tone=` on a branch takes one of the tones of the language: `neutral`, `blue`, `violet`, `aqua`, `orange`, `green`, `amber`, or `red`. Leave it out and the branch takes the next tone in order. A name that is not one is error E121.

### What the picture shows

| Element | How it is drawn |
|---|---|
| Branch | A pill at the start of its lane with the branch icon and the name, in the lane's tone, and a faint dotted guide along the lane. |
| Commit | A dot in the lane's tone. Its message hangs below it, or in a column to the right of the lanes when the graph runs top to bottom. |
| `type=highlight` | The dot inside a halo tinted with the lane's color. |
| `type=reverse` | A hollow ring with a cross. |
| Fork | A line that leaves the commit a branch was made from and turns into the new lane, in the new branch's tone. |
| Merge | A ring around the merge commit in the tone of the merged branch, and a line from the merged branch's newest commit into it. |
| Cherry-pick | A dashed ring in the tone of the lane the commit came from, and a muted line under the message, `cherry-pick of c3`. The copied commit shows its id so the pick can be matched to its source. |
| Tag | A small pill with a tag glyph. |
| Branch with no commit | A short stub ending in a small ring where its first commit would be, and warning W301. |

### A second example

Three short branches leave the trunk and are merged back, and a release branch starts from an old commit by its id. It shows `main=` renaming the default branch, `direction=down`, `from=` with a commit id, `order=0` for a lane before the default branch, and a tag on a highlighted merge.

**Diagram source**

```diagram
git "Trunk-based development" direction=down main=trunk desc="Three short branches leave the trunk and are merged back within a few commits. The last merge is tagged as the 2.0 release, and a release branch starts from an old commit."

commit "Start the project" id=start
branch "fix/login"
commit "Fix the login redirect"
commit "Add a test"
checkout trunk
merge "fix/login" "Merge login fix"
branch "feat/export"
commit "Export to CSV"
commit "Export to JSON"
checkout trunk
commit "Update dependencies"
merge "feat/export" "Merge export" tag="v2.0" type=highlight
branch "release/1.x" from=start order=0
commit "Backport the login fix"
```

*Picture: Trunk-based development: 9 commits on 4 branches, 2 merges, 1 tag. Three short branches leave the trunk and are merged back within a few commits. The last merge is tagged as the 2.0 release, and a release branch starts from an old commit.*

**Text description**

**Branches, in lane order:**

- release/1.x was made from trunk at "Start the project"
- trunk is the default branch
- fix/login was made from trunk at "Start the project"
- feat/export was made from trunk at "Merge login fix"

**History, oldest first:**

**1. On trunk: commit "Start the project", id start**

- fix/login was made from trunk at "Start the project"

**2. On fix/login: commit "Fix the login redirect"**

**3. On fix/login: commit "Add a test"**

**4. On trunk: merge of fix/login into trunk ("Merge login fix")**

- feat/export was made from trunk at "Merge login fix"

**5. On feat/export: commit "Export to CSV"**

**6. On feat/export: commit "Export to JSON"**

**7. On trunk: commit "Update dependencies"**

**8. On trunk: merge of feat/export into trunk ("Merge export"), highlighted, tagged v2.0**

- release/1.x was made from trunk at "Start the project"

**9. On release/1.x: commit "Backport the login fix"**

## Limits and warnings

A history may hold at most 300 commits and 24 branches. Past either, the diagram is refused with error E140 before any layout work. Warnings never stop the picture. They point at things a reader will notice. Text is cut only past a hard limit: a message after two lines, a tag, or a branch name that is longer than its pill can hold.

### Errors

| Code | When it fires | Fix |
|---|---|---|
| E100 | A syntax error, such as a branch name with a slash that is not in quotes. | Write what the hint gives, such as `branch "feature/x"`. |
| E101 | A string with no closing quote. | Close the quote. |
| E110 | A statement the language does not have. | Use `commit`, `branch`, `checkout`, `switch`, `merge`, `cherry-pick`, or `desc`. |
| E121 | A tone that is not one of the eight. | Use one the hint lists. |
| E123 | A direction that is not `auto`, `right`, or `down`. | Use one of the three. |
| E130 | A name used twice. Branch names and commit ids share one set. | Pick a different id. |
| E131 | A `checkout`, `merge`, `from=`, or `cherry-pick` that names a branch or a commit that does not exist. | Make it first with `branch`, or fix the spelling. |
| E135 | An option the statement does not take. | Use one the hint lists. |
| E136 | A bad value for an option, such as a commit `type=` that is not `normal`, `highlight`, or `reverse`. | Use a value the hint lists. |
| E140 | More than 300 commits or 24 branches. | Split the history into several graphs. |
| E300 | A branch merged into itself. | Check out the branch that should receive the changes first. |
| E301 | A branch made before any commit, or from a branch with no commit. | Write a commit first. |
| E302 | A cherry-pick of a commit the current branch already has. | Cherry-pick a commit from another branch. |
| E303 | More than 3 tags on one commit. | Keep the tags a reader needs, or tag a later commit with the rest. |
| E304 | A history with no commit. | Add commits. |

### Warnings

| Code | When it fires | Fix |
|---|---|---|
| W200 | More than 40 commits, or more than 7 branches. | Split along a branch or a period. |
| W202 | The graph is wider than a Markdown column and its text would shrink. | Use `direction=down`, shorten messages, or split it. |
| W203 | Text was cut with an ellipsis: a message, a tag, or a branch name. | Shorten the text. |
| W300 | A merge that brings in nothing new. No line is drawn for it. | Remove the merge, or commit on the merged branch first. |
| W301 | A branch with no commit of its own, drawn as an empty stub. | Commit on it, or leave the branch out. |
| W302 | The same tag on two commits. | A tag names one commit. Rename one, for example with a patch number. |
| W303 | A fork or a merge passes two or more other lanes. | Move the lanes that exchange commits next to each other with `order=`. |

## From Mermaid

A `gitGraph` converts to a git graph. The converter replays the history as Mermaid would, so a statement that Mermaid itself would refuse is reported instead of guessed at. Header words `LR`, `TB`, and `BT`, and a trailing colon, are read.

```mermaid-source
gitGraph
  commit id: "Initial commit"
  branch develop
  checkout develop
  commit id: "Set up CI"
  checkout main
  merge develop tag: "v1.0"
```

| Mermaid | Plotwork |
|---|---|
| `commit id: "A"` | `commit "A"`. What Mermaid draws on a commit is its id, so the id becomes the message. |
| `commit "text"` and `commit msg: "text"` | `commit "text"`. |
| `commit` with no id or message | A bare dot, reported once for all of them with M220. |
| `commit id: "A" msg: "B"` | `commit "A"`, with M222, because Mermaid draws only the id. |
| `tag:` and `type: NORMAL`, `REVERSE`, `HIGHLIGHT` | `tag=` and `type=normal`, `reverse`, `highlight`. Any case is read. An unknown type is a normal commit, with M204. |
| `branch name order: 2` | `branch name order=2`. A name with a slash or a space is quoted. An order that is not a whole number from 0 to 99 is dropped, with M203. |
| `checkout name` and `switch name` | `checkout name`. A checkout of the branch you are already on is not kept. |
| `merge name id: "M" tag: "v" type: T` | `merge name "M" tag="v" type=t`. |
| `cherry-pick id: "A"` | `cherry-pick A`, and the copied commit gets `id=A`. An id that is not valid, or that is a branch name, is renamed, with M206. |
| `cherry-pick id: "A" parent: "B"` | The parent is dropped, with M221, because a cherry-pick copies one commit. |
| `gitGraph LR:`, `TB:`, or nothing | `direction=right`, `down`, or left to `auto`. |
| `gitGraph BT:` | `direction=down`, with M204, because Plotwork draws time downward. |
| `%%{init}%%` and front matter `config:` | Dropped, with M200. A front matter `title:` and `accTitle` become the title, and `accDescr` becomes the description. |

What stops the conversion or changes it:

| Code | What happened | What to do |
|---|---|---|
| M120 | The history cannot be replayed: a statement names a branch or commit that does not exist, makes a branch that already exists, merges a branch into itself, branches before the first commit, repeats an id, or cherry-picks a commit the branch already has. Nothing is converted. | Fix the line the diagnostic points at, or convert with `lenient` to skip the statements that cannot be replayed. |
| M218 | With `lenient`, a statement was skipped and the rest was converted. | Fix the Mermaid line, or add the commit by hand. |
| M110 | A line is not a gitGraph statement, or has text after its attributes. | Fix the line the diagnostic points at. |
| M102 | More than 300 commits or 24 branches. | Split the history into several graphs. |
| M220 | Commits with no id or message are drawn as bare dots. | Give the commit an `id:` if the picture should say something next to it. |
| M221 | A cherry-pick named a `parent:`, which Plotwork has no choice of. | Nothing, unless the picked commit is a merge and the parent mattered. Say which side in the commit message. |
| M222 | A commit had both an `id:` and a `msg:`, and only the id was kept. | Put the text the picture should show in the `id:`, or in the message of the Plotwork commit. |

When a directive renamed the main branch with `mainBranchName`, the directive is dropped, and a later `checkout master` is then reported as M120. The hint says so. Set `main=` on the header to keep the name.

## See also

| Doc | Why |
|---|---|
| [Writing diagrams](https://docs.plotwork.dev/writing-diagrams.md) | The language kind by kind, for flow, sequence, and schema diagrams |
| [Examples to copy](https://docs.plotwork.dev/examples.md) | Finished diagrams with the prompt that gets an agent to write each |
| [Migrating from Mermaid](https://docs.plotwork.dev/migrating-from-mermaid.md) | How a whole document converts, and every conversion code |
| [Gantt charts](https://docs.plotwork.dev/gantt-charts.md) | Plans over time, with tasks, dependencies, and milestones |
| [Class diagrams](https://docs.plotwork.dev/class-diagrams.md) | Classes, their members, and the relations between them |
| [State diagrams](https://docs.plotwork.dev/state-diagrams.md) | States and the transitions between them |
| [Timelines](https://docs.plotwork.dev/timelines.md) | Events in order, grouped by period |
| [User journeys](https://docs.plotwork.dev/user-journeys.md) | The steps of a person, each scored |
| [Mind maps](https://docs.plotwork.dev/mind-maps.md) | A topic and the branches that grow from it |
| [Language reference](https://docs.plotwork.dev/reference/language.md) | Every word of the language, one page for each topic |
| [Diagram kinds](https://docs.plotwork.dev/reference/language/kinds.md) | The kinds Plotwork draws and their headers |
