diff --git a/gipeda.cabal b/gipeda.cabal
--- a/gipeda.cabal
+++ b/gipeda.cabal
@@ -1,5 +1,5 @@
 name:                gipeda
-version:             0.3.2.2
+version:             0.3.3.0
 category:            Development
 synopsis:            Git Performance Dashboard
 description:
@@ -76,7 +76,7 @@
       vector               >= 0.10  && <0.12,
       cassava              >= 0.4   && <0.5,
       yaml                 >= 0.8   && <0.9,
-      aeson                >= 0.7   && <1.1,
+      aeson                >= 0.7   && <1.2,
       scientific           >= 0.3   && <0.4,
       gitlib               >= 3.1.0.2 && <3.2,
       gitlib-libgit2,
diff --git a/site/js/gipeda.js b/site/js/gipeda.js
--- a/site/js/gipeda.js
+++ b/site/js/gipeda.js
@@ -47,7 +47,15 @@
         { regex: /^revision\/([a-f0-9]+)$/,
           viewData: function (match) { return { hash: match[1] }; },
           download: function () {
-            return ['out/benchNames.json','out/reports/' + viewData.hash + '.json'];
+            todo = ['out/benchNames.json','out/reports/' + viewData.hash + '.json'];
+            if (data && data.revisions) {
+                var rev = data.revisions[viewData.hash];
+                if (rev && rev.summary && rev.summary.parents) {
+                    var parentHash = rev.summary.parents[0];
+                    todo.push('out/reports/' + parentHash + '.json');
+                }
+            }
+            return todo;
           },
           url: function (hash) { return "revision/" + hash; },
         },
@@ -105,13 +113,15 @@
     viewChanged.dispatch();
 }
 
-viewChanged.add(function () {
+function load_missing_data() {
     if (routes[view].download) {
         d = routes[view].download;
-        if ($.isFunction(d)) {d = d()}
-        d.forEach(function (url) { getJSON(url) });
+        if ($.isFunction(d)) {d = d(); }
+        d.forEach(function (url) { getJSON(url); });
     }
-});
+}
+viewChanged.add(load_missing_data);
+dataChanged.add(load_missing_data);
 
 function handleHashChange(newHash) {
     parseRoute(newHash);
@@ -343,7 +353,7 @@
         if (benchmark_name_matches(s.match, name)) {
             $.extend(benchSettings, s);
         }
-    })
+    });
 
     return benchSettings;
 }
@@ -351,12 +361,12 @@
 
 // The following logic should be kept in sync with toResult in ReportTypes.hs
 function compareResults (res1, res2) {
-    if (!res1 && !res2) { return };
+    if (!res1 && !res2) { return; }
 
-    name = res1? res1.name : res2.name;
-    s = setting_for(name);
+    var name = res1? res1.name : res2.name;
+    var s = setting_for(name);
 
-    res = {
+    var res = {
         name: name,
         previous:    res1 ? res1.value : null,
         value:       res2 ? res2.value : null,
@@ -368,9 +378,9 @@
 
     if (res1 && res2){
         if (s.type == "integral" || s.type == "float"){
-            if (res1.value == 0 && res2.value == 0) {
+            if (res1.value === 0 && res2.value === 0) {
                 res.change = "=";
-            } else if (res1.value == 0) {
+            } else if (res1.value === 0) {
                 res.change = "+  ∞";
                 res.changeType = "Improvement";
             } else {
@@ -418,26 +428,73 @@
     return res;
 }
 
+// A variant of compareResults, for when there is nothing to compare.
+function singleResult (res) {
+    if (!res) { return; }
+    var name = res.name;
+    var s = setting_for(name);
+
+    return  {
+        name: name,
+        previous:    null,
+        value:       res.value,
+        unit:        s.unit,
+        important:   s.important,
+        changeType: "Boring",
+        change:     "",
+    };
+}
+
 // Some views require the data to be prepared in ways that are 
 // too complicated for the template, so lets do it here.
-dataViewPrepare = {
-  'revision': function (data, viewData) {
-    if (!data.benchGroups || !data.revisions) return {};
-    var hash = viewData.hash;
-    var rev = data.revisions[hash];
-    if (!rev) return {};
-    if (!rev.benchResults) return {};
 
-    var groups = data.benchGroups.map(function (group) {
+// revision and compare actually share a lot of logic, the difference is only
+// where the starting commit is from
+function calculate_groups(rev1, rev2) {
+    if (!rev2) return {};
+    if (!rev2.benchResults) return {};
+
+    return data.benchGroups.map(function (group) {
       var benchmarks = group.groupMembers.map(function (bn) {
-	return rev.benchResults[bn]
-      }).filter(function (br) {return br});
+        var r2 = rev2.benchResults[bn];
+        if (rev1 && rev1.benchResults) {
+            var r1 = rev1.benchResults[bn];
+            return compareResults(r1,r2);
+        } else {
+            return singleResult(r2);
+        }
+      }).filter(function (br) {return br;});
       return {
 	groupName: group.groupName || "Benchmarks",
 	benchResults: benchmarks,
 	groupStats: groupStats(benchmarks),
       };
     });
+}
+
+dataViewPrepare = {
+  'revision': function (data, viewData) {
+    if (!data.benchGroups || !data.revisions) return {};
+    var hash = viewData.hash;
+    var rev = data.revisions[hash];
+
+    if (!rev) return {};
+    if (!rev.benchResults) return {};
+
+    var groups;
+    if (rev.summary.parents) {
+        var parentHash = rev.summary.parents[0];
+        var parentRev  = data.revisions[parentHash];
+
+        if (parentRev) {
+            groups = calculate_groups(parentRev, rev);
+        }
+    }
+    // Fallback (no parent, or parent not loaded yet)
+    if (!groups) {
+        groups = calculate_groups(null, rev);
+    }
+
     return {
       rev : rev,
       groups : groups,
@@ -449,30 +506,13 @@
     var hash2 = viewData.hash2;
     var rev1 = data.revisions[hash1];
     var rev2 = data.revisions[hash2];
-    if (!rev1) return {};
-    if (!rev1.benchResults) return {};
-    if (!rev2) return {};
-    if (!rev2.benchResults) return {};
-
-    var groups = data.benchGroups.map(function (group) {
-      var benchmarks = group.groupMembers.map(function (bn) {
-	var r1 = rev1.benchResults[bn];
-	var r2 = rev2.benchResults[bn];
-	return compareResults(r1,r2);
-      }).filter(function (br) {return br});
-      return {
-	groupName: group.groupName || "Benchmarks",
-	benchResults: benchmarks,
-	groupStats: groupStats(benchmarks),
-      };
-    });
     return {
       rev1 : rev1,
       rev2 : rev2,
-      groups : groups,
+      groups : calculate_groups(rev1, rev2),
     };
   },
-}
+};
 
 function remember_from_to() {
     settings.compare.from = $('#compare-from').data('rev');
diff --git a/src/GraphReport.hs b/src/GraphReport.hs
--- a/src/GraphReport.hs
+++ b/src/GraphReport.hs
@@ -18,24 +18,51 @@
 graphReportMain :: [String] -> IO ()
 graphReportMain (bench:revs) = do
     settings <- S.readSettings "gipeda.yaml"
+    let s = S.benchSettings settings bench
 
-    g <- forM revs $ \rev -> do
-        json <- BS.readFile (reportOf rev)
-        rep <- case eitherDecode json of
-            Left e -> fail e
-            Right rep -> return rep
-        case M.lookup bench (benchResults (rep !!! "revisions" !!! rev)) of
+    g <- forM (withPrev revs) $ \(rev, prevM) -> do
+        report <- readReport rev
+
+        case M.lookup bench (benchResults report) of
             Nothing -> return Nothing
-            Just result -> return $ Just $ T.pack rev .= object
+            Just result -> do
+                changeType <- case prevM of
+                    Nothing -> return Boring
+                    Just prev -> do
+                        prevReport <- readReport prev
+                        case M.lookup bench (benchResults prevReport) of
+                            Nothing -> return Boring
+                            Just prevResult ->
+                                let comp = makeComparison s bench (value result) (Just (value prevResult))
+                                in return $ changeType comp
+
+                return $ Just $ T.pack rev .= object
                         [ "benchResults" .= object
-                            [ T.pack bench .= benchResultToGraphPoint result ]
+                            [ T.pack bench .= GraphPoint
+                                { gpValue = value result
+                                , gpChangeType = changeType
+                                }
+                            ]
                         ]
     let doc = object
                 [ "revisions" .= object (catMaybes g)
                 , "benchmarkSettings" .= object
-                    [ T.pack bench .= toJSON (S.benchSettings settings bench) ]
+                    [ T.pack bench .= toJSON s ]
                 ]
 
     BS.putStr (encode doc)
-  where
-   m !!! k =  m M.! T.pack k
+
+readReport :: Hash -> IO RevReport
+readReport hash = do
+    json <- BS.readFile (reportOf hash)
+    case eitherDecode json of
+        Left e    -> fail e
+        Right rep -> return $ rep !!! "revisions" !!! hash
+
+(!!!) :: M.Map T.Text a -> String -> a
+m !!! k =  m M.! T.pack k
+
+withPrev :: [a] -> [(a, Maybe a)]
+withPrev (x:y:ys) = (x, Just y) : withPrev (y:ys)
+withPrev [x]      = [(x, Nothing)]
+withPrev []       = []
diff --git a/src/ReportTypes.hs b/src/ReportTypes.hs
--- a/src/ReportTypes.hs
+++ b/src/ReportTypes.hs
@@ -63,12 +63,18 @@
             SummaryStats (a + a') (b + b') (c + c')
 -}
 
+data Status = Built | Failed | Waiting
+ deriving (Show, Generic)
+instance ToJSON Status
+instance FromJSON Status
+
 data Summary = Summary
     { hash :: Hash
     , gitDate :: Integer
     , gitSubject :: String
     , stats :: SummaryStats
-    , parents :: [String]
+    , parents :: [Hash]
+--    , status :: Status
     }
  deriving (Generic)
 instance ToJSON Summary
@@ -111,9 +117,6 @@
 data BenchResult = BenchResult
     { name :: String
     , value :: BenchValue
-    , previous :: Maybe BenchValue
-    , change :: String
-    , changeType :: ChangeType
     , unit :: String
     , important :: Bool
     }
@@ -126,7 +129,17 @@
 instance FromJSON BenchResult where
     parseJSON = genericParseJSON defaultOptions
 
+data BenchComparison = BenchComparison
+    { changeName :: String
+    , change :: String
+    , changeType :: ChangeType
+    , changeImportant :: Bool
+    }
+
 -- A smaller BenchResult
+-- (This is a hack: BenchResult no longer carries a changeType. But it is convenient to
+-- have that in the graph report, for the tallying for the graph summary. But all not very
+-- satisfactory.)
 data GraphPoint = GraphPoint
     { gpValue :: BenchValue
     , gpChangeType :: ChangeType
@@ -143,11 +156,6 @@
 graphPointOptions = defaultOptions { fieldLabelModifier = fixup }
   where fixup ('g':'p':c:cs) = toLower c : cs
 
-benchResultToGraphPoint (BenchResult {..}) = GraphPoint
-    { gpValue = value
-    , gpChangeType = changeType
-    }
-
 invertChangeType :: ChangeType -> ChangeType
 invertChangeType Improvement = Regression
 invertChangeType Boring = Boring
@@ -200,17 +208,22 @@
 -- even if the user did not set the numberType correctly:
 explain s                                     v1     v2     = explainFloat s (toFloat v1) (toFloat v2)
 
-toResult :: S.BenchSettings -> String -> BenchValue -> Maybe BenchValue -> BenchResult
-toResult s name value prev = BenchResult
-    { name = name
-    , value = value
-    , previous = prev
-    , change = change
-    , changeType = changeType
-    , unit = S.unit s
+toResult :: S.BenchSettings -> String -> BenchValue -> BenchResult
+toResult s name value = BenchResult
+    { name      = name
+    , value     = value
+    , unit      = S.unit s
     , important = S.important s
     }
-  where 
+
+makeComparison :: S.BenchSettings -> String -> BenchValue -> Maybe BenchValue -> BenchComparison
+makeComparison s name value prev = BenchComparison
+    { changeName      = name
+    , change          = change
+    , changeType      = changeType
+    , changeImportant = S.important s
+    }
+  where
     (change, changeType') =
         case prev of
             Just p -> explain s p value
@@ -218,22 +231,20 @@
     changeType | S.smallerIsBetter s = invertChangeType changeType'
                | otherwise           =                  changeType'
 
-toSummaryStats :: [BenchResult] -> SummaryStats
-toSummaryStats res = SummaryStats
-    { totalCount = length res
+toSummaryStats :: [BenchComparison] -> SummaryStats
+toSummaryStats comps = SummaryStats
+    { totalCount = length comps
     , improvementCount = length
-        [ ()
-        | BenchResult { changeType = Improvement, important = True } <- res
-        ]
+        [ () | comp <- importantComps , changeType comp == Improvement ]
     , regressionCount =  length
-        [ ()
-        | BenchResult { changeType = Regression, important = True } <- res
-        ]
+        [ () | comp <- importantComps , changeType comp == Regression ]
     , summaryDesc = andMore 5
-        [ name r ++ ": " ++ change r
-        | r <- res, important r, changeType r `elem` [Improvement, Regression]
+        [ changeName comp ++ ": " ++ change comp
+        | comp <- importantComps
+        , changeType comp `elem` [Improvement, Regression]
         ]
     }
+  where importantComps = filter changeImportant comps
 
 andMore :: Int -> [String] -> String
 andMore _ [] = "–"
@@ -262,12 +273,12 @@
 createBranchReport settings this other thisM otherM commitCount = BranchReport
     { branchHash = this
     , mergeBaseHash = other
-    , branchStats = toSummaryStats $ M.elems results
+    , branchStats = toSummaryStats comparisons
     , commitCount = commitCount
     }
   where
-    results = M.fromList
-        [ (name, toResult s name value (M.lookup name otherM))
+    comparisons =
+        [ makeComparison s name value (M.lookup name otherM)
         | (name, value) <- M.toAscList thisM
         , let s = S.benchSettings settings name
         ]
@@ -277,11 +288,11 @@
     ResultMap -> ResultMap ->
     String -> String -> Integer ->
     RevReport
-createReport settings this parents thisM parentM log subject date = RevReport 
+createReport settings this parents thisM parentM log subject date = RevReport
     { summary = Summary
         { hash = this
         , parents = parents
-        , stats = toSummaryStats $ M.elems results
+        , stats = toSummaryStats comparisons
         , gitSubject = subject
         , gitDate = date
         }
@@ -291,10 +302,15 @@
     }
   where
     results = M.fromList
-        [ (name, toResult s name value (M.lookup name parentM))
+        [ (name, toResult s name value)
         | (name, value) <- M.toAscList thisM
         , let s = S.benchSettings settings name
         ]
+    comparisons =
+        [ makeComparison s name value (M.lookup name parentM)
+        | (name, value) <- M.toAscList thisM
+        , let s = S.benchSettings settings name
+        ]
 
 summarize :: RevReport -> Summary
-summarize (RevReport {..}) =  summary 
+summarize (RevReport {..}) = summary
