diff --git a/upgrade-helper.py b/upgrade-helper.py
index aecb207..e6ae77f 100755
--- a/upgrade-helper.py
+++ b/upgrade-helper.py
@@ -42,6 +42,7 @@ import re
 import signal
 import sys
 import configparser
+import glob
 from datetime import datetime
 from datetime import date
 import shutil
@@ -99,10 +100,12 @@ def parse_cmdline():
 
     parser.add_argument("-t", "--to_version",
                         help="version to upgrade the recipe to")
-
     parser.add_argument("--stable", action="store_true", default=False,
                         help="only upgrade to the next patch version within the stable branch (e.g. 1.2.3 -> 1.2.4)")
 
+    parser.add_argument("--resume", action="store_true", default=False,
+                        help="skip recipes already attempted in the last run")
+
     parser.add_argument("-d", "--debug-level", type=int, default=4, choices=range(1, 6),
                         help="set the debug level: CRITICAL=1, ERROR=2, WARNING=3, INFO=4, DEBUG=5")
     parser.add_argument("-e", "--send-emails", action="store_true", default=False,
@@ -493,10 +496,34 @@ class Updater(object):
         succeeded_pkggroups_ctx = []
         failed_pkggroups_ctx = []
         attempted_pkggroups = 0
+
+        # --resume: skip recipes already attempted in the most recent run
+        resume_skip = set()
+        if self.args.resume:
+            prev_runs = sorted(glob.glob(os.path.join(self.uh_dir, "20*")))
+            prev_runs = [r for r in prev_runs if r != self.uh_work_dir]
+            if prev_runs:
+                prev_dir = prev_runs[-1]
+                for d in ("succeed", "failed"):
+                    result_dir = os.path.join(prev_dir, d)
+                    if os.path.isdir(result_dir):
+                        resume_skip.update(os.listdir(result_dir))
+                if resume_skip:
+                    I(" --resume: skipping %d recipes from %s" %
+                      (len(resume_skip), prev_dir))
+            else:
+                W(" --resume: no previous run found, nothing to skip")
         for g in pkggroups_ctx:
             attempted_pkggroups += 1
             pkggroup_name = g["name"]
+
+            if g['name'] in resume_skip:
+                I(" SKIP PACKAGE GROUP %d/%d (already attempted): %s" %
+                  (attempted_pkggroups, total_pkggroups, pkggroup_name))
+                continue
+
             I(" ATTEMPT PACKAGE GROUP %d/%d" % (attempted_pkggroups, total_pkggroups))
+
             try:
                 for pkg_ctx in g['pkgs']:
                     I(" %s: Upgrading to %s" % (pkg_ctx['PN'], pkg_ctx['NPV']))
@@ -541,6 +568,15 @@ class Updater(object):
                     succeeded_pkggroups_ctx.remove(g)
                     failed_pkggroups_ctx.append(g)
 
+            # Create symlink immediately so --resume can find it
+            if 'workdir' in g:
+                if any(g['name'] == s['name'] for s in succeeded_pkggroups_ctx):
+                    link = os.path.join(self.uh_recipes_succeed_dir, g['name'])
+                else:
+                    link = os.path.join(self.uh_recipes_failed_dir, g['name'])
+                if not os.path.exists(link):
+                    os.symlink(g['workdir'], link)
+
         if self.opts['testimage']:
             ctxs = {}
             ctxs['succeeded'] = succeeded_pkggroups_ctx
@@ -551,15 +587,7 @@ class Updater(object):
 
             tim.run()
 
-        for g in pkggroups_ctx:
-
-            if g in succeeded_pkggroups_ctx:
-                os.symlink(g['workdir'], os.path.join( \
-                    self.uh_recipes_succeed_dir, g['name']))
-            else:
-                os.symlink(g['workdir'], os.path.join( \
-                    self.uh_recipes_failed_dir, g['name']))
-
+        for g in succeeded_pkggroups_ctx + failed_pkggroups_ctx:
             self.statistics.update(g)
             self.pkg_upgrade_handler(g)
 
