#git bot interface

The .gitgraph command

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).

Don't like grammars? Don't worry, I have examples below you can crib from, including explanations.

Like 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 / "-" / "/" / "."
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]
kw-align = ("align" / "a") SPACE
kw-branch = ("branch" / "b") 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-label / cattr-mergeto / cattr-remote / cattr-tag
cattr-branch = kw-branch ref-id
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)


We'll be working our way up here. (Line breaks inserted for clarity, of course on IRC you can't use any.)

CodeGenerated 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!

  • We add branch labels to some commits.
  • The question mark dims a commit or pretty much anything, typically to show an old version/state.
  • A and A' are automatically linked to visualize commit rewriting, e.g. rebases.

The cluster split (;;) helps the layouting – in this case it helped Graphviz render the two histories in the correct order. However, this is a little hit-and-miss.

.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:

  • We can draw a dimmed HEAD and a proper one; easy!
  • HEAD is a special case of a symbolic ref; the "symref" keyword is needed if you want to draw symbolic refs with other names.
  • Two series of commits can share commits. The first usage determines where it is rendered. Generally you can reuse commit names virtually everywhere.
  • It really pays off putting any related refs in the same cluster. Experiment with putting the ;; in any different place and you'll see what I mean.
.gitgraph A[label "I like really long commit titles"] B C;

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 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: