Git graphs
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. |
Ask your agent
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.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.
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=2commit "Set up CI"branch "feature/search" from=developcommit "Add search box"commit "Index the docs"checkout developmerge "feature/search" "Add search"checkout mainmerge develop "Release 1.0" tag="v1.0" type=highlightbranch hotfix order=1commit "Fix null check" id=fixcheckout mainmerge hotfix tag="v1.0.1"checkout developcherry-pick fixcommit "Revert flaky test" type=reverseBranches, 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. |
git "Release flow" direction=down main=trunkStatements
| 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.
branch "feature/search" from=developNames 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.
branch develop order=2branch hotfix order=1Tones
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.
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=startbranch "fix/login"commit "Fix the login redirect"commit "Add a test"checkout trunkmerge "fix/login" "Merge login fix"branch "feat/export"commit "Export to CSV"commit "Export to JSON"checkout trunkcommit "Update dependencies"merge "feat/export" "Merge export" tag="v2.0" type=highlightbranch "release/1.x" from=start order=0commit "Backport the login fix"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.
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 | The language kind by kind, for flow, sequence, and schema diagrams |
| Examples to copy | Finished diagrams with the prompt that gets an agent to write each |
| Migrating from Mermaid | How a whole document converts, and every conversion code |
| Gantt charts | Plans over time, with tasks, dependencies, and milestones |
| Class diagrams | Classes, their members, and the relations between them |
| State diagrams | States and the transitions between them |
| Timelines | Events in order, grouped by period |
| User journeys | The steps of a person, each scored |
| Mind maps | A topic and the branches that grow from it |
| Language reference | Every word of the language, one page for each topic |
| Diagram kinds | The kinds Plotwork draws and their headers |