I think most people prefer learning by example, so here are the examples. If you like formal definitions, there's a grammar below.
We'll be working our way up here. (Line breaks inserted for clarity, of course on IRC you can't use any.)
Code | Generated graph |
---|---|
.gitgraph A B C | |
.gitgraph A B C; D E F[mergeto C] My first merge, yay! | |
.gitgraph A B C;; D E F[mergeto C] More spacing because the empty definition starts a cluster. | |
.gitgraph A B C;; D E F[mergeto C]; align A D Maybe we want to align the two root commits at the same level... | |
.gitgraph A B C[branch master?];; A' B' C'[branch master] Three new features at once!
The cluster split ( | |
.gitgraph A B C[tag v0.1 remote origin/master] We can do some other types of references, too. | |
.gitgraph A B C[branch master remote origin/master]; HEAD? master; symref FETCH_HEAD origin/master;; A D E[branch test]; HEAD test New lessons:
| |
.gitgraph A[label "I like really long commit titles"] B C; A D E If you want to make a commit description super verbose, you can put it as a label and still reuse the commit's original name in other parts of the definition. | |
.gitgraph A[color red] B[color green] C[color yellow] D[color blue]; E[c orange] F[c cyan] G[c pink] H[c violet]; I[c gold] ...[c silver] K[c bronze] Did someone say colours? (The full list of abbreviations is in the grammar at the bottom.) | |
.gitgraph A B; merge C B ... X[label ...]; edge C X label "this history is boring" dashed;; F; G; edge G F Thought I didn't have you covered with exotic features like octopus merges? Hah, think again. Also, notice how I can just "make up" commits as children for the merge and they will be auto-created. Whenever you mention a commit somewhere that isn't part of a sequence, it will be created as an (otherwise) unlinked commit, until you do something else that links it up. You noticed the elliptical commits, I'm sure. Basically you can use "..." once to automatically create a differently-rendered fake commit that suggests that there are more commits than the graph shows. If you want to use it a second time, well, two commits can't have the same name, hence the label trick which achieves the same look. Finally, you can use the "edge" command to add a label to an existing edge. It will not automatically create a new edge, though, as can be seen in the right part of the example. (We can also style edges using the keywords "dashed", "dim" and "dotted".) | |
Troubleshooting example | |
Attempt 1: .gitgraph A B C[branch origin/master?] D? E? F?[branch master?]; C G H I[branch origin/master]; I D' E' F'[branch master] This looks a little chaotic, doesn't it? How can we fix that? Well, ideally D-F and D'-F' would be aligned on the same level, right? Let's try that next... | |
Attempt 2: .gitgraph A B C[branch origin/master?] D? E? F?[branch master?]; C G H I[branch origin/master]; I D' E' F'[branch master]; align D? D' Wow, that's even worse! (Spoiler: if we repeat the same for E and F, it doesn't get much better...) Fortunately there's a different approach if we take a step back. We told Graphviz that D should be above C (due to the arrow between them) and D' should be above I. Can't we tell it that D should be above I, too? Yes we can! Let's check it out: | |
Attempt 3: .gitgraph A B C[branch origin/master?] D? E? F?[branch master?]; C G H I[branch origin/master]; I D' E' F'[branch master]; up I D? Say, that looks quite decent. Let's stick with this one. |
Some more remarks without examples:
master
, for example.
Here's a grammar of the language in ABNF syntax. Don't get too hung up on
the parsing ambiguities, please, I'm sure you'll understand what I mean. If in
doubt, think of the /
as the ordered-choice operator from parsing
expression grammars.
Never seen ABNF before? Don't worry, it's easy to understand if you know
the basic ideas behind grammars. Most things are self-explanatory, just the
weird number/asterisk prefixes might need some explaining. Basically
a*b
is the same as a {a,b}
suffix in most of today's
regular expression dialects (both a
and b
are
optional, as always), and an a
prefix is the same as a
{a}
suffix in regex.
UALPHA = %x41-5A
IDENT = ALPHA / DIGIT / "-" / "/" / "."
SPACE = 1*WSP
literal-string = DQUOTE *(%x00-21 / %x23-FF) DQUOTE ; strings can contain anything except double quotes; no escaping mechanism
dimmed = "?"
derived = "'"
commit-id = 1*(IDENT) [derived] [dimmed]
ref-id = 1*IDENT
auto-commit-id = (UALPHA / DIGIT) *IDENT [derived] [dimmed]
color-name = (
"blue" / "b" / "bronze" / "br" / "cyan" / "c" /
"gold" / "go" / "green" / "g" / "orange" / "o" /
"pink" / "p" / "red" / "r" / "silver" / "s" /
"violet" / "v" / "yellow" / "y"
)
kw-align = ("align" / "a") SPACE
kw-branch = ("branch" / "b") SPACE
kw-color = ("color" / "colour" / "c") SPACE
kw-commit = ("commit" / "c") SPACE
kw-dashed = ("dashed" / "-")
kw-dim = ("dim" / "d")
kw-dotted = ("dotted" / ".")
kw-edge = ("edge" / "e") SPACE
kw-label = ("label" / "l") SPACE
kw-merge = ("merge" / "m") SPACE
kw-mergeto = ("mergeto" / "m") SPACE
kw-remote = ("remote" / "r") SPACE
kw-symref = ("symref" / "s") SPACE
kw-tag = ("tag" / "t") SPACE
kw-up = ("up" / "u") SPACE
graph = ".gitgraph" SPACE definition *(*WSP ";" *WSP definition) *WSP
definition = cluster-def / align-def / commit-def / edge-def / merge-def / symref-def / up-def
cluster-def = ""
align-def = kw-align commit-id 1*(SPACE commit-id)
commit-def = (kw-commit commit / commit-short) *(SPACE commit)
commit = commit-id *WSP [commit-attrs]
commit-short = auto-commit-id *WSP [commit-attrs]
commit-attrs = "[" *WSP commit-attr *(SPACE commit-attr) *WSP "]"
commit-attr = cattr-branch / cattr-color / cattr-label / cattr-mergeto / cattr-remote / cattr-tag
cattr-branch = kw-branch ref-id
cattr-color = kw-color color-name
cattr-label = kw-label (1*IDENT / literal-string)
cattr-mergeto = kw-mergeto commit-id
cattr-remote = kw-remote ref-id
cattr-tag = kw-tag ref-id
edge-def = kw-edge commit-id commit-id edge-attrs
edge-attrs = edge-attr *(SPACE edge-attr)
edge-attr = eattr-dashed / eattr-dim / eattr-dotted / eattr-label
eattr-dashed = kw-dashed
eattr-dim = kw-dim
eattr-dotted = kw-dotted
eattr-label = kw-label (1*IDENT / literal-string)
merge-def = kw-merge commit-id 2*(SPACE commit-id)
symref-def = kw-symref ref-id / "HEAD" [dimmed]
up-def = kw-up commit-id 1*(SPACE commit-id)