diff --git a/lib/workers/repository/index.js b/lib/workers/repository/index.js
index 59410ac512b3e4b809b31992df7ea46ffd285bd7..ca886116c59fc45bb59adf2a84b295e95865ff2e 100644
--- a/lib/workers/repository/index.js
+++ b/lib/workers/repository/index.js
@@ -24,130 +24,140 @@ function pinDependenciesFirst(a, b) {
   return a.branchName > b.branchName;
 }
 
-async function renovateRepository(repoConfig, token) {
+async function renovateRepositoryInner(repoConfig, token, count = 1) {
   let config = { ...repoConfig };
   const { logger } = config;
-  config.tmpDir = tmp.dirSync({ unsafeCleanup: true });
-  config.errors = [];
-  config.warnings = [];
-  logger.trace({ config }, 'renovateRepository');
-  try {
-    let branchList;
-    let baseBranchUpdated;
-    let loopCount = 1;
-    do {
-      logger.debug(`renovateRepository loop ${loopCount}`);
-      baseBranchUpdated = false;
-      config = await apis.initApis(config, token);
-      config = await apis.mergeRenovateJson(config);
-      if (config.enabled === false) {
-        logger.debug('repository is disabled');
-        await cleanup.pruneStaleBranches(config, []);
-        return;
-      }
-      if (config.isFork && !config.renovateJsonPresent) {
-        logger.debug('repository is a fork and not manually configured');
-        return;
-      }
-      if (config.baseBranch) {
-        // Renovate should read content and target PRs here
-        if (await config.api.branchExists(config.baseBranch)) {
-          config.api.setBaseBranch(config.baseBranch);
-        } else {
-          // Warn and ignore setting (use default branch)
-          const message = `The configured baseBranch "${config.baseBranch}" is not present. Ignoring`;
-          config.errors.push({
-            depName: 'baseBranch',
-            message,
-          });
-          logger.warn(message);
-        }
-      }
-      config = await onboarding.getOnboardingStatus(config);
-      // Detect package files in default branch if not manually provisioned
-      if (config.packageFiles.length === 0) {
-        logger.debug('Detecting package files');
-        config = await apis.detectPackageFiles(config);
-        // If we can't detect any package.json then return
-        if (config.packageFiles.length === 0) {
-          logger.info('Cannot detect package files');
-          // istanbul ignore if
-          if (config.repoIsOnboarded === false) {
-            logger.warn('Need to delete onboarding PR');
-            const pr = await config.api.getBranchPr(config.onboardingBranch);
-            if (pr) {
-              logger.info('Found onboarding PR');
-              await config.api.updatePr(
-                pr.number,
-                'Configure Renovate - canceled',
-                'This PR was created in error and is now being deleted automatically. Sorry for the inconvenience.'
-              );
-              await config.api.deleteBranch(config.onboardingBranch);
-              throw new Error('no package files');
-            }
-          }
-          return;
-        }
-        logger.debug(
-          `Detected ${config.packageFiles
-            .length} package files: ${config.packageFiles}`
-        );
-      }
-      logger.debug('Resolving package files and content');
-      config = await apis.resolvePackageFiles(config);
-      config = await apis.checkMonorepos(config);
-      logger.trace({ config }, 'post-packageFiles config');
-      // TODO: why is this fix needed?!
-      config.logger = logger;
-      config = decryptConfig(config);
-      logger.trace({ config }, 'post-decrypt config');
-      const allUpgrades = await upgrades.determineRepoUpgrades(config);
-      const res = await upgrades.branchifyUpgrades(allUpgrades, logger);
-      config.errors = config.errors.concat(res.errors);
-      config.warnings = config.warnings.concat(res.warnings);
-      const branchUpgrades = res.upgrades;
-      logger.debug(`Updating ${branchUpgrades.length} branch(es)`);
-      logger.trace({ config: branchUpgrades }, 'branchUpgrades');
-      if (config.repoIsOnboarded) {
-        logger.info(`Processing ${branchUpgrades.length} branch(es)`);
-        // eslint-disable-next-line no-loop-function
-        branchUpgrades.sort(pinDependenciesFirst);
-        const branchStartTime = process.hrtime();
-        for (const branchUpgrade of branchUpgrades) {
-          const branchResult = await branchWorker.processBranch(
-            branchUpgrade,
-            config.errors,
-            config.warnings
+  // istanbul ignore if
+  if (count > 5) {
+    // This is an arbitrary number added in to cut short any unintended infinite recursion
+    throw new Error('Existing renovateRepositoryInner after 5 loops');
+  }
+  logger.info(`renovateRepository loop ${count}`);
+  let branchList = [];
+  config = await apis.initApis(config, token);
+  config = await apis.mergeRenovateJson(config);
+  if (config.enabled === false) {
+    logger.debug('repository is disabled');
+    await cleanup.pruneStaleBranches(config, []);
+    return null;
+  }
+  if (config.isFork && !config.renovateJsonPresent) {
+    logger.debug('repository is a fork and not manually configured');
+    return null;
+  }
+  if (config.baseBranch) {
+    // Renovate should read content and target PRs here
+    if (await config.api.branchExists(config.baseBranch)) {
+      config.api.setBaseBranch(config.baseBranch);
+    } else {
+      // Warn and ignore setting (use default branch)
+      const message = `The configured baseBranch "${config.baseBranch}" is not present. Ignoring`;
+      config.errors.push({
+        depName: 'baseBranch',
+        message,
+      });
+      logger.warn(message);
+    }
+  }
+  config = await onboarding.getOnboardingStatus(config);
+  // Detect package files in default branch if not manually provisioned
+  if (config.packageFiles.length === 0) {
+    logger.debug('Detecting package files');
+    config = await apis.detectPackageFiles(config);
+    // If we can't detect any package.json then return
+    if (config.packageFiles.length === 0) {
+      logger.info('Cannot detect package files');
+      // istanbul ignore if
+      if (config.repoIsOnboarded === false) {
+        logger.warn('Need to delete onboarding PR');
+        const pr = await config.api.getBranchPr(config.onboardingBranch);
+        if (pr) {
+          logger.info('Found onboarding PR');
+          await config.api.updatePr(
+            pr.number,
+            'Configure Renovate - canceled',
+            'This PR was created in error and is now being deleted automatically. Sorry for the inconvenience.'
           );
-          if (branchResult === 'automerged') {
-            // Stop procesing other branches because base branch has been changed by an automerge
-            logger.info('Restarting repo renovation after automerge');
-            baseBranchUpdated = true;
-            break;
-          } else if (branchResult === 'lockFileError') {
-            logger.info('Lock file error - stopping branch updates');
-            break;
-          } else if (branchUpgrade.type === 'pin') {
-            logger.info(
-              'Stopping branch processing until Pin Dependencies is merged'
-            );
-            break;
-          }
+          await config.api.deleteBranch(config.onboardingBranch);
+          throw new Error('no package files');
         }
+      }
+      return null;
+    }
+    logger.info(
+      {
+        packageFiles: config.packageFiles,
+        count: config.packageFiles.length,
+      },
+      `Detected package files`
+    );
+  }
+  logger.debug('Resolving package files and content');
+  config = await apis.resolvePackageFiles(config);
+  config = await apis.checkMonorepos(config);
+  logger.trace({ config }, 'post-packageFiles config');
+  // TODO: why is this fix needed?!
+  config.logger = logger;
+  config = decryptConfig(config);
+  logger.trace({ config }, 'post-decrypt config');
+  const allUpgrades = await upgrades.determineRepoUpgrades(config);
+  const res = await upgrades.branchifyUpgrades(allUpgrades, logger);
+  config.errors = config.errors.concat(res.errors);
+  config.warnings = config.warnings.concat(res.warnings);
+  const branchUpgrades = res.upgrades;
+  logger.debug(`Updating ${branchUpgrades.length} branch(es)`);
+  logger.trace({ config: branchUpgrades }, 'branchUpgrades');
+  if (config.repoIsOnboarded) {
+    logger.info(`Processing ${branchUpgrades.length} branch(es)`);
+    // eslint-disable-next-line no-loop-function
+    branchUpgrades.sort(pinDependenciesFirst);
+    const branchStartTime = process.hrtime();
+    branchList = branchUpgrades.map(upgrade => upgrade.branchName);
+    for (const branchUpgrade of branchUpgrades) {
+      const branchResult = await branchWorker.processBranch(
+        branchUpgrade,
+        config.errors,
+        config.warnings
+      );
+      if (branchResult === 'automerged') {
+        // Stop procesing other branches because base branch has been changed by an automerge
+        logger.info('Restarting repo renovation after automerge');
+        return renovateRepositoryInner(repoConfig, token, count + 1);
+      } else if (branchResult === 'lockFileError') {
+        logger.info('Lock file error - stopping branch updates');
+        return branchList;
+      } else if (branchUpgrade.type === 'pin') {
         logger.info(
-          { seconds: convertHrTime(process.hrtime(branchStartTime)).seconds },
-          'Finished updating branches'
+          'Stopping branch processing until Pin Dependencies is merged'
         );
-        branchList = branchUpgrades.map(upgrade => upgrade.branchName);
-        logger.debug(`branchList=${branchList}`);
-      } else {
-        await onboarding.ensurePr(config, branchUpgrades);
-        logger.info('"Configure Renovate" PR needs to be closed first');
-        branchList = [`${config.branchPrefix}configure`];
+        return branchList;
       }
-      loopCount += 1;
-    } while (baseBranchUpdated);
-    await cleanup.pruneStaleBranches(config, branchList);
+    }
+    logger.info(
+      { seconds: convertHrTime(process.hrtime(branchStartTime)).seconds },
+      'Finished updating branches'
+    );
+  } else {
+    await onboarding.ensurePr(config, branchUpgrades);
+    logger.info('"Configure Renovate" PR needs to be closed first');
+    branchList = [`${config.branchPrefix}configure`];
+  }
+  logger.debug(`branchList=${branchList}`);
+  return branchList;
+}
+
+async function renovateRepository(repoConfig, token) {
+  const config = { ...repoConfig };
+  const { logger } = config;
+  logger.trace({ config }, 'renovateRepository');
+  config.tmpDir = tmp.dirSync({ unsafeCleanup: true });
+  config.errors = [];
+  config.warnings = [];
+  try {
+    const branchList = await renovateRepositoryInner(config, token);
+    if (branchList) {
+      await cleanup.pruneStaleBranches(config, branchList);
+    }
   } catch (err) {
     // Swallow this error so that other repositories can be processed
     if (err.message === 'uninitiated') {