123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- <?php
- require("user.inc.php");
- require("template.inc.php");
- tpl_header();
- ?>
- <h2>The .gitgraph command</h2>
- <p>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).
- <p><strong>Don't like grammars?</strong> Don't worry, I have examples below
- you can crib from, including explanations.
- <p>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
- <code>a*b</code> is the same as a <code>{a,b}</code> suffix in most of today's
- regular expression dialects (both <code>a</code> and <code>b</code> are
- optional, as always), and an <code>a</code> prefix is the same as a
- <code>{a}</code> suffix in regex.
- <pre><code class="abnf">
- 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]
- 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)
- </code></pre>
- <h3>Examples</h3>
- <p>We'll be working our way up here. (Line breaks inserted for clarity, of
- course on IRC you can't use any.)
- <table class="large">
- <tr><th>Code</th><th>Generated graph</th></tr>
- <tr><td><pre class="wrap">
- .gitgraph A B C
- </pre></td><td><img src="/g/NT.png"></td></tr>
- <tr><td><pre class="wrap">
- .gitgraph A B C;
- D E F[mergeto C]
- </pre>
- <p>My first merge, yay!
- </td><td><img src="/g/NU.png"></td></tr>
- <tr><td><pre class="wrap">
- .gitgraph A B C;;
- D E F[mergeto C]
- </pre>
- <p>More spacing because the empty definition starts a cluster.
- </td><td><img src="/g/NV.png"></td></tr>
- <tr><td><pre class="wrap">
- .gitgraph A B C;;
- D E F[mergeto C];
- align A D
- </pre>
- <p>Maybe we want to align the two root commits at the same level...
- </td><td><img src="/g/OC.png"></td></tr>
- <tr><td><pre class="wrap">
- .gitgraph A B C[branch master?];;
- A' B' C'[branch master]
- </pre>
- <p>Three new features at once!
- <ul>
- <li>We add branch labels to some commits.
- <li>The question mark <em>dims</em> a commit or pretty much anything,
- typically to show an old version/state.
- <li><code>A</code> and <code>A'</code> are automatically linked to visualize
- commit rewriting, e.g. rebases.
- </ul>
- <p>The cluster split (<code>;;</code>) 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.
- </td><td><img src="/g/OD.png"></td></tr>
- <tr><td><pre class="wrap">
- .gitgraph A B C[tag v0.1 remote origin/master]
- </pre>
- <p>We can do some other types of references, too.
- </td><td><img src="/g/NY.png"></td></tr>
- <tr><td><pre class="wrap">
- .gitgraph A B C[branch master remote origin/master];
- HEAD? master;
- symref FETCH_HEAD origin/master;;
- A D E[branch test];
- HEAD test
- </pre>
- <p>New lessons:
- <ul>
- <li>We can draw a dimmed HEAD and a proper one; easy!
- <li>HEAD is a special case of a symbolic ref; the "symref" keyword is needed
- if you want to draw symbolic refs with other names.
- <li>Two series of commits can share commits. The first usage determines
- where it is rendered. Generally you can reuse commit names virtually
- everywhere.
- <li>It really pays off putting any related refs in the same cluster.
- Experiment with putting the <code>;;</code> in any different place and
- you'll see what I mean.
- </ul></td><td><img src="/g/N-.png"></td></tr>
- <tr><td><pre class="wrap">
- .gitgraph A[label "I like really long commit titles"] B C;
- A D E
- </pre>
- <p>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.
- </td><td><img src="/g/O0.png"></td></tr>
- <tr><td><pre class="wrap">
- .gitgraph A B;
- merge C B ... X[label ...];
- edge C X label "this history is boring" dashed;;
- F; G; edge G F
- </pre>
- <p>Thought I didn't have you covered with exotic features like octopus merges?
- Hah, think again.
- <p>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.
- <p>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.
- <p>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".)
- </td><td><img src="/g/Pc.png"></td></tr>
- <tr><th colspan="2">Troubleshooting example</th></tr>
- <tr><td><p>Attempt 1:
- <pre class="wrap">
- .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]
- </pre>
- <p>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...
- </td><td><img src="/g/OL.png"></td></tr>
- <tr><td><p>Attempt 2:
- <pre class="wrap">
- .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];
- <strong>align D? D'</strong>
- </pre>
- <p>Wow, that's even worse! (Spoiler: if we repeat the same for E and F, it
- doesn't get much better...)
- <p>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:
- </td><td><img src="/g/OM.png"></td></tr>
- <tr><td><p>Attempt 3:
- <pre class="wrap">
- .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];
- <strong>up I D?</strong>
- </pre>
- <p>Say, that looks quite decent. Let's stick with this one.
- </td><td><img src="/g/OR.png"></td></tr>
- </table>
- <p>Some more remarks without examples:
- <ul>
- <li>Commits and all ref types share the same namespace. You can't have a
- commit and a branch that are both called <code>master</code>, for example.
- <li>You can use the <code>edge</code> keyword to link arbitrary nodes if you
- really want to, but please don't. I'm not sure my sanity will survive that.
- </ul>
- <script src="hljs/highlight.pack.js"></script>
- <script>hljs.highlightAll();</script>
- <?php tpl_footer();
|