diff --git a/bin/is b/bin/is
index 3ff65366d5f43b34912c7f72c4dc8da5f52b91d4..4b7932a7485de39655678dcea7b128b56cf8e78e 100755
--- a/bin/is
+++ b/bin/is
@@ -149,6 +149,18 @@ def c_del(parser, args):
                 raise Exception("Aborted!")
         repo.delete(img.name, img.version)
 
+def c_diff(parser, args):
+    '''
+    Show diff between two repositories or images
+    '''
+    repoman = load_repositories(args)
+    if args.object[0] in repoman.onlines and args.object[1] in repoman.onlines:
+        Repository.diff(repoman[args.object[0]], repoman[args.object[1]])
+    else:
+        img1, repo1 = select_image(args.object[0], repoman, args.best)
+        img2, repo2 = select_image(args.object[1], repoman, args.best)
+        PackageImage.diff(img1, img2)
+
 def c_extract(parser, args):
     '''
     Extract an image package inside a directory
@@ -357,6 +369,14 @@ p_del.add_argument("-f", "--force", action="store_true", default=False,
                    help="delete image without confirmation")
 p_del.set_defaults(func=c_del)
 
+# diff command parser
+p_diff = subparsers.add_parser("diff", help=c_diff.__doc__.lower())
+p_diff.add_argument("object", nargs=2,
+                    help="object syntax is <path|repository|[repository/]image[:version]>")
+p_diff.add_argument("-b", "--best", action="store_true", default=False,
+                    help="in best mode, image is the most recent in all repositories")
+p_diff.set_defaults(func=c_diff)
+
 # extract command parser
 p_extract = subparsers.add_parser("extract", help=c_extract.__doc__.lower())
 p_extract.add_argument("-p", action="store_true", dest="payload", default=False,
diff --git a/installsystems/image.py b/installsystems/image.py
index d261c87ac6ae6917ac9a89b76e2b75e71da741e6..db07b5a2df2a72cefe033475a2b897922abda90f 100644
--- a/installsystems/image.py
+++ b/installsystems/image.py
@@ -10,6 +10,7 @@ import os
 import stat
 import time
 import json
+import difflib
 import ConfigParser
 import subprocess
 import tarfile
@@ -351,6 +352,46 @@ class PackageImage(Image):
     Packaged image manipulation class
     '''
 
+    @classmethod
+    def diff(cls, pkg1, pkg2):
+        '''
+        Diff two packaged images
+        '''
+        arrow("Differnce from images #y#%s v%s#R# to #r#%s v%s#R#:" % (pkg1.name,
+                                                                       pkg1.version,
+                                                                       pkg2.name,
+                                                                       pkg2.version))
+        # Extract images for diff scripts files
+        fromfiles = set(pkg1._tarball.getnames(re_pattern="(parser|setup)/.*"))
+        tofiles = set(pkg2._tarball.getnames(re_pattern="(parser|setup)/.*"))
+        for f in fromfiles | tofiles:
+            # preparing from info
+            if f in fromfiles:
+                fromfile = os.path.join(pkg1.id, f)
+                fromdata = pkg1._tarball.extractfile(f).readlines()
+            else:
+                fromfile = "/dev/null"
+                fromdata = ""
+            # preparing to info
+            if f in tofiles:
+                tofile = os.path.join(pkg2.id, f)
+                todata = pkg2._tarball.extractfile(f).readlines()
+            else:
+                tofile = "/dev/null"
+                todata = ""
+            # generate diff
+            for line in difflib.unified_diff(fromdata, todata,
+                                             fromfile=fromfile, tofile=tofile):
+                # coloring diff
+                if line.startswith("+"):
+                   out("#g#%s#R#" % line, endl="")
+                elif line.startswith("-"):
+                   out("#r#%s#R#" % line, endl="")
+                elif line.startswith("@@"):
+                   out("#c#%s#R#" % line, endl="")
+                else:
+                   out(line, endl="")
+
     def __init__(self, path, fileobj=None, md5name=False):
         '''
         Initialize a package image
@@ -569,7 +610,6 @@ class PackageImage(Image):
             arrowlevel(level=old_level)
         arrowlevel(-1)
 
-
 class Payload(object):
     '''
     Payload class represents a payload object
diff --git a/installsystems/repository.py b/installsystems/repository.py
index 858b528ec7b590c3772e186ec3787ce2fc56a430..418d251484224b389fe7ce7c692b4c74f7e09f35 100644
--- a/installsystems/repository.py
+++ b/installsystems/repository.py
@@ -26,6 +26,42 @@ class Repository(object):
     Repository class
     '''
 
+    @classmethod
+    def diff(cls, repo1, repo2):
+        '''
+        Comptue a diff between two repositories
+        '''
+        arrow("Diff between repositories #y#%s#R# and #g#%s#R#" % (repo1.config.name,
+                                                       repo2.config.name))
+        # Get info from databases
+        i_dict1 = dict((b[0], b[1:]) for b in repo1.db.ask(
+                "SELECT md5, name, version FROM image").fetchall())
+        i_set1 = set(i_dict1.keys())
+        i_dict2 = dict((b[0], b[1:]) for b in repo2.db.ask(
+                "SELECT md5, name, version FROM image").fetchall())
+        i_set2 = set(i_dict2.keys())
+        p_dict1 = dict((b[0], b[1:]) for b in  repo1.db.ask(
+                "SELECT md5, name FROM payload").fetchall())
+        p_set1 = set(p_dict1.keys())
+        p_dict2 = dict((b[0], b[1:]) for b in repo2.db.ask(
+                "SELECT md5, name FROM payload").fetchall())
+        p_set2 = set(p_dict2.keys())
+        # computing diff
+        i_only1 = i_set1 - i_set2
+        i_only2 = i_set2 - i_set1
+        p_only1 = p_set1 - p_set2
+        p_only2 = p_set2 - p_set1
+        # printing functions
+        pimg = lambda r,c,m,d,: out("#%s#Image only in repository %s: %s v%s (%s)#R#" %
+                                    (c, r.config.name, d[m][0], d[m][1], m))
+        ppay = lambda r,c,m,d,: out("#%s#Payload only in repository %s: %s (%s)#R#" %
+                                    (c, r.config.name, d[m][0], m))
+        # printing image diff
+        for md5 in i_only1: pimg(repo1, "y", md5, i_dict1)
+        for md5 in p_only1: ppay(repo1, "y", md5, p_dict1)
+        for md5 in i_only2: pimg(repo2, "g", md5, i_dict2)
+        for md5 in p_only2: ppay(repo2, "g", md5, p_dict2)
+
     def __init__(self, config):
         self.config = config
         if not config.offline: