diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb
index efb73358d65db315824f47232712687d25e9247c..7b333d4ce254fd7f39a549c5925d7e95d6b31032 100644
--- a/Library/Homebrew/cmd/install.rb
+++ b/Library/Homebrew/cmd/install.rb
@@ -263,7 +263,7 @@ module Homebrew
       Cleanup.install_formula_clean!(f)
     end
 
-    check_installed_dependents(args: args)
+    Upgrade.check_installed_dependents(args: args)
 
     Homebrew.messages.display_messages(display_times: args.display_times?)
   rescue FormulaUnreadableError, FormulaClassUnavailableError,
diff --git a/Library/Homebrew/cmd/reinstall.rb b/Library/Homebrew/cmd/reinstall.rb
index f18f02df6583dcaced89af14ca0355bec0e86cb6..9d936270ca47764daf0ed5ef1482888d46a78f1a 100644
--- a/Library/Homebrew/cmd/reinstall.rb
+++ b/Library/Homebrew/cmd/reinstall.rb
@@ -72,7 +72,7 @@ module Homebrew
       Cleanup.install_formula_clean!(f)
     end
 
-    check_installed_dependents(args: args)
+    Upgrade.check_installed_dependents(args: args)
 
     Homebrew.messages.display_messages(display_times: args.display_times?)
 
diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb
index 21be88389cc6fc09211871cccf6e39232e35587f..59a228038bb467b7ff4fb5b36b6fe4cc913ab931 100644
--- a/Library/Homebrew/cmd/upgrade.rb
+++ b/Library/Homebrew/cmd/upgrade.rb
@@ -137,9 +137,9 @@ module Homebrew
       puts formulae_upgrades.join("\n")
     end
 
-    upgrade_formulae(formulae_to_install, args: args)
+    Upgrade.upgrade_formulae(formulae_to_install, args: args)
 
-    check_installed_dependents(args: args)
+    Upgrade.check_installed_dependents(args: args)
 
     Homebrew.messages.display_messages(display_times: args.display_times?)
   end
diff --git a/Library/Homebrew/upgrade.rb b/Library/Homebrew/upgrade.rb
index 752f06e585dba344ba4fad684d6faea2a4931388..e1dab76e7abc7ace3ba60c83ead1020690c700a5 100644
--- a/Library/Homebrew/upgrade.rb
+++ b/Library/Homebrew/upgrade.rb
@@ -7,219 +7,99 @@ require "messages"
 require "cleanup"
 
 module Homebrew
-  module_function
-
-  def upgrade_formulae(formulae_to_install, args:)
-    return if formulae_to_install.empty?
-    return if args.dry_run?
-
-    # Sort keg-only before non-keg-only formulae to avoid any needless conflicts
-    # with outdated, non-keg-only versions of formulae being upgraded.
-    formulae_to_install.sort! do |a, b|
-      if !a.keg_only? && b.keg_only?
-        1
-      elsif a.keg_only? && !b.keg_only?
-        -1
-      else
-        0
+  # Helper functions for upgrading formulae.
+  #
+  # @api private
+  module Upgrade
+    module_function
+
+    def upgrade_formulae(formulae_to_install, args:)
+      return if formulae_to_install.empty?
+      return if args.dry_run?
+
+      # Sort keg-only before non-keg-only formulae to avoid any needless conflicts
+      # with outdated, non-keg-only versions of formulae being upgraded.
+      formulae_to_install.sort! do |a, b|
+        if !a.keg_only? && b.keg_only?
+          1
+        elsif a.keg_only? && !b.keg_only?
+          -1
+        else
+          0
+        end
       end
-    end
 
-    formulae_to_install.each do |f|
-      Migrator.migrate_if_needed(f, force: args.force?)
-      begin
-        upgrade_formula(f, args: args)
-        Cleanup.install_formula_clean!(f)
-      rescue UnsatisfiedRequirements => e
-        Homebrew.failed = true
-        onoe "#{f}: #{e}"
+      formulae_to_install.each do |f|
+        Migrator.migrate_if_needed(f, force: args.force?)
+        begin
+          upgrade_formula(f, args: args)
+          Cleanup.install_formula_clean!(f)
+        rescue UnsatisfiedRequirements => e
+          Homebrew.failed = true
+          onoe "#{f}: #{e}"
+        end
       end
     end
-  end
-
-  def upgrade_formula(f, args:)
-    return if args.dry_run?
-
-    if f.opt_prefix.directory?
-      keg = Keg.new(f.opt_prefix.resolved_path)
-      keg_had_linked_opt = true
-      keg_was_linked = keg.linked?
-    end
 
-    formulae_maybe_with_kegs = [f] + f.old_installed_formulae
-    outdated_kegs = formulae_maybe_with_kegs
-                    .map(&:linked_keg)
-                    .select(&:directory?)
-                    .map { |k| Keg.new(k.resolved_path) }
-    linked_kegs = outdated_kegs.select(&:linked?)
-
-    if f.opt_prefix.directory?
-      keg = Keg.new(f.opt_prefix.resolved_path)
-      tab = Tab.for_keg(keg)
-    end
-
-    build_options = BuildOptions.new(Options.create(args.flags_only), f.options)
-    options = build_options.used_options
-    options |= f.build.used_options
-    options &= f.options
-
-    fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?,
-                                 build_from_source_formulae: args.build_from_source_formulae,
-                                 debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?)
-    fi.options = options
-    fi.force = args.force?
-    fi.keep_tmp = args.keep_tmp?
-    fi.build_bottle = args.build_bottle?
-    fi.installed_on_request = args.named.present?
-    fi.link_keg           ||= keg_was_linked if keg_had_linked_opt
-    if tab
-      fi.build_bottle          ||= tab.built_bottle?
-      fi.installed_as_dependency = tab.installed_as_dependency
-      fi.installed_on_request  ||= tab.installed_on_request
-    end
+    def upgrade_formula(f, args:)
+      return if args.dry_run?
 
-    upgrade_version = if f.optlinked?
-      "#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
-    else
-      "-> #{f.pkg_version}"
-    end
-    oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
-
-    fi.prelude
-    fi.fetch
-
-    # first we unlink the currently active keg for this formula otherwise it is
-    # possible for the existing build to interfere with the build we are about to
-    # do! Seriously, it happens!
-    outdated_kegs.each(&:unlink)
-
-    fi.install
-    fi.finish
-  rescue FormulaInstallationAlreadyAttemptedError
-    # We already attempted to upgrade f as part of the dependency tree of
-    # another formula. In that case, don't generate an error, just move on.
-    nil
-  rescue CannotInstallFormulaError => e
-    ofail e
-  rescue BuildError => e
-    e.dump(verbose: args.verbose?)
-    puts
-    Homebrew.failed = true
-  rescue DownloadError => e
-    ofail e
-  ensure
-    # restore previous installation state if build failed
-    begin
-      linked_kegs.each(&:link) unless f.latest_version_installed?
-    rescue
-      nil
-    end
-  end
-
-  def check_installed_dependents(args:)
-    installed_formulae = FormulaInstaller.installed.to_a
-    return if installed_formulae.empty?
-
-    outdated_dependents =
-      installed_formulae.flat_map(&:runtime_installed_formula_dependents)
-                        .select(&:outdated?)
-    return if outdated_dependents.blank?
-
-    outdated_dependents -= installed_formulae if args.dry_run?
-
-    upgradeable_dependents =
-      outdated_dependents.reject(&:pinned?)
-                         .sort { |a, b| depends_on(a, b) }
-    pinned_dependents =
-      outdated_dependents.select(&:pinned?)
-                         .sort { |a, b| depends_on(a, b) }
+      if f.opt_prefix.directory?
+        keg = Keg.new(f.opt_prefix.resolved_path)
+        keg_had_linked_opt = true
+        keg_was_linked = keg.linked?
+      end
 
-    if pinned_dependents.present?
-      plural = "dependent".pluralize(pinned_dependents.count)
-      ohai "Not upgrading #{pinned_dependents.count} pinned #{plural}:"
-      puts(pinned_dependents.map do |f|
-        "#{f.full_specified_name} #{f.pkg_version}"
-      end.join(", "))
-    end
+      formulae_maybe_with_kegs = [f] + f.old_installed_formulae
+      outdated_kegs = formulae_maybe_with_kegs.map(&:linked_keg)
+                                              .select(&:directory?)
+                                              .map { |k| Keg.new(k.resolved_path) }
+      linked_kegs = outdated_kegs.select(&:linked?)
 
-    # Print the upgradable dependents.
-    if upgradeable_dependents.blank?
-      ohai "No outdated dependents to upgrade!" unless args.dry_run?
-    else
-      plural = "dependent".pluralize(upgradeable_dependents.count)
-      verb = args.dry_run? ? "Would upgrade" : "Upgrading"
-      ohai "#{verb} #{upgradeable_dependents.count} #{plural}:"
-      formulae_upgrades = upgradeable_dependents.map do |f|
-        name = f.full_specified_name
-        if f.optlinked?
-          "#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
-        else
-          "#{name} #{f.pkg_version}"
-        end
+      if f.opt_prefix.directory?
+        keg = Keg.new(f.opt_prefix.resolved_path)
+        tab = Tab.for_keg(keg)
       end
-      puts formulae_upgrades.join(", ")
-    end
 
-    upgrade_formulae(upgradeable_dependents, args: args)
-
-    # Assess the dependents tree again now we've upgraded.
-    oh1 "Checking for dependents of upgraded formulae..." unless args.dry_run?
-    broken_dependents = CacheStoreDatabase.use(:linkage) do |db|
-      installed_formulae.flat_map(&:runtime_installed_formula_dependents)
-                        .select do |f|
-        keg = f.opt_or_installed_prefix_keg
-        next unless keg
+      build_options = BuildOptions.new(Options.create(args.flags_only), f.options)
+      options = build_options.used_options
+      options |= f.build.used_options
+      options &= f.options
+
+      fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?,
+                                   build_from_source_formulae: args.build_from_source_formulae,
+                                   debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?)
+      fi.options = options
+      fi.force = args.force?
+      fi.keep_tmp = args.keep_tmp?
+      fi.build_bottle = args.build_bottle?
+      fi.installed_on_request = args.named.present?
+      fi.link_keg           ||= keg_was_linked if keg_had_linked_opt
+      if tab
+        fi.build_bottle          ||= tab.built_bottle?
+        fi.installed_as_dependency = tab.installed_as_dependency
+        fi.installed_on_request  ||= tab.installed_on_request
+      end
 
-        LinkageChecker.new(keg, cache_db: db)
-                      .broken_library_linkage?
-      end.compact
-    end
-    if broken_dependents.blank?
-      if args.dry_run?
-        ohai "No currently broken dependents found!"
-        opoo "If they are broken by the upgrade they will also be upgraded or reinstalled."
+      upgrade_version = if f.optlinked?
+        "#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
       else
-        ohai "No broken dependents found!"
+        "-> #{f.pkg_version}"
       end
-      return
-    end
+      oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
 
-    reinstallable_broken_dependents =
-      broken_dependents.reject(&:outdated?)
-                       .reject(&:pinned?)
-                       .sort { |a, b| depends_on(a, b) }
-    outdated_pinned_broken_dependents =
-      broken_dependents.select(&:outdated?)
-                       .select(&:pinned?)
-                       .sort { |a, b| depends_on(a, b) }
-
-    # Print the pinned dependents.
-    if outdated_pinned_broken_dependents.present?
-      count = outdated_pinned_broken_dependents.count
-      plural = "dependent".pluralize(outdated_pinned_broken_dependents.count)
-      onoe "Not reinstalling #{count} broken and outdated, but pinned #{plural}:"
-      $stderr.puts(outdated_pinned_broken_dependents.map do |f|
-        "#{f.full_specified_name} #{f.pkg_version}"
-      end.join(", "))
-    end
-
-    # Print the broken dependents.
-    if reinstallable_broken_dependents.blank?
-      ohai "No broken dependents to reinstall!"
-    else
-      count = reinstallable_broken_dependents.count
-      plural = "dependent".pluralize(reinstallable_broken_dependents.count)
-      ohai "Reinstalling #{count} broken #{plural} from source:"
-      puts reinstallable_broken_dependents.map(&:full_specified_name)
-                                          .join(", ")
-    end
+      fi.prelude
+      fi.fetch
 
-    return if args.dry_run?
+      # first we unlink the currently active keg for this formula otherwise it is
+      # possible for the existing build to interfere with the build we are about to
+      # do! Seriously, it happens!
+      outdated_kegs.each(&:unlink)
 
-    reinstallable_broken_dependents.each do |f|
-      reinstall_formula(f, build_from_source: true, args: args)
+      fi.install
+      fi.finish
     rescue FormulaInstallationAlreadyAttemptedError
-      # We already attempted to reinstall f as part of the dependency tree of
+      # We already attempted to upgrade f as part of the dependency tree of
       # another formula. In that case, don't generate an error, just move on.
       nil
     rescue CannotInstallFormulaError => e
@@ -230,17 +110,142 @@ module Homebrew
       Homebrew.failed = true
     rescue DownloadError => e
       ofail e
+    ensure
+      # restore previous installation state if build failed
+      begin
+        linked_kegs.each(&:link) unless f.latest_version_installed?
+      rescue
+        nil
+      end
     end
-  end
+    private_class_method :upgrade_formula
+
+    def check_installed_dependents(args:)
+      installed_formulae = FormulaInstaller.installed.to_a
+      return if installed_formulae.empty?
+
+      outdated_dependents =
+        installed_formulae.flat_map(&:runtime_installed_formula_dependents)
+                          .select(&:outdated?)
+      return if outdated_dependents.blank?
+
+      outdated_dependents -= installed_formulae if args.dry_run?
+
+      upgradeable_dependents =
+        outdated_dependents.reject(&:pinned?)
+                           .sort { |a, b| depends_on(a, b) }
+      pinned_dependents =
+        outdated_dependents.select(&:pinned?)
+                           .sort { |a, b| depends_on(a, b) }
+
+      if pinned_dependents.present?
+        plural = "dependent".pluralize(pinned_dependents.count)
+        ohai "Not upgrading #{pinned_dependents.count} pinned #{plural}:"
+        puts(pinned_dependents.map do |f|
+          "#{f.full_specified_name} #{f.pkg_version}"
+        end.join(", "))
+      end
 
-  # @private
-  def depends_on(a, b)
-    if a.opt_or_installed_prefix_keg
-       &.runtime_dependencies
-       &.any? { |d| d["full_name"] == b.full_name }
-      1
-    else
-      a <=> b
+      # Print the upgradable dependents.
+      if upgradeable_dependents.blank?
+        ohai "No outdated dependents to upgrade!" unless args.dry_run?
+      else
+        plural = "dependent".pluralize(upgradeable_dependents.count)
+        verb = args.dry_run? ? "Would upgrade" : "Upgrading"
+        ohai "#{verb} #{upgradeable_dependents.count} #{plural}:"
+        formulae_upgrades = upgradeable_dependents.map do |f|
+          name = f.full_specified_name
+          if f.optlinked?
+            "#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
+          else
+            "#{name} #{f.pkg_version}"
+          end
+        end
+        puts formulae_upgrades.join(", ")
+      end
+
+      upgrade_formulae(upgradeable_dependents, args: args)
+
+      # Assess the dependents tree again now we've upgraded.
+      oh1 "Checking for dependents of upgraded formulae..." unless args.dry_run?
+      broken_dependents = CacheStoreDatabase.use(:linkage) do |db|
+        installed_formulae.flat_map(&:runtime_installed_formula_dependents)
+                          .select do |f|
+          keg = f.opt_or_installed_prefix_keg
+          next unless keg
+
+          LinkageChecker.new(keg, cache_db: db)
+                        .broken_library_linkage?
+        end.compact
+      end
+      if broken_dependents.blank?
+        if args.dry_run?
+          ohai "No currently broken dependents found!"
+          opoo "If they are broken by the upgrade they will also be upgraded or reinstalled."
+        else
+          ohai "No broken dependents found!"
+        end
+        return
+      end
+
+      reinstallable_broken_dependents =
+        broken_dependents.reject(&:outdated?)
+                         .reject(&:pinned?)
+                         .sort { |a, b| depends_on(a, b) }
+      outdated_pinned_broken_dependents =
+        broken_dependents.select(&:outdated?)
+                         .select(&:pinned?)
+                         .sort { |a, b| depends_on(a, b) }
+
+      # Print the pinned dependents.
+      if outdated_pinned_broken_dependents.present?
+        count = outdated_pinned_broken_dependents.count
+        plural = "dependent".pluralize(outdated_pinned_broken_dependents.count)
+        onoe "Not reinstalling #{count} broken and outdated, but pinned #{plural}:"
+        $stderr.puts(outdated_pinned_broken_dependents.map do |f|
+          "#{f.full_specified_name} #{f.pkg_version}"
+        end.join(", "))
+      end
+
+      # Print the broken dependents.
+      if reinstallable_broken_dependents.blank?
+        ohai "No broken dependents to reinstall!"
+      else
+        count = reinstallable_broken_dependents.count
+        plural = "dependent".pluralize(reinstallable_broken_dependents.count)
+        ohai "Reinstalling #{count} broken #{plural} from source:"
+        puts reinstallable_broken_dependents.map(&:full_specified_name)
+                                            .join(", ")
+      end
+
+      return if args.dry_run?
+
+      reinstallable_broken_dependents.each do |f|
+        reinstall_formula(f, build_from_source: true, args: args)
+      rescue FormulaInstallationAlreadyAttemptedError
+        # We already attempted to reinstall f as part of the dependency tree of
+        # another formula. In that case, don't generate an error, just move on.
+        nil
+      rescue CannotInstallFormulaError => e
+        ofail e
+      rescue BuildError => e
+        e.dump(verbose: args.verbose?)
+        puts
+        Homebrew.failed = true
+      rescue DownloadError => e
+        ofail e
+      end
+    end
+
+    def depends_on(a, b)
+      if a.opt_or_installed_prefix_keg
+         &.runtime_dependencies
+         &.any? { |d| d["full_name"] == b.full_name }
+        1
+      else
+        a <=> b
+      end
     end
+    private_class_method :depends_on
   end
 end