diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+0.12.2.0
+---
+* add a diff button to setHo
+
 0.12.1.0
 ---
 * "refresh" clears upstream version so you can see if you get a response
diff --git a/Plot-ho-matic.cabal b/Plot-ho-matic.cabal
--- a/Plot-ho-matic.cabal
+++ b/Plot-ho-matic.cabal
@@ -1,5 +1,5 @@
 name:                Plot-ho-matic
-version:             0.12.1.0
+version:             0.12.2.0
 synopsis:            Real-time line plotter for generic data
 license:             BSD3
 license-file:        LICENSE
@@ -44,7 +44,7 @@
                      , Chart-cairo >= 1.1
                      , containers
                      , data-default-class
-                     , generic-accessors >= 0.6.0.0
+                     , generic-accessors >= 0.6.2.0
                      , glib
                      , gtk3 >= 0.14.2
                      , lens
diff --git a/src/SetHo.hs b/src/SetHo.hs
--- a/src/SetHo.hs
+++ b/src/SetHo.hs
@@ -104,6 +104,7 @@
   buttonTakeUpstream <- Gtk.buttonNewWithLabel "take upstream"
   Gtk.widgetSetTooltipText buttonCommit
     (Just "SET ME SET ME GO HEAD DO IT COME ON SET ME")
+  buttonDiff <- Gtk.buttonNewWithLabel "diff"
 
   mbuttonAutoCommit <-
     if enableAutoCommit config
@@ -132,7 +133,7 @@
   let getAutoCommitStatus = case mbuttonAutoCommit of
         Nothing -> return False
         Just buttonAutoCommit -> Gtk.toggleButtonGetActive buttonAutoCommit
-  (treeview, getLatestStaged, receiveNewUpstream, takeLatestUpstream, loadFromFile) <-
+  (treeview, getLatestStaged, receiveNewUpstream, takeLatestUpstream, loadFromFile, printDiff) <-
     newLookupTreeview (showDouble config) (showFloat config) rootName initialValue getAutoCommitStatus commit
 
   treeviewScroll <- Gtk.scrolledWindowNew Nothing Nothing
@@ -175,6 +176,8 @@
     , Gtk.boxChildPacking buttonRefresh := Gtk.PackNatural
     , Gtk.containerChild := buttonTakeUpstream
     , Gtk.boxChildPacking buttonTakeUpstream := Gtk.PackNatural
+    , Gtk.containerChild := buttonDiff
+    , Gtk.boxChildPacking buttonDiff := Gtk.PackNatural
     , Gtk.containerChild := options
     , Gtk.boxChildPacking options := Gtk.PackNatural
     , Gtk.containerChild := treeviewExpander
@@ -190,6 +193,8 @@
     sendRequest counter
 
   _ <- on buttonTakeUpstream Gtk.buttonActivated takeLatestUpstream
+
+  _ <- on buttonDiff Gtk.buttonActivated printDiff
 
   let pollForNewMessage = do
         mmsg <- userPollForNewMessage
diff --git a/src/SetHo/LookupTree.hs b/src/SetHo/LookupTree.hs
--- a/src/SetHo/LookupTree.hs
+++ b/src/SetHo/LookupTree.hs
@@ -11,6 +11,7 @@
        ( DTree, DData(..), DConstructor(..), DSimpleEnum(..), DField(..)
        , describeDField, sameDFieldType
        , denumToString, denumToStringOrMsg, denumSetString
+       , diffDTrees
        )
 import Control.Monad ( void, when )
 import qualified Data.Text as T
@@ -158,7 +159,7 @@
   -> DTree
   -> IO Bool
   -> (DTree -> IO ())
-  -> IO (Gtk.TreeView, IO DTree, DTree -> IO (), IO (), DTree -> IO ())
+  -> IO (Gtk.TreeView, IO DTree, DTree -> IO (), IO (), DTree -> IO (), IO ())
 newLookupTreeview showDouble showFloat rootName initialValue getAutocommit commit = do
   treeStore <- Gtk.treeStoreNew [] :: IO (Gtk.TreeStore ListViewElement)
   treeview <- Gtk.treeViewNewWithModel treeStore :: IO Gtk.TreeView
@@ -497,7 +498,16 @@
   tree <- ddataToTree (Just rootName) initialValue
   Gtk.treeStoreInsertTree treeStore [] 0 tree
 
-  return (treeview, getLatestStaged, receiveNewUpstream, takeLatestUpstream, loadDTree)
+  let printDiff = do
+        mupstream <- getLatestUpstream :: IO (Maybe (Either DField DData))
+        staged <- getLatestStaged :: IO (Either DField DData)
+        case mupstream of
+          Just upstream -> case diffDTrees rootName upstream staged of
+            [] -> putStrLn "======== all fields match! ======="
+            msgs -> putStrLn "====== some fields don't match! =====" >> mapM_ putStrLn msgs
+          Nothing -> putStrLn "===== no staged data ===="
+
+  return (treeview, getLatestStaged, receiveNewUpstream, takeLatestUpstream, loadDTree, printDiff)
 
 mergeSums :: SumElem -> SumElem -> (Bool, SumElem)
 mergeSums oldSum newSum
