correl.github.io/_posts/2015-07-12-git-graphs.html

2001 lines
158 KiB
HTML
Raw Permalink Normal View History

2015-07-11 02:04:59 +00:00
---
title: Drawing Git Graphs with Graphviz and Org-Mode
author: Correl Roush
tags: emacs org-mode git graphviz
---
<style type="text/css">
svg text {
fill: white;
}
svg path,
svg polygon,
svg ellipse {
stroke: white;
}
</style>
<p>
Digging through Derek Feichtinger's <a href="https://github.com/dfeich/org-babel-examples">org-babel examples</a> (which I came
across via <a href="http://irreal.org/blog/?p=4162">irreal.org</a>), I found he had some great examples of
displaying git-style graphs using graphviz. I thought it'd be a fun
exercise to generate my own graphs based on his graphviz source using
elisp, and point it at actual git repos.
</p>
<div id="outline-container-sec-1" class="outline-2">
<h2 id="sec-1">Getting Started</h2>
<div class="outline-text-2" id="text-1">
<p>
I started out with the goal of building a simple graph showing a
mainline branch and a topic branch forked from it and eventually
merged back in.
</p>
<p>
Using Derek's example as a template, I described 5 commits on a master
branch, plus two on a topic branch.
</p>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">G</span> {
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
node[<span style="color: #268bd2;">width=</span>0.15, <span style="color: #268bd2;">height=</span>0.15, <span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>];
edge[<span style="color: #268bd2;">weight=</span>2, <span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
node[<span style="color: #268bd2;">group=</span>master];
1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5;
node[<span style="color: #268bd2;">group=</span>branch];
2 -&gt; 6 -&gt; 7 -&gt; 4;
}
</pre>
</div>
<p>
The resulting image looks like this:
</p>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: G Pages: 1 -->
<svg width="253pt" height="52pt"
viewBox="0.00 0.00 252.80 51.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 47.8)">
<title>G</title>
<!-- 1 -->
<g id="node1" class="node"><title>1</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2 -->
<g id="node2" class="node"><title>2</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge1" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M10.8594,-38.4C19.4466,-38.4 38.1856,-38.4 46.7587,-38.4"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge2" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M57.6181,-38.4C73.0565,-38.4 124.509,-38.4 140.21,-38.4"/>
</g>
<!-- 6 -->
<g id="node6" class="node"><title>6</title>
<ellipse fill="black" stroke="black" cx="99" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge5" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M57.0196,-35.5864C65.4836,-29.3518 85.7351,-14.4344 94.19,-8.20644"/>
</g>
<!-- 4 -->
<g id="node4" class="node"><title>4</title>
<ellipse fill="black" stroke="black" cx="192.6" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge3" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M151.259,-38.4C159.847,-38.4 178.586,-38.4 187.159,-38.4"/>
</g>
<!-- 5 -->
<g id="node5" class="node"><title>5</title>
<ellipse fill="black" stroke="black" cx="239.4" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge4" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M198.059,-38.4C206.647,-38.4 225.386,-38.4 233.959,-38.4"/>
</g>
<!-- 7 -->
<g id="node7" class="node"><title>7</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 6&#45;&gt;7 -->
<g id="edge6" class="edge"><title>6&#45;&gt;7</title>
<path fill="none" stroke="black" d="M104.459,-5.4C113.047,-5.4 131.786,-5.4 140.359,-5.4"/>
</g>
<!-- 7&#45;&gt;4 -->
<g id="edge7" class="edge"><title>7&#45;&gt;4</title>
<path fill="none" stroke="black" d="M150.62,-8.21356C159.084,-14.4482 179.335,-29.3656 187.79,-35.5936"/>
</g>
</g>
</svg>
</div>
<div id="outline-container-sec-1-1" class="outline-3">
<h3 id="sec-1-1">Designing the Data Structure</h3>
<div class="outline-text-3" id="text-1-1">
<p>
The first thing I needed to do was describe my data structure. Leaning
on my experiences reading and working through <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CB8QFjAA&url=https%253A%252F%252Fmitpress.mit.edu%252Fsicp%252F&ei=lH6gVau5OIGR-AG8j7yACQ&usg=AFQjCNHTCXQK7qN-kYibdy_MqRBWxlr8og&sig2=Lu9WIhyuTJS92e8hxne0Aw&bvm=bv.97653015,d.cWw">SICP</a>, I got to work
building a constructor function, and several accessors.
</p>
<p>
I decided to represent each node on a graph with an id, a list of
parent ids, and a group which will correspond to the branch on the
graph the commit belongs to.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/make-node</span> <span style="color: #b58900;">(</span><span style="color: #b6a0e0;">id</span> <span style="color: #b58900;">&amp;optional</span> <span style="color: #a6bb99;">parents</span> <span style="color: #a7aac0;">group</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #b6a0e0;">id</span> <span style="color: #a6bb99;">parents</span> <span style="color: #a7aac0;">group</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-id</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #a7aac0;">0</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-parents</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #9999bb;">1</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-group</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #a6bb99;">2</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
</div>
</div>
<div id="outline-container-sec-1-2" class="outline-3">
<h3 id="sec-1-2">Converting the structure to Graphviz</h3>
<div class="outline-text-3" id="text-1-2">
<p>
Now that I had my data structures sorted out, it was time to step
through them and generate the graphviz source that'd give me the
nice-looking graphs I was after.
</p>
<p>
The graph is constructed using the example above as a template. The
nodes are defined first, followed by the edges between them.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/to-graphviz"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz</span> <span style="color: #b58900;">(</span><span style="color: #b6a0e0;">id</span> <span style="color: #e0d0a0;">nodes</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a7c0b9;">string-join</span>
<span style="color: #268bd2;">(</span><span style="color: #b3c0a7;">list</span>
<span style="color: #6c71c4;">(</span><span style="color: #c0a7bd;">concat</span> <span style="color: #2aa198;">"digraph "</span> <span style="color: #b6a0e0;">id</span> <span style="color: #2aa198;">" {"</span><span style="color: #6c71c4;">)</span>
<span style="color: #2aa198;">"bgcolor=\"transparent\";"</span>
<span style="color: #2aa198;">"rankdir=\"LR\";"</span>
<span style="color: #2aa198;">"node[width=0.15,height=0.15,shape=point,fontsize=8.0];"</span>
<span style="color: #2aa198;">"edge[weight=2,arrowhead=none];"</span>
<span style="color: #6c71c4;">(</span><span style="color: #a7c0b9;">string-join</span>
<span style="color: #859900;">(</span><span style="color: #859900; font-weight: bold;">-map</span> #'<span style="color: #bb99b4;">git-graph/to-graphviz-node</span> <span style="color: #e0d0a0;">nodes</span><span style="color: #859900;">)</span>
<span style="color: #2aa198;">"\n"</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a7c0b9;">string-join</span>
<span style="color: #859900;">(</span><span style="color: #859900; font-weight: bold;">-uniq</span> <span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">-flatten</span> <span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">-map</span> #'<span style="color: #9999bb;">git-graph/to-graphviz-edges</span> <span style="color: #e0d0a0;">nodes</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span>
<span style="color: #2aa198;">"\n"</span><span style="color: #6c71c4;">)</span>
<span style="color: #2aa198;">"}"</span><span style="color: #268bd2;">)</span>
<span style="color: #2aa198;">"\n"</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
For the sake of readability, I'll format the output:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/to-graphviz"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-pretty</span> <span style="color: #b58900;">(</span><span style="color: #b6a0e0;">id</span> <span style="color: #e0d0a0;">nodes</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">with-temp-buffer</span>
<span style="color: #268bd2;">(</span><span style="color: #a7aac0;">graphviz-dot-mode</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #a7c0b9;">insert</span> <span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">git-graph/to-graphviz</span> <span style="color: #b6a0e0;">id</span> <span style="color: #e0d0a0;">nodes</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #a6bb99;">indent-region</span> <span style="color: #6c71c4;">(</span><span style="color: #99bbb4;">point-min</span><span style="color: #6c71c4;">)</span> <span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">point-max</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">buffer-string</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
Each node is built, setting its group attribute when applicable.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #c0afa7;">node-id</span> <span style="color: #859900;">(</span><span style="color: #c0afa7;">git-graph/to-graphviz-node-id</span>
<span style="color: #b58900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #c0a7bd;">concat</span> <span style="color: #c0afa7;">node-id</span>
<span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">--if-let</span> <span style="color: #859900;">(</span><span style="color: #b6a0e0;">git-graph/node-group</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #c0a7bd;">concat</span> <span style="color: #2aa198;">"[group=\""</span> <span style="color: #268bd2;">it</span> <span style="color: #2aa198;">"\"]"</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #2aa198;">";"</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
Graphviz node identifiers are quoted to avoid running into issues with
spaces or other special characters.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/to-graphviz-nodes"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node-id</span> <span style="color: #b58900;">(</span><span style="color: #b6a0e0;">id</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a0d6e0;">format</span> <span style="color: #2aa198;">"\"%s\""</span> <span style="color: #b6a0e0;">id</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
For each node, an edge is built connecting the node to each of its
parents.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/to-graphviz-edges"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-edges</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #c0afa7;">node-id</span> <span style="color: #859900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">parents</span> <span style="color: #859900;">(</span><span style="color: #a7c0b9;">git-graph/node-parents</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">-map</span> <span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #859900;">(</span><span style="color: #a7c0b9;">parent</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #b3c0a7;">git-graph/to-graphviz-edge</span> <span style="color: #c0afa7;">node-id</span> <span style="color: #a7c0b9;">parent</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #a6bb99;">parents</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-edge</span> <span style="color: #b58900;">(</span><span style="color: #a3e0a0;">from</span> <span style="color: #e0a0bc;">to</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #c0a7bd;">concat</span>
<span style="color: #268bd2;">(</span><span style="color: #c0afa7;">git-graph/to-graphviz-node-id</span> <span style="color: #e0a0bc;">to</span><span style="color: #268bd2;">)</span>
<span style="color: #2aa198;">" -&gt; "</span>
<span style="color: #268bd2;">(</span><span style="color: #c0afa7;">git-graph/to-graphviz-node-id</span> <span style="color: #a3e0a0;">from</span><span style="color: #268bd2;">)</span>
<span style="color: #2aa198;">";"</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
With that done, the simple graph above could be generated with the
following code:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-example"><span style="color: #2aa198;">(</span><span style="color: #b6a0e0;">git-graph/to-graphviz-pretty</span>
<span style="color: #2aa198;">"example"</span>
<span style="color: #b58900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #9999bb;">1</span> <span style="color: #bb99b4;">nil</span> <span style="color: #2aa198;">"master"</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a6bb99;">2</span> '<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">1</span><span style="color: #6c71c4;">)</span> <span style="color: #2aa198;">"master"</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #e0a0bc;">3</span> '<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">2</span><span style="color: #6c71c4;">)</span> <span style="color: #2aa198;">"master"</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a0d6e0;">4</span> '<span style="color: #6c71c4;">(</span><span style="color: #e0a0bc;">3</span> <span style="color: #e0a0bc;">7</span><span style="color: #6c71c4;">)</span> <span style="color: #2aa198;">"master"</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">5</span> '<span style="color: #6c71c4;">(</span><span style="color: #a0d6e0;">4</span><span style="color: #6c71c4;">)</span> <span style="color: #2aa198;">"master"</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">6</span> '<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">2</span><span style="color: #6c71c4;">)</span> <span style="color: #2aa198;">"branch"</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #e0a0bc;">7</span> '<span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">6</span><span style="color: #6c71c4;">)</span> <span style="color: #2aa198;">"branch"</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
Which generates the following graphviz source:
</p>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">example</span> {
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
node[<span style="color: #268bd2;">width=</span>0.15,<span style="color: #268bd2;">height=</span>0.15,<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>,<span style="color: #268bd2;">fontsize=</span>8.0];
edge[<span style="color: #268bd2;">weight=</span>2,<span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
<span style="color: #2aa198;">"1"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"2"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"3"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"4"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"5"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"6"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"branch"</span>];
<span style="color: #2aa198;">"7"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"branch"</span>];
<span style="color: #2aa198;">"1"</span> -&gt; <span style="color: #2aa198;">"2"</span>;
<span style="color: #2aa198;">"2"</span> -&gt; <span style="color: #2aa198;">"3"</span>;
<span style="color: #2aa198;">"3"</span> -&gt; <span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"7"</span> -&gt; <span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"4"</span> -&gt; <span style="color: #2aa198;">"5"</span>;
<span style="color: #2aa198;">"2"</span> -&gt; <span style="color: #2aa198;">"6"</span>;
<span style="color: #2aa198;">"6"</span> -&gt; <span style="color: #2aa198;">"7"</span>;
}
</pre>
</div>
<p>
The generated image matches the example exactly:
</p>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: example Pages: 1 -->
<svg width="253pt" height="52pt"
viewBox="0.00 0.00 252.80 51.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 47.8)">
<title>example</title>
<!-- 1 -->
<g id="node1" class="node"><title>1</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2 -->
<g id="node2" class="node"><title>2</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge1" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M10.8594,-38.4C19.4466,-38.4 38.1856,-38.4 46.7587,-38.4"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge2" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M57.6181,-38.4C73.0565,-38.4 124.509,-38.4 140.21,-38.4"/>
</g>
<!-- 6 -->
<g id="node6" class="node"><title>6</title>
<ellipse fill="black" stroke="black" cx="99" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge6" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M57.0196,-35.5864C65.4836,-29.3518 85.7351,-14.4344 94.19,-8.20644"/>
</g>
<!-- 4 -->
<g id="node4" class="node"><title>4</title>
<ellipse fill="black" stroke="black" cx="192.6" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge3" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M151.259,-38.4C159.847,-38.4 178.586,-38.4 187.159,-38.4"/>
</g>
<!-- 5 -->
<g id="node5" class="node"><title>5</title>
<ellipse fill="black" stroke="black" cx="239.4" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge5" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M198.059,-38.4C206.647,-38.4 225.386,-38.4 233.959,-38.4"/>
</g>
<!-- 7 -->
<g id="node7" class="node"><title>7</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 6&#45;&gt;7 -->
<g id="edge7" class="edge"><title>6&#45;&gt;7</title>
<path fill="none" stroke="black" d="M104.459,-5.4C113.047,-5.4 131.786,-5.4 140.359,-5.4"/>
</g>
<!-- 7&#45;&gt;4 -->
<g id="edge4" class="edge"><title>7&#45;&gt;4</title>
<path fill="none" stroke="black" d="M150.62,-8.21356C159.084,-14.4482 179.335,-29.3656 187.79,-35.5936"/>
</g>
</g>
</svg>
</div>
</div>
</div>
<div id="outline-container-sec-2" class="outline-2">
<h2 id="sec-2">Adding Labels</h2>
<div class="outline-text-2" id="text-2">
<p>
The next thing my graph needed was a way of labeling nodes. Rather
than trying to figure out some way of attaching a separate label to a
node, I decided to simply draw a labeled node as a box with text.
</p>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">G</span> {
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
node[<span style="color: #268bd2;">width=</span>0.15, <span style="color: #268bd2;">height=</span>0.15, <span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>,<span style="color: #268bd2;">fontsize=</span>8.0];
edge[<span style="color: #268bd2;">weight=</span>2, <span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
node[<span style="color: #268bd2;">group=</span>main];
1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5;
5[<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">box</span>,<span style="color: #268bd2;">label=</span>master];
node[<span style="color: #268bd2;">group=</span>branch1];
2 -&gt; 6 -&gt; 7 -&gt; 4;
7[<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">box</span>,<span style="color: #268bd2;">label=</span>branch];
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: G Pages: 1 -->
<svg width="307pt" height="58pt"
viewBox="0.00 0.00 307.20 58.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 54)">
<title>G</title>
<!-- 1 -->
<g id="node1" class="node"><title>1</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 2 -->
<g id="node2" class="node"><title>2</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge1" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M10.8594,-41.5C19.4466,-41.5 38.1856,-41.5 46.7587,-41.5"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="black" stroke="black" cx="159.4" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge2" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M57.7203,-41.5C74.8673,-41.5 135.82,-41.5 153.537,-41.5"/>
</g>
<!-- 6 -->
<g id="node6" class="node"><title>6</title>
<ellipse fill="black" stroke="black" cx="99" cy="-8.5" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge5" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M57.0196,-38.6864C65.4836,-32.4518 85.7351,-17.5344 94.19,-11.3064"/>
</g>
<!-- 4 -->
<g id="node4" class="node"><title>4</title>
<ellipse fill="black" stroke="black" cx="219.8" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge3" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M164.983,-41.5C175.953,-41.5 203.614,-41.5 214.399,-41.5"/>
</g>
<!-- 5 -->
<g id="node5" class="node"><title>5</title>
<polygon fill="none" stroke="black" points="299.2,-50 261.2,-50 261.2,-33 299.2,-33 299.2,-50"/>
<text text-anchor="middle" x="280.2" y="-39.6" font-family="Times,serif" font-size="8.00">master</text>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge4" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M225.383,-41.5C232.965,-41.5 248.521,-41.5 260.967,-41.5"/>
</g>
<!-- 7 -->
<g id="node7" class="node"><title>7</title>
<polygon fill="none" stroke="black" points="178.4,-17 140.4,-17 140.4,-0 178.4,-0 178.4,-17"/>
<text text-anchor="middle" x="159.4" y="-6.6" font-family="Times,serif" font-size="8.00">branch</text>
</g>
<!-- 6&#45;&gt;7 -->
<g id="edge6" class="edge"><title>6&#45;&gt;7</title>
<path fill="none" stroke="black" d="M104.583,-8.5C112.165,-8.5 127.721,-8.5 140.167,-8.5"/>
</g>
<!-- 7&#45;&gt;4 -->
<g id="edge7" class="edge"><title>7&#45;&gt;4</title>
<path fill="none" stroke="black" d="M175.744,-17.1704C188.721,-24.5034 206.452,-34.5223 214.506,-39.0734"/>
</g>
</g>
</svg>
</div>
<div id="outline-container-sec-2-1" class="outline-3">
<h3 id="sec-2-1">Updating the Data Structure</h3>
<div class="outline-text-3" id="text-2-1">
<p>
I updated my data structure to support an optional label applied to a
node. I opted to store it in an associative list alongside the group.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/structure"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/make-node</span> <span style="color: #b58900;">(</span><span style="color: #b6a0e0;">id</span> <span style="color: #b58900;">&amp;optional</span> <span style="color: #a6bb99;">parents</span> <span style="color: #e0d0a0;">options</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #b6a0e0;">id</span> <span style="color: #a6bb99;">parents</span> <span style="color: #e0d0a0;">options</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-id</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #a7aac0;">0</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-parents</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #9999bb;">1</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-group</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #268bd2;">(</span><span style="color: #bb99b4;">assoc</span> '<span style="color: #a7aac0;">group</span> <span style="color: #6c71c4;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #a6bb99;">2</span> <span style="color: #99bbb4;">node</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-label</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #268bd2;">(</span><span style="color: #bb99b4;">assoc</span> '<span style="color: #a7aac0;">label</span> <span style="color: #6c71c4;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #a6bb99;">2</span> <span style="color: #99bbb4;">node</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
</div>
</div>
<div id="outline-container-sec-2-2" class="outline-3">
<h3 id="sec-2-2">Updating the Graphviz node generation</h3>
<div class="outline-text-3" id="text-2-2">
<p>
The next step was updating the Graphviz generation functions to handle
the new data structure, and set the shape and label attributes of
labeled nodes.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/to-graphviz-nodes"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #c0afa7;">node-id</span> <span style="color: #859900;">(</span><span style="color: #c0afa7;">git-graph/to-graphviz-node-id</span> <span style="color: #b58900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #c0a7bd;">concat</span> <span style="color: #c0afa7;">node-id</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">git-graph/to-graphviz-node--attributes</span> <span style="color: #99bbb4;">node</span><span style="color: #6c71c4;">)</span>
<span style="color: #2aa198;">";"</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node--attributes</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">attributes</span> <span style="color: #859900;">(</span><span style="color: #99bbb4;">git-graph/to-graphviz-node--compute-attributes</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #b3c0a7;">and</span> <span style="color: #a3e0a0;">attributes</span>
<span style="color: #6c71c4;">(</span><span style="color: #c0a7bd;">concat</span> <span style="color: #2aa198;">"["</span>
<span style="color: #859900;">(</span><span style="color: #b6a0e0;">mapconcat</span> <span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #268bd2;">(</span><span style="color: #a7aac0;">pair</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #a0d6e0;">format</span> <span style="color: #2aa198;">"%s=\"%s\""</span>
<span style="color: #6c71c4;">(</span><span style="color: #99bbb4;">car</span> <span style="color: #a7aac0;">pair</span><span style="color: #6c71c4;">)</span> <span style="color: #6c71c4;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #a7aac0;">pair</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span>
<span style="color: #a3e0a0;">attributes</span>
<span style="color: #2aa198;">", "</span><span style="color: #859900;">)</span>
<span style="color: #2aa198;">"]"</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node--compute-attributes</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">-filter</span> #'<span style="color: #a3e0a0;">identity</span>
<span style="color: #268bd2;">(</span><span style="color: #a7aac0;">append</span> <span style="color: #6c71c4;">(</span><span style="color: #b3c0a7;">and</span> <span style="color: #859900;">(</span><span style="color: #b6a0e0;">git-graph/node-group</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #b58900;">(</span><span style="color: #a0d6e0;">cons</span> '<span style="color: #a7aac0;">group</span> <span style="color: #268bd2;">(</span><span style="color: #b6a0e0;">git-graph/node-group</span> <span style="color: #99bbb4;">node</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #b3c0a7;">and</span> <span style="color: #859900;">(</span><span style="color: #e0a0bc;">git-graph/node-label</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #b58900;">(</span><span style="color: #a0d6e0;">cons</span> '<span style="color: #a6bb99;">shape</span> '<span style="color: #bba699;">box</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a0d6e0;">cons</span> '<span style="color: #a7aac0;">label</span> <span style="color: #268bd2;">(</span><span style="color: #e0a0bc;">git-graph/node-label</span> <span style="color: #99bbb4;">node</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
I could then label the tips of each branch:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="graph-example-labels"><span style="color: #2aa198;">(</span><span style="color: #b6a0e0;">git-graph/to-graphviz-pretty</span>
<span style="color: #2aa198;">"labeled"</span>
<span style="color: #b58900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #9999bb;">1</span> <span style="color: #bb99b4;">nil</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"master"</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a6bb99;">2</span> '<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">1</span><span style="color: #6c71c4;">)</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"master"</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #e0a0bc;">3</span> '<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">2</span><span style="color: #6c71c4;">)</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"master"</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a0d6e0;">4</span> '<span style="color: #6c71c4;">(</span><span style="color: #e0a0bc;">3</span> <span style="color: #e0a0bc;">7</span><span style="color: #6c71c4;">)</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"master"</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">5</span> '<span style="color: #6c71c4;">(</span><span style="color: #a0d6e0;">4</span><span style="color: #6c71c4;">)</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"master"</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"master"</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">6</span> '<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">2</span><span style="color: #6c71c4;">)</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"branch"</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #e0a0bc;">7</span> '<span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">6</span><span style="color: #6c71c4;">)</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"branch"</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> <span style="color: #2aa198;">"branch"</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">labeled</span> {
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
node[<span style="color: #268bd2;">width=</span>0.15,<span style="color: #268bd2;">height=</span>0.15,<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>,<span style="color: #268bd2;">fontsize=</span>8.0];
edge[<span style="color: #268bd2;">weight=</span>2,<span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
<span style="color: #2aa198;">"1"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"2"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"3"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"4"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"5"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"master"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"6"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"branch"</span>];
<span style="color: #2aa198;">"7"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"branch"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"branch"</span>];
<span style="color: #2aa198;">"1"</span> -&gt; <span style="color: #2aa198;">"2"</span>;
<span style="color: #2aa198;">"2"</span> -&gt; <span style="color: #2aa198;">"3"</span>;
<span style="color: #2aa198;">"3"</span> -&gt; <span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"7"</span> -&gt; <span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"4"</span> -&gt; <span style="color: #2aa198;">"5"</span>;
<span style="color: #2aa198;">"2"</span> -&gt; <span style="color: #2aa198;">"6"</span>;
<span style="color: #2aa198;">"6"</span> -&gt; <span style="color: #2aa198;">"7"</span>;
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: labeled Pages: 1 -->
<svg width="307pt" height="58pt"
viewBox="0.00 0.00 307.20 58.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 54)">
<title>labeled</title>
<!-- 1 -->
<g id="node1" class="node"><title>1</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 2 -->
<g id="node2" class="node"><title>2</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge1" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M10.8594,-41.5C19.4466,-41.5 38.1856,-41.5 46.7587,-41.5"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="black" stroke="black" cx="159.4" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge2" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M57.7203,-41.5C74.8673,-41.5 135.82,-41.5 153.537,-41.5"/>
</g>
<!-- 6 -->
<g id="node6" class="node"><title>6</title>
<ellipse fill="black" stroke="black" cx="99" cy="-8.5" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge6" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M57.0196,-38.6864C65.4836,-32.4518 85.7351,-17.5344 94.19,-11.3064"/>
</g>
<!-- 4 -->
<g id="node4" class="node"><title>4</title>
<ellipse fill="black" stroke="black" cx="219.8" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge3" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M164.983,-41.5C175.953,-41.5 203.614,-41.5 214.399,-41.5"/>
</g>
<!-- 5 -->
<g id="node5" class="node"><title>5</title>
<polygon fill="none" stroke="black" points="299.2,-50 261.2,-50 261.2,-33 299.2,-33 299.2,-50"/>
<text text-anchor="middle" x="280.2" y="-39.6" font-family="Times,serif" font-size="8.00">master</text>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge5" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M225.383,-41.5C232.965,-41.5 248.521,-41.5 260.967,-41.5"/>
</g>
<!-- 7 -->
<g id="node7" class="node"><title>7</title>
<polygon fill="none" stroke="black" points="178.4,-17 140.4,-17 140.4,-0 178.4,-0 178.4,-17"/>
<text text-anchor="middle" x="159.4" y="-6.6" font-family="Times,serif" font-size="8.00">branch</text>
</g>
<!-- 6&#45;&gt;7 -->
<g id="edge7" class="edge"><title>6&#45;&gt;7</title>
<path fill="none" stroke="black" d="M104.583,-8.5C112.165,-8.5 127.721,-8.5 140.167,-8.5"/>
</g>
<!-- 7&#45;&gt;4 -->
<g id="edge4" class="edge"><title>7&#45;&gt;4</title>
<path fill="none" stroke="black" d="M175.744,-17.1704C188.721,-24.5034 206.452,-34.5223 214.506,-39.0734"/>
</g>
</g>
</svg>
</div>
</div>
</div>
<div id="outline-container-sec-3" class="outline-2">
<h2 id="sec-3">Automatic Grouping Using Leaf Nodes</h2>
<div class="outline-text-2" id="text-3">
<p>
Manually assigning groups to each node is tedious, and easy to
accidentally get wrong. Also, with the goal to graph git repositories,
I was going to have to figure out groupings automatically anyway.
</p>
<p>
To do this, it made sense to traverse the nodes in <a href="https://en.wikipedia.org/wiki/Topological_sorting">topological order</a>.
</p>
<p>
Repeating the example above,
</p>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">G</span> {
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
node[<span style="color: #268bd2;">width=</span>0.15, <span style="color: #268bd2;">height=</span>0.15, <span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">circle</span>];
edge[<span style="color: #268bd2;">weight=</span>2, <span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
node[<span style="color: #268bd2;">group=</span>main];
1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5;
node[<span style="color: #268bd2;">group=</span>branch1];
2 -&gt; 6 -&gt; 7 -&gt; 4;
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: G Pages: 1 -->
<svg width="383pt" height="92pt"
viewBox="0.00 0.00 383.16 91.53" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 87.5269)">
<title>G</title>
<!-- 1 -->
<g id="node1" class="node"><title>1</title>
<ellipse fill="none" stroke="black" cx="16.2635" cy="-67.2635" rx="16.0303" ry="16.0303"/>
<text text-anchor="middle" x="16.2635" y="-63.5635" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- 2 -->
<g id="node2" class="node"><title>2</title>
<ellipse fill="none" stroke="black" cx="84.7904" cy="-67.2635" rx="16.0303" ry="16.0303"/>
<text text-anchor="middle" x="84.7904" y="-63.5635" font-family="Times,serif" font-size="14.00">2</text>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge1" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M32.6933,-67.2635C43.4409,-67.2635 57.715,-67.2635 68.4442,-67.2635"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="none" stroke="black" cx="221.844" cy="-67.2635" rx="16.0303" ry="16.0303"/>
<text text-anchor="middle" x="221.844" y="-63.5635" font-family="Times,serif" font-size="14.00">3</text>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge2" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M101.283,-67.2635C127.334,-67.2635 179.603,-67.2635 205.532,-67.2635"/>
</g>
<!-- 6 -->
<g id="node6" class="node"><title>6</title>
<ellipse fill="none" stroke="black" cx="153.317" cy="-16.2635" rx="16.0303" ry="16.0303"/>
<text text-anchor="middle" x="153.317" y="-12.5635" font-family="Times,serif" font-size="14.00">6</text>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge5" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M98.3036,-57.6707C110.198,-48.5528 127.985,-34.9169 139.86,-25.8132"/>
</g>
<!-- 4 -->
<g id="node4" class="node"><title>4</title>
<ellipse fill="none" stroke="black" cx="290.371" cy="-67.2635" rx="16.0303" ry="16.0303"/>
<text text-anchor="middle" x="290.371" y="-63.5635" font-family="Times,serif" font-size="14.00">4</text>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge3" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M238.274,-67.2635C249.022,-67.2635 263.296,-67.2635 274.025,-67.2635"/>
</g>
<!-- 5 -->
<g id="node5" class="node"><title>5</title>
<ellipse fill="none" stroke="black" cx="358.898" cy="-67.2635" rx="16.0303" ry="16.0303"/>
<text text-anchor="middle" x="358.898" y="-63.5635" font-family="Times,serif" font-size="14.00">5</text>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge4" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M306.801,-67.2635C317.549,-67.2635 331.823,-67.2635 342.552,-67.2635"/>
</g>
<!-- 7 -->
<g id="node7" class="node"><title>7</title>
<ellipse fill="none" stroke="black" cx="221.844" cy="-16.2635" rx="16.0303" ry="16.0303"/>
<text text-anchor="middle" x="221.844" y="-12.5635" font-family="Times,serif" font-size="14.00">7</text>
</g>
<!-- 6&#45;&gt;7 -->
<g id="edge6" class="edge"><title>6&#45;&gt;7</title>
<path fill="none" stroke="black" d="M169.747,-16.2635C180.495,-16.2635 194.769,-16.2635 205.498,-16.2635"/>
</g>
<!-- 7&#45;&gt;4 -->
<g id="edge7" class="edge"><title>7&#45;&gt;4</title>
<path fill="none" stroke="black" d="M235.357,-25.8562C247.251,-34.9742 265.039,-48.61 276.914,-57.7138"/>
</g>
</g>
</svg>
<p>
These nodes can be represented (right to left) in topological order as
either <code>5, 4, 3, 7, 6, 2, 1</code> or <code>5, 4, 7, 6, 3, 2, 1</code>.
</p>
<p>
Having no further children, <code>5</code> is a leaf node, and can be used as a
group. All first parents of <code>5</code> can therefore be considered to be in
group <code>5</code>.
</p>
<p>
<code>7</code> is a second parent to <code>4</code>, and so should be used as the group for
all of its parents not present in group <code>5</code>.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/group-topo"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/group-topo</span> <span style="color: #b58900;">(</span><span style="color: #a7aac0;">nodelist</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #c0afa7;">reverse</span>
<span style="color: #268bd2;">(</span><span style="color: #99bbb4;">car</span>
<span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">-reduce-from</span>
<span style="color: #859900;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #b58900;">(</span><span style="color: #268bd2;">acc</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let*</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">grouped-nodes</span> <span style="color: #859900;">(</span><span style="color: #99bbb4;">car</span> <span style="color: #268bd2;">acc</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">group-stack</span> <span style="color: #859900;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #268bd2;">acc</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #c0afa7;">node-id</span> <span style="color: #859900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a7c0b9;">group-from-stack</span> <span style="color: #859900;">(</span><span style="color: #859900; font-weight: bold;">--if-let</span> <span style="color: #2aa198;">(</span><span style="color: #bb99b4;">assoc</span> <span style="color: #c0afa7;">node-id</span> <span style="color: #a6bb99;">group-stack</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #268bd2;">it</span><span style="color: #2aa198;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #859900;">(</span><span style="color: #a7aac0;">or</span> <span style="color: #a7c0b9;">group-from-stack</span> <span style="color: #c0afa7;">node-id</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">parents</span> <span style="color: #859900;">(</span><span style="color: #a7c0b9;">git-graph/node-parents</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #b6a0e0;">first-parent</span> <span style="color: #859900;">(</span><span style="color: #a0d6e0;">first</span> <span style="color: #a6bb99;">parents</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">if</span> <span style="color: #a7c0b9;">group-from-stack</span>
<span style="color: #6c71c4;">(</span><span style="color: #99bbb4;">pop</span> <span style="color: #a6bb99;">group-stack</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">if</span> <span style="color: #6c71c4;">(</span><span style="color: #b3c0a7;">and</span> <span style="color: #b6a0e0;">first-parent</span> <span style="color: #859900;">(</span><span style="color: #9999bb;">not</span> <span style="color: #2aa198;">(</span><span style="color: #bb99b4;">assoc</span> <span style="color: #b6a0e0;">first-parent</span> <span style="color: #a6bb99;">group-stack</span><span style="color: #2aa198;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">push</span> <span style="color: #859900;">(</span><span style="color: #a0d6e0;">cons</span> <span style="color: #b6a0e0;">first-parent</span> <span style="color: #a7aac0;">group</span><span style="color: #859900;">)</span> <span style="color: #a6bb99;">group-stack</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #a0d6e0;">cons</span> <span style="color: #6c71c4;">(</span><span style="color: #a0d6e0;">cons</span> <span style="color: #859900;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #c0afa7;">node-id</span>
<span style="color: #a6bb99;">parents</span>
`<span style="color: #2aa198;">(</span><span style="color: #b58900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> ,<span style="color: #a7aac0;">group</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> ,<span style="color: #268bd2;">(</span><span style="color: #e0a0bc;">git-graph/node-label</span> <span style="color: #99bbb4;">node</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span><span style="color: #859900;">)</span>
<span style="color: #a3e0a0;">grouped-nodes</span><span style="color: #6c71c4;">)</span>
<span style="color: #a6bb99;">group-stack</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span>
<span style="color: #bb99b4;">nil</span>
<span style="color: #a7aac0;">nodelist</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
While iterating through the node list, I maintained a stack of pairs
built from the first parent of the current node, and the current
group. To determine the group, the head of the stack is checked to see
if it contains a group for the current node id. If it does, that group
is used and it is popped off the stack, otherwise the current node id
is used.
</p>
<p>
The following table illustrates how the stack is used to store and
assign group relationships as the process iterates through the node
list:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<caption class="t-above"><span class="table-number">Table 1:</span> Progressing through the nodes</caption>
<colgroup>
<col class="right" />
<col class="left" />
<col class="left" />
<col class="right" />
</colgroup>
<thead>
<tr>
<th scope="col" class="right">Node</th>
<th scope="col" class="left">Parents</th>
<th scope="col" class="left">Group Stack</th>
<th scope="col" class="right">Group</th>
</tr>
</thead>
<tbody>
<tr>
<td class="right">5</td>
<td class="left">(4)</td>
<td class="left">(4 . 5)</td>
<td class="right">5</td>
</tr>
<tr>
<td class="right">4</td>
<td class="left">(3 7)</td>
<td class="left">(3 . 5)</td>
<td class="right">5</td>
</tr>
<tr>
<td class="right">3</td>
<td class="left">(2)</td>
<td class="left">(2 . 5)</td>
<td class="right">5</td>
</tr>
<tr>
<td class="right">7</td>
<td class="left">(6)</td>
<td class="left">(6 . 7) (2 . 5)</td>
<td class="right">7</td>
</tr>
<tr>
<td class="right">6</td>
<td class="left">(2)</td>
<td class="left">(2 . 5)</td>
<td class="right">7</td>
</tr>
<tr>
<td class="right">2</td>
<td class="left">(1)</td>
<td class="left">(1 . 5)</td>
<td class="right">5</td>
</tr>
<tr>
<td class="right">1</td>
<td class="left">&#xa0;</td>
<td class="left">&#xa0;</td>
<td class="right">5</td>
</tr>
</tbody>
</table>
</div>
<div id="outline-container-sec-3-1" class="outline-3">
<h3 id="sec-3-1">Graph without automatic grouping</h3>
<div class="outline-text-3" id="text-3-1">
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="graph-no-auto-grouping"><span style="color: #2aa198;">(</span><span style="color: #b6a0e0;">git-graph/to-graphviz-pretty</span>
<span style="color: #2aa198;">"nogroups"</span>
<span style="color: #b58900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">5</span> '<span style="color: #6c71c4;">(</span><span style="color: #a0d6e0;">4</span><span style="color: #6c71c4;">)</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> <span style="color: #c0a7bd;">master</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a0d6e0;">4</span> '<span style="color: #6c71c4;">(</span><span style="color: #e0a0bc;">3</span> <span style="color: #e0a0bc;">7</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #e0a0bc;">3</span> '<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">2</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #e0a0bc;">7</span> '<span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">6</span><span style="color: #6c71c4;">)</span> '<span style="color: #6c71c4;">(</span><span style="color: #859900;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> <span style="color: #c0a7bd;">develop</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">6</span> '<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">2</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a6bb99;">2</span> '<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">1</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #9999bb;">1</span> <span style="color: #bb99b4;">nil</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">nogroups</span> {
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
node[<span style="color: #268bd2;">width=</span>0.15,<span style="color: #268bd2;">height=</span>0.15,<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>,<span style="color: #268bd2;">fontsize=</span>8.0];
edge[<span style="color: #268bd2;">weight=</span>2,<span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
<span style="color: #2aa198;">"5"</span>[<span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"3"</span>;
<span style="color: #2aa198;">"7"</span>[<span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"develop"</span>];
<span style="color: #2aa198;">"6"</span>;
<span style="color: #2aa198;">"2"</span>;
<span style="color: #2aa198;">"1"</span>;
<span style="color: #2aa198;">"4"</span> -&gt; <span style="color: #2aa198;">"5"</span>;
<span style="color: #2aa198;">"3"</span> -&gt; <span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"7"</span> -&gt; <span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"2"</span> -&gt; <span style="color: #2aa198;">"3"</span>;
<span style="color: #2aa198;">"6"</span> -&gt; <span style="color: #2aa198;">"7"</span>;
<span style="color: #2aa198;">"2"</span> -&gt; <span style="color: #2aa198;">"6"</span>;
<span style="color: #2aa198;">"1"</span> -&gt; <span style="color: #2aa198;">"2"</span>;
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: nogroups Pages: 1 -->
<svg width="310pt" height="54pt"
viewBox="0.00 0.00 310.20 53.90" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 49.9)">
<title>nogroups</title>
<!-- 5 -->
<g id="node1" class="node"><title>5</title>
<polygon fill="none" stroke="black" points="302.2,-33 264.2,-33 264.2,-16 302.2,-16 302.2,-33"/>
<text text-anchor="middle" x="283.2" y="-22.6" font-family="Times,serif" font-size="8.00">master</text>
</g>
<!-- 4 -->
<g id="node2" class="node"><title>4</title>
<ellipse fill="black" stroke="black" cx="222.8" cy="-24.5" rx="5.4" ry="5.4"/>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge1" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M228.383,-24.5C235.965,-24.5 251.521,-24.5 263.967,-24.5"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="black" stroke="black" cx="160.9" cy="-40.5" rx="5.4" ry="5.4"/>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge2" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M166.208,-39.3493C177.153,-36.4259 205.956,-28.7322 217.205,-25.7273"/>
</g>
<!-- 7 -->
<g id="node4" class="node"><title>7</title>
<polygon fill="none" stroke="black" points="181.4,-17 140.4,-17 140.4,-0 181.4,-0 181.4,-17"/>
<text text-anchor="middle" x="160.9" y="-6.6" font-family="Times,serif" font-size="8.00">develop</text>
</g>
<!-- 7&#45;&gt;4 -->
<g id="edge3" class="edge"><title>7&#45;&gt;4</title>
<path fill="none" stroke="black" d="M181.514,-13.739C194.343,-17.1658 210.056,-21.363 217.498,-23.3509"/>
</g>
<!-- 6 -->
<g id="node5" class="node"><title>6</title>
<ellipse fill="black" stroke="black" cx="99" cy="-8.5" rx="5.4" ry="5.4"/>
</g>
<!-- 6&#45;&gt;7 -->
<g id="edge5" class="edge"><title>6&#45;&gt;7</title>
<path fill="none" stroke="black" d="M104.7,-8.5C112.312,-8.5 127.758,-8.5 140.38,-8.5"/>
</g>
<!-- 2 -->
<g id="node6" class="node"><title>2</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-24.5" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge4" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M57.7848,-25.1875C75.3358,-27.8193 138.136,-37.2364 155.451,-39.8329"/>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge6" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M57.6594,-22.9074C66.2466,-19.8405 84.9856,-13.148 93.5587,-10.0862"/>
</g>
<!-- 1 -->
<g id="node7" class="node"><title>1</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-24.5" rx="5.4" ry="5.4"/>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge7" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M10.8594,-24.5C19.4466,-24.5 38.1856,-24.5 46.7587,-24.5"/>
</g>
</g>
</svg>
</div>
</div>
<div id="outline-container-sec-3-2" class="outline-3">
<h3 id="sec-3-2">Graph with automatic grouping</h3>
<div class="outline-text-3" id="text-3-2">
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="graph-with-auto-grouping"><span style="color: #2aa198;">(</span><span style="color: #b6a0e0;">git-graph/to-graphviz-pretty</span>
<span style="color: #2aa198;">"autogroups"</span>
<span style="color: #b58900;">(</span><span style="color: #b3c0a7;">git-graph/group-topo</span>
<span style="color: #268bd2;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #6c71c4;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">5</span> '<span style="color: #859900;">(</span><span style="color: #a0d6e0;">4</span><span style="color: #859900;">)</span> '<span style="color: #859900;">(</span><span style="color: #b58900;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> <span style="color: #c0a7bd;">master</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a0d6e0;">4</span> '<span style="color: #859900;">(</span><span style="color: #e0a0bc;">3</span> <span style="color: #e0a0bc;">7</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #e0a0bc;">3</span> '<span style="color: #859900;">(</span><span style="color: #a6bb99;">2</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #e0a0bc;">7</span> '<span style="color: #859900;">(</span><span style="color: #a3e0a0;">6</span><span style="color: #859900;">)</span> '<span style="color: #859900;">(</span><span style="color: #b58900;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> <span style="color: #c0a7bd;">develop</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">6</span> '<span style="color: #859900;">(</span><span style="color: #a6bb99;">2</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a6bb99;">2</span> '<span style="color: #859900;">(</span><span style="color: #9999bb;">1</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #9999bb;">1</span> <span style="color: #bb99b4;">nil</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">autogroups</span> {
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
node[<span style="color: #268bd2;">width=</span>0.15,<span style="color: #268bd2;">height=</span>0.15,<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>,<span style="color: #268bd2;">fontsize=</span>8.0];
edge[<span style="color: #268bd2;">weight=</span>2,<span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
<span style="color: #2aa198;">"5"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"5"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"4"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"5"</span>];
<span style="color: #2aa198;">"3"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"5"</span>];
<span style="color: #2aa198;">"7"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"7"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"develop"</span>];
<span style="color: #2aa198;">"6"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"7"</span>];
<span style="color: #2aa198;">"2"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"5"</span>];
<span style="color: #2aa198;">"1"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"5"</span>];
<span style="color: #2aa198;">"4"</span> -&gt; <span style="color: #2aa198;">"5"</span>;
<span style="color: #2aa198;">"3"</span> -&gt; <span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"7"</span> -&gt; <span style="color: #2aa198;">"4"</span>;
<span style="color: #2aa198;">"2"</span> -&gt; <span style="color: #2aa198;">"3"</span>;
<span style="color: #2aa198;">"6"</span> -&gt; <span style="color: #2aa198;">"7"</span>;
<span style="color: #2aa198;">"2"</span> -&gt; <span style="color: #2aa198;">"6"</span>;
<span style="color: #2aa198;">"1"</span> -&gt; <span style="color: #2aa198;">"2"</span>;
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: autogroups Pages: 1 -->
<svg width="310pt" height="58pt"
viewBox="0.00 0.00 310.20 58.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 54)">
<title>autogroups</title>
<!-- 5 -->
<g id="node1" class="node"><title>5</title>
<polygon fill="none" stroke="black" points="302.2,-50 264.2,-50 264.2,-33 302.2,-33 302.2,-50"/>
<text text-anchor="middle" x="283.2" y="-39.6" font-family="Times,serif" font-size="8.00">master</text>
</g>
<!-- 4 -->
<g id="node2" class="node"><title>4</title>
<ellipse fill="black" stroke="black" cx="222.8" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge1" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M228.383,-41.5C235.965,-41.5 251.521,-41.5 263.967,-41.5"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="black" stroke="black" cx="160.9" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge2" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M166.6,-41.5C177.853,-41.5 206.224,-41.5 217.285,-41.5"/>
</g>
<!-- 7 -->
<g id="node4" class="node"><title>7</title>
<polygon fill="none" stroke="black" points="181.4,-17 140.4,-17 140.4,-0 181.4,-0 181.4,-17"/>
<text text-anchor="middle" x="160.9" y="-6.6" font-family="Times,serif" font-size="8.00">develop</text>
</g>
<!-- 7&#45;&gt;4 -->
<g id="edge3" class="edge"><title>7&#45;&gt;4</title>
<path fill="none" stroke="black" d="M177.638,-17.1704C190.949,-24.5034 209.134,-34.5223 217.395,-39.0734"/>
</g>
<!-- 6 -->
<g id="node5" class="node"><title>6</title>
<ellipse fill="black" stroke="black" cx="99" cy="-8.5" rx="5.4" ry="5.4"/>
</g>
<!-- 6&#45;&gt;7 -->
<g id="edge5" class="edge"><title>6&#45;&gt;7</title>
<path fill="none" stroke="black" d="M104.7,-8.5C112.312,-8.5 127.758,-8.5 140.38,-8.5"/>
</g>
<!-- 2 -->
<g id="node6" class="node"><title>2</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge4" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M57.7848,-41.5C75.3358,-41.5 138.136,-41.5 155.451,-41.5"/>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge6" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M57.0196,-38.6864C65.4836,-32.4518 85.7351,-17.5344 94.19,-11.3064"/>
</g>
<!-- 1 -->
<g id="node7" class="node"><title>1</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-41.5" rx="5.4" ry="5.4"/>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge7" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M10.8594,-41.5C19.4466,-41.5 38.1856,-41.5 46.7587,-41.5"/>
</g>
</g>
</svg>
</div>
</div>
</div>
<div id="outline-container-sec-4" class="outline-2">
<h2 id="sec-4">Graphing a Git Repository</h2>
<div class="outline-text-2" id="text-4">
<p>
Satisfied that I had all the necessary tools to start graphing real
git repositories, I created an example repository to test against.
</p>
</div>
<div id="outline-container-sec-4-1" class="outline-3">
<h3 id="sec-4-1">Creating a Sample Repository</h3>
<div class="outline-text-3" id="text-4-1">
<p>
Using the following script, I created a sample repository to test
against. I performed the following actions:
</p>
<ul class="org-ul">
<li>Forked a develop branch from master.
</li>
<li>Forked a feature branch from develop, with two commits.
</li>
<li>Added another commit to develop.
</li>
<li>Forked a second feature branch from develop, with two commits.
</li>
<li>Merged the second feature branch to develop.
</li>
<li>Merged develop to master and tagged it.
</li>
</ul>
<div class="org-src-container">
<pre class="src src-sh">mkdir /tmp/test.git
<span style="color: #839496; font-weight: bold;">cd</span> /tmp/test.git
git init
touch README
git add README
git commit -m <span style="color: #2aa198;">'initial'</span>
git commit --allow-empty -m <span style="color: #2aa198;">'first'</span>
git checkout -b develop
git commit --allow-empty -m <span style="color: #2aa198;">'second'</span>
git checkout -b feature-1
git commit --allow-empty -m <span style="color: #2aa198;">'feature 1'</span>
git commit --allow-empty -m <span style="color: #2aa198;">'feature 1 again'</span>
git checkout develop
git commit --allow-empty -m <span style="color: #2aa198;">'third'</span>
git checkout -b feature-2
git commit --allow-empty -m <span style="color: #2aa198;">'feature 2'</span>
git commit --allow-empty -m <span style="color: #2aa198;">'feature 2 again'</span>
git checkout develop
git merge --no-ff feature-2
git checkout master
git merge --no-ff develop
git tag -a 1.0
</pre>
</div>
</div>
</div>
<div id="outline-container-sec-4-2" class="outline-3">
<h3 id="sec-4-2">Generating a Graph From a Git Branch</h3>
<div class="outline-text-3" id="text-4-2">
<p>
The first order of business was to have a way to call out to git and
return the results:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/from-git"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-execute</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #b6a0e0;">command</span> <span style="color: #b58900;">&amp;rest</span> <span style="color: #a6bb99;">args</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">with-temp-buffer</span>
<span style="color: #268bd2;">(</span><span style="color: #bba699;">shell-command</span> <span style="color: #6c71c4;">(</span><span style="color: #a0d6e0;">format</span> <span style="color: #2aa198;">"git -C \"%s\" %s"</span>
<span style="color: #9999bb;">repo-url</span>
<span style="color: #859900;">(</span><span style="color: #a7c0b9;">string-join</span> <span style="color: #b58900;">(</span><span style="color: #a0d6e0;">cons</span> <span style="color: #b6a0e0;">command</span> <span style="color: #a6bb99;">args</span><span style="color: #b58900;">)</span>
<span style="color: #2aa198;">" "</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #a0d6e0;">t</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">buffer-string</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
Next, I needed to get the list of commits for a branch in topological
order, with a list of parent commits for each. It turns out git
provides exactly that via its <code>rev-list</code> command.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/from-git"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-rev-list</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #a6bb99;">head</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">-map</span> <span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">line</span><span style="color: #6c71c4;">)</span> <span style="color: #6c71c4;">(</span><span style="color: #9999bb;">split-string</span> <span style="color: #a3e0a0;">line</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">split-string</span> <span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">git-graph/git-execute</span>
<span style="color: #9999bb;">repo-url</span>
<span style="color: #2aa198;">"rev-list"</span> <span style="color: #2aa198;">"--topo-order"</span> <span style="color: #2aa198;">"--parents"</span> <span style="color: #a6bb99;">head</span><span style="color: #6c71c4;">)</span>
<span style="color: #2aa198;">"\n"</span> <span style="color: #a0d6e0;">t</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
I also wanted to label branch heads wherever possible. To do this, I
looked up the revision name from git, discarding it if it was relative
to some other named commit.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/from-git"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-label</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #a3e0a0;">rev</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #bba699;">name</span> <span style="color: #859900;">(</span><span style="color: #bba699;">string-trim</span>
<span style="color: #b58900;">(</span><span style="color: #a3e0a0;">git-graph/git-execute</span> <span style="color: #9999bb;">repo-url</span>
<span style="color: #2aa198;">"name-rev"</span> <span style="color: #2aa198;">"--name-only"</span> <span style="color: #a3e0a0;">rev</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">unless</span> <span style="color: #6c71c4;">(</span><span style="color: #c0a7bd;">s-contains?</span> <span style="color: #2aa198;">"~"</span> <span style="color: #bba699;">name</span><span style="color: #6c71c4;">)</span>
<span style="color: #bba699;">name</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
Generating the graph for a single branch was as simple as iterating
over each commit and creating a node for it.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-graph-head</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #a6bb99;">head</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #b3c0a7;">git-graph/group-topo</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">-map</span> <span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #859900;">(</span><span style="color: #e0d0a0;">rev-with-parents</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #859900; font-weight: bold;">let*</span> <span style="color: #b58900;">(</span><span style="color: #268bd2;">(</span><span style="color: #a3e0a0;">rev</span> <span style="color: #6c71c4;">(</span><span style="color: #99bbb4;">car</span> <span style="color: #e0d0a0;">rev-with-parents</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #a6bb99;">parents</span> <span style="color: #6c71c4;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #e0d0a0;">rev-with-parents</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #6c71c4;">(</span><span style="color: #c0afa7;">git-graph/git-label</span> <span style="color: #9999bb;">repo-url</span> <span style="color: #a3e0a0;">rev</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #a3e0a0;">rev</span> <span style="color: #a6bb99;">parents</span>
`<span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> ,<span style="color: #a7aac0;">label</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #e0a0bc;">git-graph/git-rev-list</span> <span style="color: #9999bb;">repo-url</span> <span style="color: #a6bb99;">head</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
Here's the result of graphing the <code>master</code> branch:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="graph-git-branch"><span style="color: #2aa198;">(</span><span style="color: #b6a0e0;">git-graph/to-graphviz-pretty</span>
<span style="color: #2aa198;">"git"</span>
<span style="color: #b58900;">(</span><span style="color: #a7aac0;">git-graph/git-graph-head</span>
<span style="color: #2aa198;">"/tmp/test.git"</span>
<span style="color: #2aa198;">"master"</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">git</span> {
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
node[<span style="color: #268bd2;">width=</span>0.15,<span style="color: #268bd2;">height=</span>0.15,<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>,<span style="color: #268bd2;">fontsize=</span>8.0];
edge[<span style="color: #268bd2;">weight=</span>2,<span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
<span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"develop"</span>];
<span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"feature-2"</span>];
<span style="color: #2aa198;">"ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span>];
<span style="color: #2aa198;">"3992cf3e490b423591805d4c6bc335a34753f9d7"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>];
<span style="color: #2aa198;">"43c20e67d20b154ae0fbfd54ad946dd188732e83"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>];
<span style="color: #2aa198;">"cb495d05531ffb36b47f07bfde7b29547b60d68a"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>];
<span style="color: #2aa198;">"fe2eaeeb6a0f555c12e1304fa4738d2ce465a478"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>];
<span style="color: #2aa198;">"cb495d05531ffb36b47f07bfde7b29547b60d68a"</span> -&gt; <span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>;
<span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span> -&gt; <span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>;
<span style="color: #2aa198;">"3992cf3e490b423591805d4c6bc335a34753f9d7"</span> -&gt; <span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>;
<span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span> -&gt; <span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>;
<span style="color: #2aa198;">"ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b"</span> -&gt; <span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span>;
<span style="color: #2aa198;">"3992cf3e490b423591805d4c6bc335a34753f9d7"</span> -&gt; <span style="color: #2aa198;">"ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b"</span>;
<span style="color: #2aa198;">"43c20e67d20b154ae0fbfd54ad946dd188732e83"</span> -&gt; <span style="color: #2aa198;">"3992cf3e490b423591805d4c6bc335a34753f9d7"</span>;
<span style="color: #2aa198;">"cb495d05531ffb36b47f07bfde7b29547b60d68a"</span> -&gt; <span style="color: #2aa198;">"43c20e67d20b154ae0fbfd54ad946dd188732e83"</span>;
<span style="color: #2aa198;">"fe2eaeeb6a0f555c12e1304fa4738d2ce465a478"</span> -&gt; <span style="color: #2aa198;">"cb495d05531ffb36b47f07bfde7b29547b60d68a"</span>;
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: git Pages: 1 -->
<svg width="440pt" height="100pt"
viewBox="0.00 0.00 440.00 100.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 96)">
<title>git</title>
<!-- cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4 -->
<g id="node1" class="node"><title>cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4</title>
<polygon fill="none" stroke="black" points="432,-92 394,-92 394,-75 432,-75 432,-92"/>
<text text-anchor="middle" x="413" y="-81.6" font-family="Times,serif" font-size="8.00">master</text>
</g>
<!-- 82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5 -->
<g id="node2" class="node"><title>82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5</title>
<polygon fill="none" stroke="black" points="358,-54 317,-54 317,-37 358,-37 358,-54"/>
<text text-anchor="middle" x="337.5" y="-43.6" font-family="Times,serif" font-size="8.00">develop</text>
</g>
<!-- 82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5&#45;&gt;cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4 -->
<g id="edge2" class="edge"><title>82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5&#45;&gt;cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4</title>
<path fill="none" stroke="black" d="M355.178,-54.1228C367.207,-60.3417 383.374,-68.7003 395.388,-74.9113"/>
</g>
<!-- ee5c898281c0ba1965a2623e89bdfc1c6a767d4b -->
<g id="node3" class="node"><title>ee5c898281c0ba1965a2623e89bdfc1c6a767d4b</title>
<polygon fill="none" stroke="black" points="281,-17 234,-17 234,-0 281,-0 281,-17"/>
<text text-anchor="middle" x="257.5" y="-6.6" font-family="Times,serif" font-size="8.00">feature&#45;2</text>
</g>
<!-- ee5c898281c0ba1965a2623e89bdfc1c6a767d4b&#45;&gt;82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5 -->
<g id="edge4" class="edge"><title>ee5c898281c0ba1965a2623e89bdfc1c6a767d4b&#45;&gt;82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5</title>
<path fill="none" stroke="black" d="M276.591,-17.0815C289.192,-23.059 305.928,-30.9978 318.507,-36.965"/>
</g>
<!-- ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b -->
<g id="node4" class="node"><title>ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b</title>
<ellipse fill="black" stroke="black" cx="192.6" cy="-8.5" rx="5.4" ry="5.4"/>
</g>
<!-- ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b&#45;&gt;ee5c898281c0ba1965a2623e89bdfc1c6a767d4b -->
<g id="edge5" class="edge"><title>ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b&#45;&gt;ee5c898281c0ba1965a2623e89bdfc1c6a767d4b</title>
<path fill="none" stroke="black" d="M198.124,-8.5C205.56,-8.5 220.848,-8.5 233.914,-8.5"/>
</g>
<!-- 3992cf3e490b423591805d4c6bc335a34753f9d7 -->
<g id="node5" class="node"><title>3992cf3e490b423591805d4c6bc335a34753f9d7</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-45.5" rx="5.4" ry="5.4"/>
</g>
<!-- 3992cf3e490b423591805d4c6bc335a34753f9d7&#45;&gt;82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5 -->
<g id="edge3" class="edge"><title>3992cf3e490b423591805d4c6bc335a34753f9d7&#45;&gt;82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5</title>
<path fill="none" stroke="black" d="M151.489,-45.5C174.254,-45.5 273.896,-45.5 316.769,-45.5"/>
</g>
<!-- 3992cf3e490b423591805d4c6bc335a34753f9d7&#45;&gt;ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b -->
<g id="edge6" class="edge"><title>3992cf3e490b423591805d4c6bc335a34753f9d7&#45;&gt;ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b</title>
<path fill="none" stroke="black" d="M150.62,-42.3454C159.084,-35.3551 179.335,-18.6295 187.79,-11.6466"/>
</g>
<!-- 43c20e67d20b154ae0fbfd54ad946dd188732e83 -->
<g id="node6" class="node"><title>43c20e67d20b154ae0fbfd54ad946dd188732e83</title>
<ellipse fill="black" stroke="black" cx="99" cy="-45.5" rx="5.4" ry="5.4"/>
</g>
<!-- 43c20e67d20b154ae0fbfd54ad946dd188732e83&#45;&gt;3992cf3e490b423591805d4c6bc335a34753f9d7 -->
<g id="edge7" class="edge"><title>43c20e67d20b154ae0fbfd54ad946dd188732e83&#45;&gt;3992cf3e490b423591805d4c6bc335a34753f9d7</title>
<path fill="none" stroke="black" d="M104.459,-45.5C113.047,-45.5 131.786,-45.5 140.359,-45.5"/>
</g>
<!-- cb495d05531ffb36b47f07bfde7b29547b60d68a -->
<g id="node7" class="node"><title>cb495d05531ffb36b47f07bfde7b29547b60d68a</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-83.5" rx="5.4" ry="5.4"/>
</g>
<!-- cb495d05531ffb36b47f07bfde7b29547b60d68a&#45;&gt;cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4 -->
<g id="edge1" class="edge"><title>cb495d05531ffb36b47f07bfde7b29547b60d68a&#45;&gt;cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4</title>
<path fill="none" stroke="black" d="M57.775,-83.5C71.1596,-83.5 111.404,-83.5 144.8,-83.5 144.8,-83.5 144.8,-83.5 258.5,-83.5 307.268,-83.5 364.752,-83.5 393.57,-83.5"/>
</g>
<!-- cb495d05531ffb36b47f07bfde7b29547b60d68a&#45;&gt;43c20e67d20b154ae0fbfd54ad946dd188732e83 -->
<g id="edge8" class="edge"><title>cb495d05531ffb36b47f07bfde7b29547b60d68a&#45;&gt;43c20e67d20b154ae0fbfd54ad946dd188732e83</title>
<path fill="none" stroke="black" d="M56.7154,-80.5182C65.0488,-73.4497 85.9357,-55.7331 94.3765,-48.5735"/>
</g>
<!-- fe2eaeeb6a0f555c12e1304fa4738d2ce465a478 -->
<g id="node8" class="node"><title>fe2eaeeb6a0f555c12e1304fa4738d2ce465a478</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-83.5" rx="5.4" ry="5.4"/>
</g>
<!-- fe2eaeeb6a0f555c12e1304fa4738d2ce465a478&#45;&gt;cb495d05531ffb36b47f07bfde7b29547b60d68a -->
<g id="edge9" class="edge"><title>fe2eaeeb6a0f555c12e1304fa4738d2ce465a478&#45;&gt;cb495d05531ffb36b47f07bfde7b29547b60d68a</title>
<path fill="none" stroke="black" d="M10.8594,-83.5C19.4466,-83.5 38.1856,-83.5 46.7587,-83.5"/>
</g>
</g>
</svg>
</div>
</div>
<div id="outline-container-sec-4-3" class="outline-3">
<h3 id="sec-4-3">Graphing Multiple Branches</h3>
<div class="outline-text-3" id="text-4-3">
<p>
To graph multiple branches, I needed a function for combining
histories. To do so, I simply append any nodes I don't already know
about in the first history from the second.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/adder"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/+</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">a</span> <span style="color: #9999bb;">b</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a7aac0;">append</span> <span style="color: #9999bb;">a</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">-remove</span> <span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #859900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #bb99b4;">assoc</span> <span style="color: #b58900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span> <span style="color: #9999bb;">a</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #9999bb;">b</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
From there, all that remained was to accumulate the branch histories
and output the complete graph:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="git-graph/from-git"><span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-load</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #a7c0b9;">heads</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">-reduce</span> #'<span style="color: #c0afa7;">git-graph/+</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">-map</span> <span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #859900;">(</span><span style="color: #a6bb99;">head</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #a7aac0;">git-graph/git-graph-head</span> <span style="color: #9999bb;">repo-url</span> <span style="color: #a6bb99;">head</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #a7c0b9;">heads</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
And here's the example repository, graphed in full:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="graph-git-repo"><span style="color: #2aa198;">(</span><span style="color: #b6a0e0;">git-graph/to-graphviz-pretty</span>
<span style="color: #2aa198;">"git"</span>
<span style="color: #b58900;">(</span><span style="color: #bb99b4;">git-graph/git-load</span>
<span style="color: #2aa198;">"/tmp/test.git"</span>
'<span style="color: #268bd2;">(</span><span style="color: #2aa198;">"master"</span> <span style="color: #2aa198;">"feature-1"</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">git</span> {
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
node[<span style="color: #268bd2;">width=</span>0.15,<span style="color: #268bd2;">height=</span>0.15,<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>,<span style="color: #268bd2;">fontsize=</span>8.0];
edge[<span style="color: #268bd2;">weight=</span>2,<span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
<span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"master"</span>];
<span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"develop"</span>];
<span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"feature-2"</span>];
<span style="color: #2aa198;">"ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span>];
<span style="color: #2aa198;">"3992cf3e490b423591805d4c6bc335a34753f9d7"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>];
<span style="color: #2aa198;">"43c20e67d20b154ae0fbfd54ad946dd188732e83"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>];
<span style="color: #2aa198;">"cb495d05531ffb36b47f07bfde7b29547b60d68a"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>];
<span style="color: #2aa198;">"fe2eaeeb6a0f555c12e1304fa4738d2ce465a478"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>];
<span style="color: #2aa198;">"6b3ccf19c49a57363607bc4ac9a3213f8f900f04"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"6b3ccf19c49a57363607bc4ac9a3213f8f900f04"</span>, <span style="color: #268bd2;">shape=</span><span style="color: #2aa198;">"box"</span>, <span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"feature-1"</span>];
<span style="color: #2aa198;">"5e0a1de946c0cefa35b007996d9a649e44adec5e"</span>[<span style="color: #268bd2;">group=</span><span style="color: #2aa198;">"6b3ccf19c49a57363607bc4ac9a3213f8f900f04"</span>];
<span style="color: #2aa198;">"cb495d05531ffb36b47f07bfde7b29547b60d68a"</span> -&gt; <span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>;
<span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span> -&gt; <span style="color: #2aa198;">"cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4"</span>;
<span style="color: #2aa198;">"3992cf3e490b423591805d4c6bc335a34753f9d7"</span> -&gt; <span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>;
<span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span> -&gt; <span style="color: #2aa198;">"82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5"</span>;
<span style="color: #2aa198;">"ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b"</span> -&gt; <span style="color: #2aa198;">"ee5c898281c0ba1965a2623e89bdfc1c6a767d4b"</span>;
<span style="color: #2aa198;">"3992cf3e490b423591805d4c6bc335a34753f9d7"</span> -&gt; <span style="color: #2aa198;">"ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b"</span>;
<span style="color: #2aa198;">"43c20e67d20b154ae0fbfd54ad946dd188732e83"</span> -&gt; <span style="color: #2aa198;">"3992cf3e490b423591805d4c6bc335a34753f9d7"</span>;
<span style="color: #2aa198;">"cb495d05531ffb36b47f07bfde7b29547b60d68a"</span> -&gt; <span style="color: #2aa198;">"43c20e67d20b154ae0fbfd54ad946dd188732e83"</span>;
<span style="color: #2aa198;">"fe2eaeeb6a0f555c12e1304fa4738d2ce465a478"</span> -&gt; <span style="color: #2aa198;">"cb495d05531ffb36b47f07bfde7b29547b60d68a"</span>;
<span style="color: #2aa198;">"5e0a1de946c0cefa35b007996d9a649e44adec5e"</span> -&gt; <span style="color: #2aa198;">"6b3ccf19c49a57363607bc4ac9a3213f8f900f04"</span>;
<span style="color: #2aa198;">"43c20e67d20b154ae0fbfd54ad946dd188732e83"</span> -&gt; <span style="color: #2aa198;">"5e0a1de946c0cefa35b007996d9a649e44adec5e"</span>;
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: git Pages: 1 -->
<svg width="476pt" height="132pt"
viewBox="0.00 0.00 476.20 132.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 128)">
<title>git</title>
<!-- cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4 -->
<g id="node1" class="node"><title>cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4</title>
<polygon fill="none" stroke="black" points="468.2,-124 430.2,-124 430.2,-107 468.2,-107 468.2,-124"/>
<text text-anchor="middle" x="449.2" y="-113.6" font-family="Times,serif" font-size="8.00">master</text>
</g>
<!-- 82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5 -->
<g id="node2" class="node"><title>82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5</title>
<polygon fill="none" stroke="black" points="394.2,-86 353.2,-86 353.2,-69 394.2,-69 394.2,-86"/>
<text text-anchor="middle" x="373.7" y="-75.6" font-family="Times,serif" font-size="8.00">develop</text>
</g>
<!-- 82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5&#45;&gt;cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4 -->
<g id="edge2" class="edge"><title>82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5&#45;&gt;cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4</title>
<path fill="none" stroke="black" d="M391.378,-86.1228C403.407,-92.3417 419.574,-100.7 431.588,-106.911"/>
</g>
<!-- ee5c898281c0ba1965a2623e89bdfc1c6a767d4b -->
<g id="node3" class="node"><title>ee5c898281c0ba1965a2623e89bdfc1c6a767d4b</title>
<polygon fill="none" stroke="black" points="317.2,-49 270.2,-49 270.2,-32 317.2,-32 317.2,-49"/>
<text text-anchor="middle" x="293.7" y="-38.6" font-family="Times,serif" font-size="8.00">feature&#45;2</text>
</g>
<!-- ee5c898281c0ba1965a2623e89bdfc1c6a767d4b&#45;&gt;82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5 -->
<g id="edge4" class="edge"><title>ee5c898281c0ba1965a2623e89bdfc1c6a767d4b&#45;&gt;82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5</title>
<path fill="none" stroke="black" d="M312.791,-49.0815C325.392,-55.059 342.128,-62.9978 354.707,-68.965"/>
</g>
<!-- ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b -->
<g id="node4" class="node"><title>ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b</title>
<ellipse fill="black" stroke="black" cx="210.7" cy="-40.5" rx="5.4" ry="5.4"/>
</g>
<!-- ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b&#45;&gt;ee5c898281c0ba1965a2623e89bdfc1c6a767d4b -->
<g id="edge5" class="edge"><title>ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b&#45;&gt;ee5c898281c0ba1965a2623e89bdfc1c6a767d4b</title>
<path fill="none" stroke="black" d="M216.524,-40.5C226.81,-40.5 251.464,-40.5 269.959,-40.5"/>
</g>
<!-- 3992cf3e490b423591805d4c6bc335a34753f9d7 -->
<g id="node5" class="node"><title>3992cf3e490b423591805d4c6bc335a34753f9d7</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-77.5" rx="5.4" ry="5.4"/>
</g>
<!-- 3992cf3e490b423591805d4c6bc335a34753f9d7&#45;&gt;82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5 -->
<g id="edge3" class="edge"><title>3992cf3e490b423591805d4c6bc335a34753f9d7&#45;&gt;82d0efd1a5da2da60f1d01860f0b10b7f5ffa7d5</title>
<path fill="none" stroke="black" d="M151.518,-77.5C177.496,-77.5 303.702,-77.5 352.956,-77.5"/>
</g>
<!-- 3992cf3e490b423591805d4c6bc335a34753f9d7&#45;&gt;ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b -->
<g id="edge6" class="edge"><title>3992cf3e490b423591805d4c6bc335a34753f9d7&#45;&gt;ef8dddf2ba63d45c0c1b0b8de0a2293a4a0f6a0b</title>
<path fill="none" stroke="black" d="M150.927,-75.0723C162.406,-68.3199 194.601,-49.3815 205.801,-42.7936"/>
</g>
<!-- 43c20e67d20b154ae0fbfd54ad946dd188732e83 -->
<g id="node6" class="node"><title>43c20e67d20b154ae0fbfd54ad946dd188732e83</title>
<ellipse fill="black" stroke="black" cx="99" cy="-77.5" rx="5.4" ry="5.4"/>
</g>
<!-- 43c20e67d20b154ae0fbfd54ad946dd188732e83&#45;&gt;3992cf3e490b423591805d4c6bc335a34753f9d7 -->
<g id="edge7" class="edge"><title>43c20e67d20b154ae0fbfd54ad946dd188732e83&#45;&gt;3992cf3e490b423591805d4c6bc335a34753f9d7</title>
<path fill="none" stroke="black" d="M104.459,-77.5C113.047,-77.5 131.786,-77.5 140.359,-77.5"/>
</g>
<!-- 5e0a1de946c0cefa35b007996d9a649e44adec5e -->
<g id="node10" class="node"><title>5e0a1de946c0cefa35b007996d9a649e44adec5e</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-8.5" rx="5.4" ry="5.4"/>
</g>
<!-- 43c20e67d20b154ae0fbfd54ad946dd188732e83&#45;&gt;5e0a1de946c0cefa35b007996d9a649e44adec5e -->
<g id="edge11" class="edge"><title>43c20e67d20b154ae0fbfd54ad946dd188732e83&#45;&gt;5e0a1de946c0cefa35b007996d9a649e44adec5e</title>
<path fill="none" stroke="black" d="M102.668,-73.3904C110.58,-61.2051 133.862,-25.3457 141.974,-12.8522"/>
</g>
<!-- cb495d05531ffb36b47f07bfde7b29547b60d68a -->
<g id="node7" class="node"><title>cb495d05531ffb36b47f07bfde7b29547b60d68a</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-115.5" rx="5.4" ry="5.4"/>
</g>
<!-- cb495d05531ffb36b47f07bfde7b29547b60d68a&#45;&gt;cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4 -->
<g id="edge1" class="edge"><title>cb495d05531ffb36b47f07bfde7b29547b60d68a&#45;&gt;cdcc4f7434a915ff6c2c949e74672dcdf8ca36e4</title>
<path fill="none" stroke="black" d="M57.775,-115.5C71.1596,-115.5 111.404,-115.5 144.8,-115.5 144.8,-115.5 144.8,-115.5 294.7,-115.5 343.468,-115.5 400.952,-115.5 429.77,-115.5"/>
</g>
<!-- cb495d05531ffb36b47f07bfde7b29547b60d68a&#45;&gt;43c20e67d20b154ae0fbfd54ad946dd188732e83 -->
<g id="edge8" class="edge"><title>cb495d05531ffb36b47f07bfde7b29547b60d68a&#45;&gt;43c20e67d20b154ae0fbfd54ad946dd188732e83</title>
<path fill="none" stroke="black" d="M56.7154,-112.518C65.0488,-105.45 85.9357,-87.7331 94.3765,-80.5735"/>
</g>
<!-- fe2eaeeb6a0f555c12e1304fa4738d2ce465a478 -->
<g id="node8" class="node"><title>fe2eaeeb6a0f555c12e1304fa4738d2ce465a478</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-115.5" rx="5.4" ry="5.4"/>
</g>
<!-- fe2eaeeb6a0f555c12e1304fa4738d2ce465a478&#45;&gt;cb495d05531ffb36b47f07bfde7b29547b60d68a -->
<g id="edge9" class="edge"><title>fe2eaeeb6a0f555c12e1304fa4738d2ce465a478&#45;&gt;cb495d05531ffb36b47f07bfde7b29547b60d68a</title>
<path fill="none" stroke="black" d="M10.8594,-115.5C19.4466,-115.5 38.1856,-115.5 46.7587,-115.5"/>
</g>
<!-- 6b3ccf19c49a57363607bc4ac9a3213f8f900f04 -->
<g id="node9" class="node"><title>6b3ccf19c49a57363607bc4ac9a3213f8f900f04</title>
<polygon fill="none" stroke="black" points="234.2,-17 187.2,-17 187.2,-0 234.2,-0 234.2,-17"/>
<text text-anchor="middle" x="210.7" y="-6.6" font-family="Times,serif" font-size="8.00">feature&#45;1</text>
</g>
<!-- 5e0a1de946c0cefa35b007996d9a649e44adec5e&#45;&gt;6b3ccf19c49a57363607bc4ac9a3213f8f900f04 -->
<g id="edge10" class="edge"><title>5e0a1de946c0cefa35b007996d9a649e44adec5e&#45;&gt;6b3ccf19c49a57363607bc4ac9a3213f8f900f04</title>
<path fill="none" stroke="black" d="M151.324,-8.5C158.76,-8.5 174.048,-8.5 187.114,-8.5"/>
</g>
</g>
</svg>
</div>
</div>
</div>
<div id="outline-container-sec-5" class="outline-2">
<h2 id="sec-5">Things I may add in the future</h2>
<div class="outline-text-2" id="text-5">
</div><div id="outline-container-sec-5-1" class="outline-3">
<h3 id="sec-5-1">Limiting Commits to Graph</h3>
<div class="outline-text-3" id="text-5-1">
<p>
Running this against repos with any substantial history can make the
graph unwieldy. It'd be a good idea to abstract out the commit list
fetching, and modify it to support different ways of limiting the
history to display.
</p>
<p>
Ideas would include:
</p>
<ul class="org-ul">
<li>Specifying commit ranges
</li>
<li>Stopping at a common ancestor to all graphed branches (e.g., using
<code>git-merge-base</code>).
</li>
<li>Other git commit limiting options, like searches, showing only merge
or non-merge commits, etc.
</li>
</ul>
</div>
</div>
<div id="outline-container-sec-5-2" class="outline-3">
<h3 id="sec-5-2">Collapsing History</h3>
<div class="outline-text-3" id="text-5-2">
<p>
Another means of reducing the size of the resulting graph would be to
collapse unimportant sections of it. It should be possible to collapse
a section of the graph, showing a count of skipped nodes.
</p>
<p>
The difficult part would be determining what parts aren't worth
drawing. Something like this would be handy, though, for concisely
graphing the state of multiple ongoing development branches (say, to
get a picture of what's been going on since the last release, and
what's still incomplete).
</p>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">G</span> {
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
node[<span style="color: #268bd2;">width=</span>0.15,<span style="color: #268bd2;">height=</span>0.15,<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>];
edge[<span style="color: #268bd2;">weight=</span>2,<span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
node[<span style="color: #268bd2;">group=</span>main];
1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5;
node[<span style="color: #268bd2;">group=</span>branch];
2 -&gt; 6 -&gt; 7 -&gt; 8 -&gt; 9 -&gt; 10 -&gt; 4;
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: G Pages: 1 -->
<svg width="393pt" height="52pt"
viewBox="0.00 0.00 393.20 51.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 47.8)">
<title>G</title>
<!-- 1 -->
<g id="node1" class="node"><title>1</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2 -->
<g id="node2" class="node"><title>2</title>
<ellipse fill="black" stroke="black" cx="52.2" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge1" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M10.8594,-38.4C19.4466,-38.4 38.1856,-38.4 46.7587,-38.4"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge2" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M57.6181,-38.4C73.0565,-38.4 124.509,-38.4 140.21,-38.4"/>
</g>
<!-- 6 -->
<g id="node6" class="node"><title>6</title>
<ellipse fill="black" stroke="black" cx="99" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge5" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M57.0196,-35.5864C65.4836,-29.3518 85.7351,-14.4344 94.19,-8.20644"/>
</g>
<!-- 4 -->
<g id="node4" class="node"><title>4</title>
<ellipse fill="black" stroke="black" cx="333" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge3" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M151.378,-38.4C177.001,-38.4 302.379,-38.4 327.582,-38.4"/>
</g>
<!-- 5 -->
<g id="node5" class="node"><title>5</title>
<ellipse fill="black" stroke="black" cx="379.8" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge4" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M338.459,-38.4C347.047,-38.4 365.786,-38.4 374.359,-38.4"/>
</g>
<!-- 7 -->
<g id="node7" class="node"><title>7</title>
<ellipse fill="black" stroke="black" cx="145.8" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 6&#45;&gt;7 -->
<g id="edge6" class="edge"><title>6&#45;&gt;7</title>
<path fill="none" stroke="black" d="M104.459,-5.4C113.047,-5.4 131.786,-5.4 140.359,-5.4"/>
</g>
<!-- 8 -->
<g id="node8" class="node"><title>8</title>
<ellipse fill="black" stroke="black" cx="192.6" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 7&#45;&gt;8 -->
<g id="edge7" class="edge"><title>7&#45;&gt;8</title>
<path fill="none" stroke="black" d="M151.259,-5.4C159.847,-5.4 178.586,-5.4 187.159,-5.4"/>
</g>
<!-- 9 -->
<g id="node9" class="node"><title>9</title>
<ellipse fill="black" stroke="black" cx="239.4" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 8&#45;&gt;9 -->
<g id="edge8" class="edge"><title>8&#45;&gt;9</title>
<path fill="none" stroke="black" d="M198.059,-5.4C206.647,-5.4 225.386,-5.4 233.959,-5.4"/>
</g>
<!-- 10 -->
<g id="node10" class="node"><title>10</title>
<ellipse fill="black" stroke="black" cx="286.2" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 9&#45;&gt;10 -->
<g id="edge9" class="edge"><title>9&#45;&gt;10</title>
<path fill="none" stroke="black" d="M244.859,-5.4C253.447,-5.4 272.186,-5.4 280.759,-5.4"/>
</g>
<!-- 10&#45;&gt;4 -->
<g id="edge10" class="edge"><title>10&#45;&gt;4</title>
<path fill="none" stroke="black" d="M291.02,-8.21356C299.484,-14.4482 319.735,-29.3656 328.19,-35.5936"/>
</g>
</g>
</svg>
<div class="org-src-container">
<pre class="src src-dot">digraph <span style="color: #268bd2;">G</span> {
<span style="color: #268bd2;">rankdir=</span><span style="color: #2aa198;">"LR"</span>;
<span style="color: #268bd2;">bgcolor=</span><span style="color: #2aa198;">"transparent"</span>;
node[<span style="color: #268bd2;">width=</span>0.15,<span style="color: #268bd2;">height=</span>0.15,<span style="color: #268bd2;">shape=</span><span style="color: #268bd2; font-weight: bold;">point</span>];
edge[<span style="color: #268bd2;">weight=</span>2,<span style="color: #268bd2;">arrowhead=</span><span style="color: #268bd2; font-weight: bold;">none</span>];
node[<span style="color: #268bd2;">group=</span>main];
1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5;
node[<span style="color: #268bd2;">group=</span>branch];
2 -&gt; 6;
6 -&gt; 10[<span style="color: #268bd2;">style=</span><span style="color: #268bd2; font-weight: bold;">dashed</span>,<span style="color: #268bd2;">label=</span><span style="color: #2aa198;">"+3"</span>];
10 -&gt; 4;
}
</pre>
</div>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: G Pages: 1 -->
<svg width="273pt" height="52pt"
viewBox="0.00 0.00 272.80 51.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 47.8)">
<title>G</title>
<!-- 1 -->
<g id="node1" class="node"><title>1</title>
<ellipse fill="black" stroke="black" cx="5.4" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2 -->
<g id="node2" class="node"><title>2</title>
<ellipse fill="black" stroke="black" cx="53.2" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 1&#45;&gt;2 -->
<g id="edge1" class="edge"><title>1&#45;&gt;2</title>
<path fill="none" stroke="black" d="M10.9589,-38.4C19.7379,-38.4 38.8951,-38.4 47.6595,-38.4"/>
</g>
<!-- 3 -->
<g id="node3" class="node"><title>3</title>
<ellipse fill="black" stroke="black" cx="132.4" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;3 -->
<g id="edge2" class="edge"><title>2&#45;&gt;3</title>
<path fill="none" stroke="black" d="M58.798,-38.4C72.5612,-38.4 113.319,-38.4 126.923,-38.4"/>
</g>
<!-- 6 -->
<g id="node6" class="node"><title>6</title>
<ellipse fill="black" stroke="black" cx="101" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 2&#45;&gt;6 -->
<g id="edge5" class="edge"><title>2&#45;&gt;6</title>
<path fill="none" stroke="black" d="M58.1049,-35.5864C66.7578,-29.3518 87.4613,-14.4344 96.105,-8.20644"/>
</g>
<!-- 4 -->
<g id="node4" class="node"><title>4</title>
<ellipse fill="black" stroke="black" cx="211.6" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge3" class="edge"><title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M137.998,-38.4C151.761,-38.4 192.519,-38.4 206.123,-38.4"/>
</g>
<!-- 5 -->
<g id="node5" class="node"><title>5</title>
<ellipse fill="black" stroke="black" cx="259.4" cy="-38.4" rx="5.4" ry="5.4"/>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge4" class="edge"><title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M217.159,-38.4C225.938,-38.4 245.095,-38.4 253.86,-38.4"/>
</g>
<!-- 10 -->
<g id="node7" class="node"><title>10</title>
<ellipse fill="black" stroke="black" cx="163.8" cy="-5.4" rx="5.4" ry="5.4"/>
</g>
<!-- 6&#45;&gt;10 -->
<g id="edge6" class="edge"><title>6&#45;&gt;10</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M106.771,-5.4C118.193,-5.4 146.99,-5.4 158.218,-5.4"/>
<text text-anchor="middle" x="132.4" y="-9.2" font-family="Times,serif" font-size="14.00">+3</text>
</g>
<!-- 10&#45;&gt;4 -->
<g id="edge7" class="edge"><title>10&#45;&gt;4</title>
<path fill="none" stroke="black" d="M168.705,-8.21356C177.358,-14.4482 198.061,-29.3656 206.705,-35.5936"/>
</g>
</g>
</svg>
</div>
</div>
<div id="outline-container-sec-5-3" class="outline-3">
<h3 id="sec-5-3">Clean up and optimize the code a bit</h3>
<div class="outline-text-3" id="text-5-3">
<p>
Some parts of this (particularly, the grouping) are probably pretty
inefficient. If this turns out to actually be useful, I may take
another crack at it.
</p>
</div>
</div>
</div>
<div id="outline-container-sec-6" class="outline-2">
<h2 id="sec-6">Final Code</h2>
<div class="outline-text-2" id="text-6">
<p>
In case anyone would like to use this code for anything, or maybe just
pick it apart and play around with it, all the Emacs Lisp code in this
post is collected into a single file below:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #586e75;">;;; </span><span style="color: #586e75;">git-graph.el --- Generate git-style graphs using graphviz</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">Copyright (c) 2015 Correl Roush <a href="mailto:correl%40gmail.com">&lt;correl@gmail.com&gt;</a></span>
<span style="color: #586e75;">;;; </span><span style="color: #586e75;">License:</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">This program is free software; you can redistribute it and/or modify</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">it under the terms of the GNU General Public License as published by</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">the Free Software Foundation; either version 3, or (at your option)</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">any later version.</span>
<span style="color: #586e75;">;;</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">This program is distributed in the hope that it will be useful,</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">GNU General Public License for more details.</span>
<span style="color: #586e75;">;;</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">You should have received a copy of the GNU General Public License</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">along with GNU Emacs; see the file COPYING. If not, write to the</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,</span>
<span style="color: #586e75;">;; </span><span style="color: #586e75;">Boston, MA 02110-1301, USA.</span>
<span style="color: #586e75;">;;; </span><span style="color: #586e75;">Commentary:</span>
<span style="color: #586e75;">;;; </span><span style="color: #586e75;">Code:</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/make-node</span> <span style="color: #b58900;">(</span><span style="color: #b6a0e0;">id</span> <span style="color: #b58900;">&amp;optional</span> <span style="color: #a6bb99;">parents</span> <span style="color: #e0d0a0;">options</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #b6a0e0;">id</span> <span style="color: #a6bb99;">parents</span> <span style="color: #e0d0a0;">options</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-id</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #a7aac0;">0</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-parents</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #9999bb;">1</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-group</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #268bd2;">(</span><span style="color: #bb99b4;">assoc</span> '<span style="color: #a7aac0;">group</span> <span style="color: #6c71c4;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #a6bb99;">2</span> <span style="color: #99bbb4;">node</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/node-label</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #268bd2;">(</span><span style="color: #bb99b4;">assoc</span> '<span style="color: #a7aac0;">label</span> <span style="color: #6c71c4;">(</span><span style="color: #9999bb;">nth</span> <span style="color: #a6bb99;">2</span> <span style="color: #99bbb4;">node</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/+</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">a</span> <span style="color: #9999bb;">b</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a7aac0;">append</span> <span style="color: #9999bb;">a</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">-remove</span> <span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #859900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #bb99b4;">assoc</span> <span style="color: #b58900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span> <span style="color: #9999bb;">a</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #9999bb;">b</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node-id</span> <span style="color: #b58900;">(</span><span style="color: #b6a0e0;">id</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a0d6e0;">format</span> <span style="color: #2aa198;">"\"%s\""</span> <span style="color: #b6a0e0;">id</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #c0afa7;">node-id</span> <span style="color: #859900;">(</span><span style="color: #c0afa7;">git-graph/to-graphviz-node-id</span> <span style="color: #b58900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #c0a7bd;">concat</span> <span style="color: #c0afa7;">node-id</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">git-graph/to-graphviz-node--attributes</span> <span style="color: #99bbb4;">node</span><span style="color: #6c71c4;">)</span>
<span style="color: #2aa198;">";"</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node--attributes</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">attributes</span> <span style="color: #859900;">(</span><span style="color: #99bbb4;">git-graph/to-graphviz-node--compute-attributes</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #b3c0a7;">and</span> <span style="color: #a3e0a0;">attributes</span>
<span style="color: #6c71c4;">(</span><span style="color: #c0a7bd;">concat</span> <span style="color: #2aa198;">"["</span>
<span style="color: #859900;">(</span><span style="color: #b6a0e0;">mapconcat</span> <span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #268bd2;">(</span><span style="color: #a7aac0;">pair</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #a0d6e0;">format</span> <span style="color: #2aa198;">"%s=\"%s\""</span>
<span style="color: #6c71c4;">(</span><span style="color: #99bbb4;">car</span> <span style="color: #a7aac0;">pair</span><span style="color: #6c71c4;">)</span> <span style="color: #6c71c4;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #a7aac0;">pair</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span>
<span style="color: #a3e0a0;">attributes</span>
<span style="color: #2aa198;">", "</span><span style="color: #859900;">)</span>
<span style="color: #2aa198;">"]"</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-node--compute-attributes</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">-filter</span> #'<span style="color: #a3e0a0;">identity</span>
<span style="color: #268bd2;">(</span><span style="color: #a7aac0;">append</span> <span style="color: #6c71c4;">(</span><span style="color: #b3c0a7;">and</span> <span style="color: #859900;">(</span><span style="color: #b6a0e0;">git-graph/node-group</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #b58900;">(</span><span style="color: #a0d6e0;">cons</span> '<span style="color: #a7aac0;">group</span> <span style="color: #268bd2;">(</span><span style="color: #b6a0e0;">git-graph/node-group</span> <span style="color: #99bbb4;">node</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #b3c0a7;">and</span> <span style="color: #859900;">(</span><span style="color: #e0a0bc;">git-graph/node-label</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #b3c0a7;">list</span> <span style="color: #b58900;">(</span><span style="color: #a0d6e0;">cons</span> '<span style="color: #a6bb99;">shape</span> '<span style="color: #bba699;">box</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a0d6e0;">cons</span> '<span style="color: #a7aac0;">label</span> <span style="color: #268bd2;">(</span><span style="color: #e0a0bc;">git-graph/node-label</span> <span style="color: #99bbb4;">node</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-edges</span> <span style="color: #b58900;">(</span><span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #c0afa7;">node-id</span> <span style="color: #859900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">parents</span> <span style="color: #859900;">(</span><span style="color: #a7c0b9;">git-graph/node-parents</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">-map</span> <span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #859900;">(</span><span style="color: #a7c0b9;">parent</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #b3c0a7;">git-graph/to-graphviz-edge</span> <span style="color: #c0afa7;">node-id</span> <span style="color: #a7c0b9;">parent</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #a6bb99;">parents</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/to-graphviz-edge</span> <span style="color: #b58900;">(</span><span style="color: #a3e0a0;">from</span> <span style="color: #e0a0bc;">to</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #c0a7bd;">concat</span>
<span style="color: #268bd2;">(</span><span style="color: #c0afa7;">git-graph/to-graphviz-node-id</span> <span style="color: #e0a0bc;">to</span><span style="color: #268bd2;">)</span>
<span style="color: #2aa198;">" -&gt; "</span>
<span style="color: #268bd2;">(</span><span style="color: #c0afa7;">git-graph/to-graphviz-node-id</span> <span style="color: #a3e0a0;">from</span><span style="color: #268bd2;">)</span>
<span style="color: #2aa198;">";"</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/group-topo</span> <span style="color: #b58900;">(</span><span style="color: #a7aac0;">nodelist</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #c0afa7;">reverse</span>
<span style="color: #268bd2;">(</span><span style="color: #99bbb4;">car</span>
<span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">-reduce-from</span>
<span style="color: #859900;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #b58900;">(</span><span style="color: #268bd2;">acc</span> <span style="color: #99bbb4;">node</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let*</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">grouped-nodes</span> <span style="color: #859900;">(</span><span style="color: #99bbb4;">car</span> <span style="color: #268bd2;">acc</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">group-stack</span> <span style="color: #859900;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #268bd2;">acc</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #c0afa7;">node-id</span> <span style="color: #859900;">(</span><span style="color: #e0d0a0;">git-graph/node-id</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a7c0b9;">group-from-stack</span> <span style="color: #859900;">(</span><span style="color: #859900; font-weight: bold;">--if-let</span> <span style="color: #2aa198;">(</span><span style="color: #bb99b4;">assoc</span> <span style="color: #c0afa7;">node-id</span> <span style="color: #a6bb99;">group-stack</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #c0a7bd;">cdr</span> <span style="color: #268bd2;">it</span><span style="color: #2aa198;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #859900;">(</span><span style="color: #a7aac0;">or</span> <span style="color: #a7c0b9;">group-from-stack</span> <span style="color: #c0afa7;">node-id</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">parents</span> <span style="color: #859900;">(</span><span style="color: #a7c0b9;">git-graph/node-parents</span> <span style="color: #99bbb4;">node</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #b6a0e0;">first-parent</span> <span style="color: #859900;">(</span><span style="color: #a0d6e0;">first</span> <span style="color: #a6bb99;">parents</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">if</span> <span style="color: #a7c0b9;">group-from-stack</span>
<span style="color: #6c71c4;">(</span><span style="color: #99bbb4;">pop</span> <span style="color: #a6bb99;">group-stack</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">if</span> <span style="color: #6c71c4;">(</span><span style="color: #b3c0a7;">and</span> <span style="color: #b6a0e0;">first-parent</span> <span style="color: #859900;">(</span><span style="color: #9999bb;">not</span> <span style="color: #2aa198;">(</span><span style="color: #bb99b4;">assoc</span> <span style="color: #b6a0e0;">first-parent</span> <span style="color: #a6bb99;">group-stack</span><span style="color: #2aa198;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #6c71c4;">(</span><span style="color: #a6bb99;">push</span> <span style="color: #859900;">(</span><span style="color: #a0d6e0;">cons</span> <span style="color: #b6a0e0;">first-parent</span> <span style="color: #a7aac0;">group</span><span style="color: #859900;">)</span> <span style="color: #a6bb99;">group-stack</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #a0d6e0;">cons</span> <span style="color: #6c71c4;">(</span><span style="color: #a0d6e0;">cons</span> <span style="color: #859900;">(</span><span style="color: #9999bb;">git-graph/make-node</span> <span style="color: #c0afa7;">node-id</span>
<span style="color: #a6bb99;">parents</span>
`<span style="color: #2aa198;">(</span><span style="color: #b58900;">(</span><span style="color: #a7aac0;">group</span> <span style="color: #b3c0a7;">.</span> ,<span style="color: #a7aac0;">group</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #a7aac0;">label</span> <span style="color: #b3c0a7;">.</span> ,<span style="color: #268bd2;">(</span><span style="color: #e0a0bc;">git-graph/node-label</span> <span style="color: #99bbb4;">node</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span><span style="color: #859900;">)</span>
<span style="color: #a3e0a0;">grouped-nodes</span><span style="color: #6c71c4;">)</span>
<span style="color: #a6bb99;">group-stack</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span>
<span style="color: #bb99b4;">nil</span>
<span style="color: #a7aac0;">nodelist</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-execute</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #b6a0e0;">command</span> <span style="color: #b58900;">&amp;rest</span> <span style="color: #a6bb99;">args</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">with-temp-buffer</span>
<span style="color: #268bd2;">(</span><span style="color: #bba699;">shell-command</span> <span style="color: #6c71c4;">(</span><span style="color: #a0d6e0;">format</span> <span style="color: #2aa198;">"git -C \"%s\" %s"</span>
<span style="color: #9999bb;">repo-url</span>
<span style="color: #859900;">(</span><span style="color: #a7c0b9;">string-join</span> <span style="color: #b58900;">(</span><span style="color: #a0d6e0;">cons</span> <span style="color: #b6a0e0;">command</span> <span style="color: #a6bb99;">args</span><span style="color: #b58900;">)</span>
<span style="color: #2aa198;">" "</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #a0d6e0;">t</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">buffer-string</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-rev-list</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #a6bb99;">head</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">-map</span> <span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">line</span><span style="color: #6c71c4;">)</span> <span style="color: #6c71c4;">(</span><span style="color: #9999bb;">split-string</span> <span style="color: #a3e0a0;">line</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #9999bb;">split-string</span> <span style="color: #6c71c4;">(</span><span style="color: #a3e0a0;">git-graph/git-execute</span>
<span style="color: #9999bb;">repo-url</span>
<span style="color: #2aa198;">"rev-list"</span> <span style="color: #2aa198;">"--topo-order"</span> <span style="color: #2aa198;">"--parents"</span> <span style="color: #a6bb99;">head</span><span style="color: #6c71c4;">)</span>
<span style="color: #2aa198;">"\n"</span> <span style="color: #a0d6e0;">t</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-label</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #a3e0a0;">rev</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">let</span> <span style="color: #268bd2;">(</span><span style="color: #6c71c4;">(</span><span style="color: #bba699;">name</span> <span style="color: #859900;">(</span><span style="color: #bba699;">string-trim</span>
<span style="color: #b58900;">(</span><span style="color: #a3e0a0;">git-graph/git-execute</span> <span style="color: #9999bb;">repo-url</span>
<span style="color: #2aa198;">"name-rev"</span> <span style="color: #2aa198;">"--name-only"</span> <span style="color: #a3e0a0;">rev</span><span style="color: #b58900;">)</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span><span style="color: #268bd2;">)</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">unless</span> <span style="color: #6c71c4;">(</span><span style="color: #c0a7bd;">s-contains?</span> <span style="color: #2aa198;">"~"</span> <span style="color: #bba699;">name</span><span style="color: #6c71c4;">)</span>
<span style="color: #bba699;">name</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
<span style="color: #2aa198;">(</span><span style="color: #859900; font-weight: bold;">defun</span> <span style="color: #268bd2;">git-graph/git-load</span> <span style="color: #b58900;">(</span><span style="color: #9999bb;">repo-url</span> <span style="color: #a7c0b9;">heads</span><span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span><span style="color: #859900; font-weight: bold;">-reduce</span> #'<span style="color: #c0afa7;">git-graph/+</span>
<span style="color: #268bd2;">(</span><span style="color: #859900; font-weight: bold;">-map</span> <span style="color: #6c71c4;">(</span><span style="color: #859900; font-weight: bold;">lambda</span> <span style="color: #859900;">(</span><span style="color: #a6bb99;">head</span><span style="color: #859900;">)</span>
<span style="color: #859900;">(</span><span style="color: #a7aac0;">git-graph/git-graph-head</span> <span style="color: #9999bb;">repo-url</span> <span style="color: #a6bb99;">head</span><span style="color: #859900;">)</span><span style="color: #6c71c4;">)</span>
<span style="color: #a7c0b9;">heads</span><span style="color: #268bd2;">)</span><span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>
</pre>
</div>
<p>
Download: <a href="/files/git-graph.el">git-graph.el</a>
</p>
</div>
</div>