diff --git a/cli/catalogue/catalogue.go b/cli/catalogue/catalogue.go
index e71b9863d1..8d32ded187 100644
--- a/cli/catalogue/catalogue.go
+++ b/cli/catalogue/catalogue.go
@@ -66,6 +66,7 @@ var catalogueGenerateCommand = &cli.Command{
 		internal.CommitFlag,
 		internal.CommitMessageFlag,
 		internal.DryFlag,
+		internal.SkipUpdatesFlag,
 	},
 	Description: `
 This command generates a new copy of the recipe catalogue which can be found on:
@@ -112,51 +113,11 @@ A new catalogue copy can be published to the recipes repository by passing the
 			barLength = len(repos)
 		}
 
-		cloneLimiter := limit.New(10)
-		retrieveBar := formatter.CreateProgressbar(len(repos), "retrieving recipes from recipes.coopcloud.tech...")
-		ch := make(chan string, barLength)
-		for _, repoMeta := range repos {
-			go func(rm catalogue.RepoMeta) {
-				cloneLimiter.Begin()
-				defer cloneLimiter.End()
-
-				if recipeName != "" && recipeName != rm.Name {
-					ch <- rm.Name
-					retrieveBar.Add(1)
-					return
-				}
-				if _, exists := CatalogueSkipList[rm.Name]; exists {
-					ch <- rm.Name
-					retrieveBar.Add(1)
-					return
-				}
-
-				recipeDir := path.Join(config.RECIPES_DIR, rm.Name)
-
-				if err := gitPkg.Clone(recipeDir, rm.SSHURL); err != nil {
-					logrus.Fatal(err)
-				}
-
-				isClean, err := gitPkg.IsClean(rm.Name)
-				if err != nil {
-					logrus.Fatal(err)
-				}
-
-				if !isClean {
-					logrus.Fatalf("%s has locally unstaged changes", rm.Name)
-				}
-
-				if err := recipe.EnsureUpToDate(rm.Name); err != nil {
-					logrus.Fatal(err)
-				}
-
-				ch <- rm.Name
-				retrieveBar.Add(1)
-			}(repoMeta)
-		}
-
-		for range repos {
-			<-ch // wait for everything
+		if !internal.SkipUpdates {
+			logrus.Warnf("ensuring %v recipe(s) are up-to-date", barLength)
+			if err := updateRepositories(repos, recipeName); err != nil {
+				logrus.Fatal(err)
+			}
 		}
 
 		catl := make(catalogue.RecipeCatalogue)
@@ -265,3 +226,62 @@ var CatalogueCommand = &cli.Command{
 		catalogueGenerateCommand,
 	},
 }
+
+func updateRepositories(repos catalogue.RepoCatalogue, recipeName string) error {
+	var barLength int
+	if recipeName != "" {
+		barLength = 1
+	} else {
+		barLength = len(repos)
+	}
+
+	cloneLimiter := limit.New(10)
+
+	retrieveBar := formatter.CreateProgressbar(barLength, "retrieving recipes from recipes.coopcloud.tech...")
+	ch := make(chan string, barLength)
+	for _, repoMeta := range repos {
+		go func(rm catalogue.RepoMeta) {
+			cloneLimiter.Begin()
+			defer cloneLimiter.End()
+
+			if recipeName != "" && recipeName != rm.Name {
+				ch <- rm.Name
+				retrieveBar.Add(1)
+				return
+			}
+			if _, exists := CatalogueSkipList[rm.Name]; exists {
+				ch <- rm.Name
+				retrieveBar.Add(1)
+				return
+			}
+
+			recipeDir := path.Join(config.RECIPES_DIR, rm.Name)
+
+			if err := gitPkg.Clone(recipeDir, rm.SSHURL); err != nil {
+				logrus.Fatal(err)
+			}
+
+			isClean, err := gitPkg.IsClean(rm.Name)
+			if err != nil {
+				logrus.Fatal(err)
+			}
+
+			if !isClean {
+				logrus.Fatalf("%s has locally unstaged changes", rm.Name)
+			}
+
+			if err := catalogue.EnsureUpToDate(rm.Name); err != nil {
+				logrus.Fatal(err)
+			}
+
+			ch <- rm.Name
+			retrieveBar.Add(1)
+		}(repoMeta)
+	}
+
+	for range repos {
+		<-ch // wait for everything
+	}
+
+	return nil
+}
diff --git a/cli/internal/common.go b/cli/internal/common.go
index 00b50184e0..8450a92c85 100644
--- a/cli/internal/common.go
+++ b/cli/internal/common.go
@@ -446,6 +446,15 @@ var OnlyErrorFlag = &cli.BoolFlag{
 	Destination: &OnlyErrors,
 }
 
+var SkipUpdates bool
+var SkipUpdatesFlag = &cli.BoolFlag{
+	Name:        "skip-updates",
+	Aliases:     []string{"s"},
+	Value:       false,
+	Usage:       "Skip updating git repositories",
+	Destination: &SkipUpdates,
+}
+
 // SSHFailMsg is a hopefully helpful SSH failure message
 var SSHFailMsg = `
 Woops, Abra is unable to connect to connect to %s.