diff --git a/lib/gitlab/build/check.rb b/lib/gitlab/build/check.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_bGliL2dpdGxhYi9idWlsZC9jaGVjay5yYg==..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_bGliL2dpdGxhYi9idWlsZC9jaGVjay5yYg== 100644
--- a/lib/gitlab/build/check.rb
+++ b/lib/gitlab/build/check.rb
@@ -1,4 +1,5 @@
 require_relative "info.rb"
+require_relative "info/git"
 require_relative "../util.rb"
 
 module Build
@@ -46,7 +47,7 @@
       end
 
       def is_auto_deploy_tag?
-        AUTO_DEPLOY_TAG_REGEX.match?(Build::Info.current_git_tag)
+        AUTO_DEPLOY_TAG_REGEX.match?(Build::Info::Git.tag_name)
       end
 
       def is_auto_deploy_branch?
@@ -59,7 +60,7 @@
       end
 
       def is_rc_tag?
-        Build::Info.current_git_tag.include?("+rc")
+        Build::Info::Git.tag_name&.include?("+rc")
       end
 
       def ci_commit_tag?
@@ -67,7 +68,7 @@
       end
 
       def is_latest_stable_tag?
-        match_tag?(Info.latest_stable_tag)
+        match_tag?(Info::Git.latest_stable_tag)
       end
 
       def is_latest_tag?
@@ -71,7 +72,7 @@
       end
 
       def is_latest_tag?
-        match_tag?(Info.latest_tag)
+        match_tag?(Info::Git.latest_tag)
       end
 
       def is_nightly?
@@ -91,7 +92,7 @@
       end
 
       def on_stable_branch?
-        Build::Info.branch_name&.match?(/^\d+-\d+-stable$/)
+        Build::Info::Git.branch_name&.match?(/^\d+-\d+-stable$/)
       end
 
       def on_regular_branch?
@@ -95,7 +96,7 @@
       end
 
       def on_regular_branch?
-        Build::Info.branch_name && !on_stable_branch?
+        Build::Info::Git.branch_name && !on_stable_branch?
       end
     end
   end
diff --git a/lib/gitlab/build/facts.rb b/lib/gitlab/build/facts.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_bGliL2dpdGxhYi9idWlsZC9mYWN0cy5yYg==..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_bGliL2dpdGxhYi9idWlsZC9mYWN0cy5yYg== 100644
--- a/lib/gitlab/build/facts.rb
+++ b/lib/gitlab/build/facts.rb
@@ -1,3 +1,5 @@
+require_relative 'info/git'
+
 module Build
   class Facts
     class << self
@@ -12,7 +14,7 @@
           :latest_stable_tag,
           :latest_tag
         ].each do |fact|
-          content = Build::Info.send(fact) # rubocop:disable GitlabSecurity/PublicSend
+          content = Build::Info::Git.send(fact) # rubocop:disable GitlabSecurity/PublicSend
           File.write("build_facts/#{fact}", content) unless content.nil?
         end
       end
@@ -74,7 +76,7 @@
           QA_IMAGE=#{Build::Info.qa_image}
           QA_TESTS=#{Gitlab::Util.get_env('QA_TESTS')}
           ALLURE_JOB_NAME=#{allure_job_name}-#{Build::Info.edition}
-          GITLAB_SEMVER_VERSION=#{Build::Info.latest_stable_tag.tr('+', '-')}
+          GITLAB_SEMVER_VERSION=#{Build::Info::Git.latest_stable_tag.tr('+', '-')}
           RAT_REFERENCE_ARCHITECTURE=#{Gitlab::Util.get_env('RAT_REFERENCE_ARCHITECTURE') || 'omnibus-gitlab-mrs'}
           RAT_FIPS_REFERENCE_ARCHITECTURE=#{Gitlab::Util.get_env('RAT_FIPS_REFERENCE_ARCHITECTURE') || 'omnibus-gitlab-mrs-fips-ubuntu'}
           RAT_PACKAGE_URL=#{Gitlab::Util.get_env('PACKAGE_URL') || Build::Info::CI.triggered_package_download_url(fips: false)}
diff --git a/lib/gitlab/build/info.rb b/lib/gitlab/build/info.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_bGliL2dpdGxhYi9idWlsZC9pbmZvLnJi..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_bGliL2dpdGxhYi9idWlsZC9pbmZvLnJi 100644
--- a/lib/gitlab/build/info.rb
+++ b/lib/gitlab/build/info.rb
@@ -1,5 +1,6 @@
 require 'omnibus'
 
+require_relative 'info/git'
 require_relative '../build_iteration'
 require_relative "../util.rb"
 require_relative './info/ci'
@@ -16,13 +17,6 @@
     PACKAGE_GLOB = "pkg/**/*.{deb,rpm}".freeze
 
     class << self
-      def fetch_fact_from_file(fact)
-        return unless File.exist?("build_facts/#{fact}")
-
-        content = File.read("build_facts/#{fact}").strip
-        return content unless content.empty?
-      end
-
       def package
         return "gitlab-fips" if Check.use_system_ssl?
         return "gitlab-ee" if Check.is_ee?
@@ -46,5 +40,5 @@
           Omnibus.load_configuration('omnibus.rb')
           Omnibus::BuildVersion.semver
         else
-          latest_git_tag = Info.latest_tag.strip
+          latest_git_tag = Info::Git.latest_tag.strip
           latest_version = latest_git_tag && !latest_git_tag.empty? ? latest_git_tag[0, latest_git_tag.match("[+]").begin(0)] : '0.0.1'
@@ -50,8 +44,8 @@
           latest_version = latest_git_tag && !latest_git_tag.empty? ? latest_git_tag[0, latest_git_tag.match("[+]").begin(0)] : '0.0.1'
-          commit_sha = Build::Info.commit_sha
+          commit_sha = Build::Info::Git.commit_sha
           ver_tag = "#{latest_version}+" + (Build::Check.is_nightly? ? "rnightly" : "rfbranch")
           ver_tag += ".fips" if Build::Check.use_system_ssl?
           [ver_tag, Gitlab::Util.get_env('CI_PIPELINE_ID'), commit_sha].compact.join('.')
         end
       end
 
@@ -52,20 +46,11 @@
           ver_tag = "#{latest_version}+" + (Build::Check.is_nightly? ? "rnightly" : "rfbranch")
           ver_tag += ".fips" if Build::Check.use_system_ssl?
           [ver_tag, Gitlab::Util.get_env('CI_PIPELINE_ID'), commit_sha].compact.join('.')
         end
       end
 
-      def branch_name
-        Gitlab::Util.get_env('CI_COMMIT_BRANCH')
-      end
-
-      def commit_sha
-        commit_sha_raw = Gitlab::Util.get_env('CI_COMMIT_SHA') || `git rev-parse HEAD`.strip
-        commit_sha_raw[0, 8]
-      end
-
       def release_version
         semver = Info.semver_version
         "#{semver}-#{Gitlab::BuildIteration.new.build_iteration}"
       end
 
@@ -67,65 +52,8 @@
       def release_version
         semver = Info.semver_version
         "#{semver}-#{Gitlab::BuildIteration.new.build_iteration}"
       end
 
-      def sorted_tags_for_edition
-        `git -c versionsort.prereleaseSuffix=rc tag -l '#{Info.tag_match_pattern}' --sort=-v:refname`.split("\n")
-      end
-
-      # TODO, merge latest_tag with latest_stable_tag
-      # TODO, add tests, needs a repo clone
-      def latest_tag
-        unless (fact_from_file = fetch_fact_from_file(__method__)).nil?
-          return fact_from_file
-        end
-
-        tags = sorted_tags_for_edition
-
-        return if tags.empty?
-
-        version = branch_name.delete_suffix('-stable').tr('-', '.') if Build::Check.on_stable_branch?
-        output = tags.find { |t| t.start_with?(version) } if version
-
-        # If no tags corresponding to the stable branch version was found, we
-        # fall back to the latest available tag
-        output || tags.first
-      end
-
-      def latest_stable_tag(level: 1)
-        unless (fact_from_file = fetch_fact_from_file(__method__)).nil?
-          return fact_from_file
-        end
-
-        # Exclude RC tags so that we only have stable tags.
-        stable_tags = sorted_tags_for_edition.reject { |t| t.include?('rc') }
-
-        return if stable_tags.empty?
-
-        version = branch_name.delete_suffix('-stable').tr('-', '.') if Build::Check.on_stable_branch?
-
-        results = stable_tags.select { |t| t.start_with?(version) } if version
-
-        # If no tags corresponding to the stable branch version was found, we
-        # fall back to the latest available stable tag
-        output = if results.nil? || results.empty?
-                   stable_tags
-                 else
-                   results
-                 end
-
-        # Level decides tag at which position you want. Level one gives you
-        # latest stable tag, two gives you the one just before it and so on.
-        # Since arrays start from 0, we subtract 1 from the specified level to
-        # get the index. If the specified level is more than the number of
-        # tags, we return the last tag.
-        if level >= output.length
-          output.last
-        else
-          output[level - 1]
-        end
-      end
-
       def docker_tag
         Gitlab::Util.get_env('IMAGE_TAG') || Info.release_version.tr('+', '-')
       end
@@ -162,12 +90,6 @@
         Gitlab::Version.new('gitlab-rails').print(prepend_version)
       end
 
-      def previous_version
-        # Get the second latest git tag
-        previous_tag = Info.latest_stable_tag(level: 2)
-        previous_tag.tr("+", "-")
-      end
-
       def gitlab_rails_project_path
         if Gitlab::Util.get_env('CI_SERVER_HOST') == 'dev.gitlab.org'
           package == "gitlab-ee" ? 'gitlab/gitlab-ee' : 'gitlab/gitlabhq'
@@ -243,12 +165,6 @@
         "https://#{Info.release_bucket}.#{Info.release_bucket_s3_endpoint}/#{folder}/#{Info.package}_#{package_filename_url_safe}_#{arch}.deb"
       end
 
-      def tag_match_pattern
-        return '*[+.]ee.*' if Check.is_ee?
-
-        '*[+.]ce.*'
-      end
-
       def release_file_contents
         repo = Gitlab::Util.get_env('PACKAGECLOUD_REPO') # Target repository
 
@@ -269,10 +185,6 @@
         contents.join
       end
 
-      def current_git_tag
-        `git describe --exact-match 2>/dev/null`.chomp
-      end
-
       def image_reference
         "#{Build::GitlabImage.gitlab_registry_image_address}:#{Info.docker_tag}"
       end
diff --git a/lib/gitlab/build/info/git.rb b/lib/gitlab/build/info/git.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_bGliL2dpdGxhYi9idWlsZC9pbmZvL2dpdC5yYg==
--- /dev/null
+++ b/lib/gitlab/build/info/git.rb
@@ -0,0 +1,104 @@
+require_relative '../../util'
+require_relative '../check'
+require_relative 'ci'
+
+module Build
+  class Info
+    class Git
+      class << self
+        def branch_name
+          # If on CI, branch name from `CI_COMMIT_BRANCH` wins
+          result = Build::Info::CI.branch_name
+
+          return result if result
+
+          # If not on CI, attempt to detect branch name
+          head_reference = Gitlab::Util.shellout_stdout('git rev-parse --abbrev-ref HEAD')
+
+          # On tags, the shell command will return `HEAD`. If that is not the
+          # case, we are on a branch and can return the output we received.
+          return head_reference unless head_reference == "HEAD"
+        end
+
+        def tag_name
+          Build::Info::CI.tag_name || Gitlab::Util.shellout_stdout('git describe --tags --exact-match')
+        rescue Gitlab::Util::ShellOutExecutionError => e
+          return nil if /fatal: no tag exactly matches/.match?(e.stderr)
+
+          raise "#{e.message}\nSTDOUT: #{e.stdout}\nSTDERR: #{e.stderr}"
+        end
+
+        def commit_sha
+          commit_sha_raw = Gitlab::Util.get_env('CI_COMMIT_SHA') || Gitlab::Util.shellout_stdout('git rev-parse HEAD')
+
+          commit_sha_raw[0, 8]
+        end
+
+        # TODO, merge latest_tag with latest_stable_tag
+        # TODO, add tests, needs a repo clone
+        def latest_tag
+          unless (fact_from_file = Gitlab::Util.fetch_fact_from_file(__method__)).nil?
+            return fact_from_file
+          end
+
+          tags = sorted_tags_for_edition
+
+          return if tags.empty?
+
+          version = branch_name.delete_suffix('-stable').tr('-', '.') if Build::Check.on_stable_branch?
+          output = tags.find { |t| t.start_with?(version) } if version
+
+          # If no tags corresponding to the stable branch version was found, we
+          # fall back to the latest available tag
+          output || tags.first
+        end
+
+        def latest_stable_tag(level: 1)
+          unless (fact_from_file = Gitlab::Util.fetch_fact_from_file(__method__)).nil?
+            return fact_from_file
+          end
+
+          # Exclude RC tags so that we only have stable tags.
+          stable_tags = sorted_tags_for_edition.reject { |t| t.include?('rc') }
+
+          return if stable_tags.empty?
+
+          version = branch_name.delete_suffix('-stable').tr('-', '.') if Build::Check.on_stable_branch?
+
+          results = stable_tags.select { |t| t.start_with?(version) } if version
+
+          # If no tags corresponding to the stable branch version was found, we
+          # fall back to the latest available stable tag
+          output = if results.nil? || results.empty?
+                     stable_tags
+                   else
+                     results
+                   end
+
+          # Level decides tag at which position you want. Level one gives you
+          # latest stable tag, two gives you the one just before it and so on.
+          # Since arrays start from 0, we subtract 1 from the specified level to
+          # get the index. If the specified level is more than the number of
+          # tags, we return the last tag.
+          if level >= output.length
+            output.last
+          else
+            output[level - 1]
+          end
+        end
+
+        private
+
+        def sorted_tags_for_edition
+          Gitlab::Util.shellout_stdout("git -c versionsort.prereleaseSuffix=rc tag -l '#{tag_match_pattern}' --sort=-v:refname")&.split("\n")
+        end
+
+        def tag_match_pattern
+          return '*[+.]ee.*' if Build::Check.is_ee?
+
+          '*[+.]ce.*'
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/tasks/build.rake b/lib/gitlab/tasks/build.rake
index f26af321538def1d4a72605a5b54310aeac8f5ff_bGliL2dpdGxhYi90YXNrcy9idWlsZC5yYWtl..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_bGliL2dpdGxhYi90YXNrcy9idWlsZC5yYWtl 100644
--- a/lib/gitlab/tasks/build.rake
+++ b/lib/gitlab/tasks/build.rake
@@ -2,6 +2,7 @@
 require_relative "../build.rb"
 require_relative "../build/check.rb"
 require_relative "../build/info.rb"
+require_relative "../build/info/git"
 require_relative '../build/facts'
 require_relative "../gcloud_helper.rb"
 require_relative "../ohai_helper.rb"
@@ -27,8 +28,8 @@
   namespace :docker do
     desc 'Show latest available tag. Includes unstable releases.'
     task :latest_tag do
-      puts Build::Info.latest_tag
+      puts Build::Info::Git.latest_tag
     end
 
     desc 'Show latest stable tag.'
     task :latest_stable_tag do
@@ -31,8 +32,8 @@
     end
 
     desc 'Show latest stable tag.'
     task :latest_stable_tag do
-      puts Build::Info.latest_stable_tag
+      puts Build::Info::Git.latest_stable_tag
     end
   end
 
diff --git a/lib/gitlab/tasks/qa.rake b/lib/gitlab/tasks/qa.rake
index f26af321538def1d4a72605a5b54310aeac8f5ff_bGliL2dpdGxhYi90YXNrcy9xYS5yYWtl..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_bGliL2dpdGxhYi90YXNrcy9xYS5yYWtl 100644
--- a/lib/gitlab/tasks/qa.rake
+++ b/lib/gitlab/tasks/qa.rake
@@ -3,6 +3,7 @@
 require_relative '../build/qa'
 require_relative '../build/check'
 require_relative '../build/info'
+require_relative "../build/info/git"
 require_relative '../build/gitlab_image'
 require_relative '../build/qa_image'
 require_relative '../build/rat'
@@ -64,7 +65,7 @@
     task :staging do
       Gitlab::Util.section('qa:push:staging') do
         Build::QAImage.tag_and_push_to_gitlab_registry(Build::Info.gitlab_version)
-        Build::QAImage.tag_and_push_to_gitlab_registry(Build::Info.commit_sha)
+        Build::QAImage.tag_and_push_to_gitlab_registry(Build::Info::Git.commit_sha)
       end
     end
 
diff --git a/lib/gitlab/util.rb b/lib/gitlab/util.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_bGliL2dpdGxhYi91dGlsLnJi..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_bGliL2dpdGxhYi91dGlsLnJi 100644
--- a/lib/gitlab/util.rb
+++ b/lib/gitlab/util.rb
@@ -1,5 +1,17 @@
 module Gitlab
   class Util
+    class ShellOutExecutionError < StandardError
+      attr_accessor :stdout, :stderr
+
+      def initialize(command, exitcode, stdout, stderr)
+        @stdout = stdout
+        @stderr = stderr
+        msg = "Execution of command `#{command}` failed with exit code #{exitcode}."
+
+        super(msg)
+      end
+    end
+
     class << self
       def get_env(key)
         value = ENV[key]&.strip
@@ -27,6 +39,24 @@
 
         $stdout.puts "section_end:#{Time.now.to_i}:#{name}\r\e[0K"
       end
+
+      def shellout_stdout(cmd)
+        output = Mixlib::ShellOut.new(cmd)
+        output.run_command
+
+        raise ShellOutExecutionError.new(cmd, output.status.exitstatus, output.stdout, output.stderr) unless output.status.exitstatus.zero?
+
+        stdout = output.stdout&.chomp&.strip
+
+        stdout unless stdout&.empty?
+      end
+
+      def fetch_fact_from_file(fact)
+        return unless File.exist?("build_facts/#{fact}")
+
+        content = File.read("build_facts/#{fact}").strip
+        return content unless content.empty?
+      end
     end
   end
 end
diff --git a/spec/lib/gitlab/build/check_spec.rb b/spec/lib/gitlab/build/check_spec.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2NoZWNrX3NwZWMucmI=..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2NoZWNrX3NwZWMucmI= 100644
--- a/spec/lib/gitlab/build/check_spec.rb
+++ b/spec/lib/gitlab/build/check_spec.rb
@@ -92,9 +92,9 @@
       it 'returns true if it is an rc release' do
         # This will be the case if latest_tag is eg. 9.3.0+rc6.ce.0
         # or 9.3.0+ce.0
-        allow(Build::Info).to receive(:latest_tag).and_return('9.3.0+rc6.ce.0') # This line only is only an example, stubbing is not needed.
+        allow(Build::Info::Git).to receive(:latest_tag).and_return('9.3.0+rc6.ce.0') # This line only is only an example, stubbing is not needed.
         allow(described_class).to receive(:match_tag?).and_return(true)
         expect(described_class.is_latest_tag?).to be_truthy
       end
 
       it 'returns true if it is not an rc release' do
@@ -96,9 +96,9 @@
         allow(described_class).to receive(:match_tag?).and_return(true)
         expect(described_class.is_latest_tag?).to be_truthy
       end
 
       it 'returns true if it is not an rc release' do
-        allow(Build::Info).to receive(:latest_tag).and_return('9.3.0+ce.0') # This line only is only an example, stubbing is not needed.
+        allow(Build::Info::Git).to receive(:latest_tag).and_return('9.3.0+ce.0') # This line only is only an example, stubbing is not needed.
         allow(described_class).to receive(:match_tag?).and_return(false)
         expect(described_class.is_latest_tag?).to be_falsey
       end
@@ -108,9 +108,9 @@
       it 'returns true if it is a stable release' do
         # This will be the case if latest_tag is eg. 9.3.0+ce.0
         # It will not be the case if the tag is 9.3.0+rc6.ce.0
-        allow(Build::Info).to receive(:latest_stable_tag).and_return('9.3.0+ce.0') # This line only is only an example, stubbing is not needed.
+        allow(Build::Info::Git).to receive(:latest_stable_tag).and_return('9.3.0+ce.0') # This line only is only an example, stubbing is not needed.
         allow(described_class).to receive(:match_tag?).and_return(true)
         expect(described_class.is_latest_stable_tag?).to be_truthy
       end
 
       it 'returns true if it is not a stable release' do
@@ -112,9 +112,9 @@
         allow(described_class).to receive(:match_tag?).and_return(true)
         expect(described_class.is_latest_stable_tag?).to be_truthy
       end
 
       it 'returns true if it is not a stable release' do
-        allow(Build::Info).to receive(:latest_stable_tag).and_return('9.3.0+rc6.ce.0') # This line only is only an example, stubbing is not needed.
+        allow(Build::Info::Git).to receive(:latest_stable_tag).and_return('9.3.0+rc6.ce.0') # This line only is only an example, stubbing is not needed.
         allow(described_class).to receive(:match_tag?).and_return(false)
         expect(described_class.is_latest_stable_tag?).to be_falsey
       end
@@ -136,8 +136,8 @@
   describe 'is_rc_tag?' do
     it 'returns true if it looks like an rc tag' do
       # It will be the case if the tag is 9.3.0+rc6.ce.0
-      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+rc6.ce.0')
+      allow(Build::Info::Git).to receive(:tag_name).and_return('9.3.0+rc6.ce.0')
       expect(described_class.is_rc_tag?).to be_truthy
     end
     it 'returns false if it does not look like an rc tag' do
       # This not be the case if tag is eg. 9.3.0+ce.0
@@ -140,8 +140,8 @@
       expect(described_class.is_rc_tag?).to be_truthy
     end
     it 'returns false if it does not look like an rc tag' do
       # This not be the case if tag is eg. 9.3.0+ce.0
-      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+ce.0')
+      allow(Build::Info::Git).to receive(:tag_name).and_return('9.3.0+ce.0')
       expect(described_class.is_rc_tag?).to be_falsey
     end
   end
@@ -149,7 +149,7 @@
   describe 'is_auto_deploy?' do
     it 'returns true if it looks like an auto-deploy tag' do
       # This is the case if the tag is 11.10.12345+5159f2949cb.59c9fa631
-      allow(Build::Info).to receive(:current_git_tag).and_return('11.10.12345+5159f2949cb.59c9fa631')
+      allow(Build::Info::Git).to receive(:tag_name).and_return('11.10.12345+5159f2949cb.59c9fa631')
       expect(described_class.is_auto_deploy?).to be_truthy
     end
 
@@ -157,7 +157,7 @@
       # This not be the case if ag is eg. 9.3.0+ce.0
       allow(Gitlab::Util).to receive(:get_env).with('CI_COMMIT_REF_NAME').and_return('a-random-branch')
 
-      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+ce.0')
+      allow(Build::Info::Git).to receive(:tag_name).and_return('9.3.0+ce.0')
       expect(described_class.is_auto_deploy?).to be_falsey
     end
   end
@@ -172,7 +172,7 @@
   describe 'on_stable_branch?' do
     context 'when on a stable branch' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '14-10-stable')
+        stub_branch('14-10-stable')
       end
 
       it 'returns true' do
@@ -182,7 +182,7 @@
 
     context 'when on a regular branch' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+        stub_branch('my-feature-branch')
       end
 
       it 'returns false' do
@@ -192,7 +192,7 @@
 
     context 'when using a a tag' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '')
+        stub_tag('1.2.3')
       end
 
       it 'returns false' do
@@ -204,7 +204,7 @@
   describe 'on_regular_tag?' do
     context 'when on a regular branch' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+        stub_branch('my-feature-branch')
         allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(false)
       end
 
@@ -215,7 +215,7 @@
 
     context 'when on a stable branch' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '15-6-stable')
+        stub_branch('15-6-stable')
         allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(false)
       end
 
@@ -226,8 +226,7 @@
 
     context 'when on RC tag' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '')
-        stub_env_var('CI_COMMIT_TAG', '15.8.0+rc42.ce.0')
+        stub_tag('15.8.0+rc42.ce.0')
         allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
       end
 
@@ -238,8 +237,7 @@
 
     context 'when on stable tag' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '')
-        stub_env_var('CI_COMMIT_TAG', '15.8.0+ce.0')
+        stub_tag('15.8.0+ce.0')
         allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
       end
 
@@ -250,9 +248,7 @@
 
     context 'when on auto-deploy tag' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '')
-        stub_env_var('CI_COMMIT_TAG', '15.8.202301050320+b251a9da107.0e5d6807f3a')
-        allow(Build::Info).to receive(:current_git_tag).and_return('15.8.202301050320+b251a9da107.0e5d6807f3a')
+        stub_tag('15.8.202301050320+b251a9da107.0e5d6807f3a')
         allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
       end
 
@@ -265,7 +261,6 @@
   describe 'on_regular_branch?' do
     context 'when on a regular branch' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
-        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(false)
+        stub_branch('my-feature-branch')
       end
 
@@ -270,9 +265,9 @@
       end
 
-      it 'returns false' do
+      it 'returns true' do
         expect(described_class.on_regular_branch?).to be_truthy
       end
     end
 
     context 'when on a stable branch' do
       before do
@@ -273,11 +268,10 @@
         expect(described_class.on_regular_branch?).to be_truthy
       end
     end
 
     context 'when on a stable branch' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '15-6-stable')
-        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(false)
+        stub_branch('15-6-stable')
       end
 
       it 'returns false' do
@@ -287,9 +281,7 @@
 
     context 'when on RC tag' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '')
-        stub_env_var('CI_COMMIT_TAG', '15.8.0+rc42.ce.0')
-        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
+        stub_tag('15.8.0+rc42.ce.0')
       end
 
       it 'returns true' do
@@ -299,9 +291,7 @@
 
     context 'when on stable tag' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '')
-        stub_env_var('CI_COMMIT_TAG', '15.8.0+ce.0')
-        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
+        stub_tag('15.8.0+ce.0')
       end
 
       it 'returns true' do
@@ -311,10 +301,7 @@
 
     context 'when on auto-deploy tag' do
       before do
-        stub_env_var('CI_COMMIT_BRANCH', '')
-        stub_env_var('CI_COMMIT_TAG', '15.8.202301050320+b251a9da107.0e5d6807f3a')
-        allow(Build::Info).to receive(:current_git_tag).and_return('15.8.202301050320+b251a9da107.0e5d6807f3a')
-        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
+        stub_tag('15.8.202301050320+b251a9da107.0e5d6807f3a')
       end
 
       it 'returns false' do
diff --git a/spec/lib/gitlab/build/facts_spec.rb b/spec/lib/gitlab/build/facts_spec.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2ZhY3RzX3NwZWMucmI=..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2ZhY3RzX3NwZWMucmI= 100644
--- a/spec/lib/gitlab/build/facts_spec.rb
+++ b/spec/lib/gitlab/build/facts_spec.rb
@@ -93,8 +93,8 @@
 
   describe '.generate_tag_files' do
     before do
-      allow(Build::Info).to receive(:latest_stable_tag).and_return('14.6.2+ce.0')
-      allow(Build::Info).to receive(:latest_tag).and_return('14.7.0+rc42.ce.0')
+      allow(Build::Info::Git).to receive(:latest_stable_tag).and_return('14.6.2+ce.0')
+      allow(Build::Info::Git).to receive(:latest_tag).and_return('14.7.0+rc42.ce.0')
     end
 
     it 'writes tag details to file' do
@@ -223,7 +223,7 @@
     before do
       allow(described_class).to receive(:generate_knapsack_report?).and_return('true')
       allow(Build::GitlabImage).to receive(:gitlab_registry_image_address).and_return('registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:14.6.2-rfbranch.450066356.c97110ad-0')
-      allow(Build::Info).to receive(:latest_stable_tag).and_return("14.6.2+rfbranch.450066356")
+      allow(Build::Info::Git).to receive(:latest_stable_tag).and_return("14.6.2+rfbranch.450066356")
 
       stub_env_var('QA_IMAGE', 'gitlab/gitlab-ee-qa:nightly')
       stub_env_var('QA_TESTS', '')
diff --git a/spec/lib/gitlab/build/info/git_spec.rb b/spec/lib/gitlab/build/info/git_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2luZm8vZ2l0X3NwZWMucmI=
--- /dev/null
+++ b/spec/lib/gitlab/build/info/git_spec.rb
@@ -0,0 +1,342 @@
+require 'spec_helper'
+require 'gitlab/build/info/git'
+
+RSpec.describe Build::Info::Git do
+  before do
+    stub_default_package_version
+
+    ce_tags = "16.1.1+ce.0\n16.0.0+rc42.ce.0\n15.11.1+ce.0\n15.11.0+ce.0\n15.10.0+ce.0\n15.10.0+rc42.ce.0"
+    ee_tags = "16.1.1+ee.0\n16.0.0+rc42.ee.0\n15.11.1+ee.0\n15.11.0+ee.0\n15.10.0+ee.0\n15.10.0+rc42.ee.0"
+    allow(Gitlab::Util).to receive(:shellout_stdout).with(/git -c versionsort.*ce/).and_return(ce_tags)
+    allow(Gitlab::Util).to receive(:shellout_stdout).with(/git -c versionsort.*ee/).and_return(ee_tags)
+  end
+
+  describe '.branch_name' do
+    context 'in tags' do
+      context 'in CI' do
+        before do
+          stub_tag('16.1.1+ee.0')
+        end
+
+        it 'returns nil' do
+          expect(described_class.branch_name).to be_nil
+        end
+      end
+
+      context 'not in CI' do
+        before do
+          stub_env_var('CI_COMMIT_BRANCH', '')
+          allow(Gitlab::Util).to receive(:shellout_stdout).with('git rev-parse --abbrev-ref HEAD').and_return('HEAD')
+        end
+
+        it 'returns nil' do
+          expect(described_class.branch_name).to be_nil
+        end
+      end
+    end
+
+    context 'in branches' do
+      context 'in CI' do
+        before do
+          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+        end
+
+        it 'returns branch name from CI variable' do
+          expect(described_class.branch_name).to eq('my-feature-branch')
+        end
+      end
+
+      context 'not in CI' do
+        before do
+          stub_env_var('CI_COMMIT_BRANCH', '')
+          stub_env_var('CI_COMMIT_TAG', '')
+          allow(Gitlab::Util).to receive(:shellout_stdout).with('git rev-parse --abbrev-ref HEAD').and_return('my-feature-branch')
+        end
+
+        it 'computes branch name from git' do
+          expect(described_class.branch_name).to eq('my-feature-branch')
+        end
+      end
+    end
+  end
+
+  describe '.tag_name' do
+    context 'in tags' do
+      context 'in CI' do
+        before do
+          stub_env_var('CI_COMMIT_BRANCH', '')
+          stub_env_var('CI_COMMIT_TAG', '16.1.1+ee.0')
+        end
+
+        it 'returns tag name from CI variables' do
+          expect(described_class.tag_name).to eq('16.1.1+ee.0')
+        end
+
+        context 'not in CI' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '')
+            stub_env_var('CI_COMMIT_TAG', '')
+            allow(Gitlab::Util).to receive(:shellout_stdout).with('git describe --tags --exact-match').and_return('16.1.1+ee.0')
+          end
+
+          it 'computes tag name from git' do
+            expect(described_class.tag_name).to eq('16.1.1+ee.0')
+          end
+        end
+      end
+    end
+
+    context 'in branches' do
+      before do
+        stub_branch('my-feature-branch')
+      end
+
+      it 'returns nil' do
+        expect(described_class.tag_name).to be_nil
+      end
+    end
+
+    context 'if some other error is raised' do
+      before do
+        stub_env_var('CI_COMMIT_BRANCH', '')
+        stub_env_var('CI_COMMIT_TAG', '')
+        allow(Gitlab::Util).to receive(:shellout_stdout).with('git describe --tags --exact-match').and_raise(Gitlab::Util::ShellOutExecutionError.new("", 100, "", "Some Other Error"))
+      end
+
+      it 'raises the error' do
+        expect { described_class.tag_name }.to raise_error(/Some Other Error/)
+      end
+    end
+  end
+
+  describe '.commit_sha' do
+    context 'from CI' do
+      before do
+        stub_env_var('CI_COMMIT_SHA', '3cd8e712ccd3c3f356108ec1a5cbeecbf3d3be88')
+        allow(Gitlab::Util).to receive(:shellout_stdout).with('git rev-parse HEAD').and_return('some-other-sha')
+      end
+
+      it 'returns truncated commit sha from CI variable' do
+        expect(described_class.commit_sha).to eq('3cd8e712')
+      end
+    end
+
+    context 'not from CI' do
+      before do
+        stub_env_var('CI_COMMIT_SHA', '')
+        allow(Gitlab::Util).to receive(:shellout_stdout).with('git rev-parse HEAD').and_return('3cd8e712ccd3c3f356108ec1a5cbeecbf3d3be88')
+      end
+
+      it 'returns truncated commit sha from CI variable' do
+        expect(described_class.commit_sha).to eq('3cd8e712')
+      end
+    end
+  end
+
+  describe '.latest_tag' do
+    context 'on CE edition' do
+      before do
+        stub_is_ee(false)
+      end
+
+      context 'on stable branch' do
+        context 'when tags already exist in the stable version series' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '15-10-stable')
+          end
+
+          it 'returns the latest tag in the stable version series' do
+            expect(described_class.latest_tag).to eq('15.10.0+ce.0')
+          end
+        end
+
+        context 'when tags does not exist in the stable version series' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '16-5-stable')
+          end
+
+          it 'returns the latest available tag' do
+            expect(described_class.latest_tag).to eq('16.1.1+ce.0')
+          end
+        end
+
+        context 'when latest tag in the series is an RC tag' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '16-0-stable')
+          end
+
+          it 'returns the RC tag' do
+            expect(described_class.latest_tag).to eq('16.0.0+rc42.ce.0')
+          end
+        end
+      end
+
+      context 'on feature branch' do
+        before do
+          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+        end
+
+        it 'returns the latest available tag' do
+          expect(described_class.latest_tag).to eq('16.1.1+ce.0')
+        end
+      end
+    end
+
+    context 'on EE edition' do
+      before do
+        stub_is_ee(true)
+      end
+
+      context 'on stable branch' do
+        context 'when tags already exist in the stable version series' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '15-10-stable')
+          end
+
+          it 'returns the latest tag in the stable version series' do
+            expect(described_class.latest_tag).to eq('15.10.0+ee.0')
+          end
+        end
+
+        context 'when tags does not exist in the stable version series' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '16-5-stable')
+          end
+
+          it 'returns the latest available tag' do
+            expect(described_class.latest_tag).to eq('16.1.1+ee.0')
+          end
+        end
+
+        context 'when latest tag in the series is an RC tag' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '16-0-stable')
+          end
+
+          it 'returns the RC tag' do
+            expect(described_class.latest_tag).to eq('16.0.0+rc42.ee.0')
+          end
+        end
+      end
+
+      context 'on feature branch' do
+        before do
+          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+        end
+
+        it 'returns the latest available tag' do
+          expect(described_class.latest_tag).to eq('16.1.1+ee.0')
+        end
+      end
+    end
+  end
+
+  describe '.latest_stable_tag' do
+    context 'on CE edition' do
+      before do
+        stub_is_ee(false)
+      end
+
+      context 'on stable branch' do
+        context 'when tags already exist in the stable version series' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '15-10-stable')
+          end
+
+          it 'returns the latest tag in the stable version series' do
+            expect(described_class.latest_stable_tag).to eq('15.10.0+ce.0')
+          end
+        end
+
+        context 'when tags does not exist in the stable version series' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '16-5-stable')
+          end
+
+          it 'returns the latest available tag' do
+            expect(described_class.latest_stable_tag).to eq('16.1.1+ce.0')
+          end
+        end
+
+        context 'when latest tag in the series is an RC tag' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '16-0-stable')
+          end
+
+          it 'skips the RC tag and returns the latest available tag' do
+            expect(described_class.latest_stable_tag).to eq('16.1.1+ce.0')
+          end
+        end
+      end
+
+      context 'on feature branch' do
+        before do
+          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+        end
+
+        it 'returns the latest available tag' do
+          expect(described_class.latest_stable_tag).to eq('16.1.1+ce.0')
+        end
+      end
+    end
+
+    context 'on EE edition' do
+      before do
+        stub_is_ee(true)
+      end
+
+      context 'on stable branch' do
+        context 'when tags already exist in the stable version series' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '15-10-stable')
+          end
+
+          it 'returns the latest tag in the stable version series' do
+            expect(described_class.latest_stable_tag).to eq('15.10.0+ee.0')
+          end
+        end
+
+        context 'when tags does not exist in the stable version series' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '16-5-stable')
+          end
+
+          it 'returns the latest available tag' do
+            expect(described_class.latest_stable_tag).to eq('16.1.1+ee.0')
+          end
+        end
+
+        context 'when latest tag in the series is an RC tag' do
+          before do
+            stub_env_var('CI_COMMIT_BRANCH', '16-0-stable')
+          end
+
+          it 'skips the RC tag and returns the latest available tag' do
+            expect(described_class.latest_stable_tag).to eq('16.1.1+ee.0')
+          end
+        end
+      end
+
+      context 'on feature branch' do
+        before do
+          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+        end
+
+        it 'returns the latest available tag' do
+          expect(described_class.latest_stable_tag).to eq('16.1.1+ee.0')
+        end
+      end
+    end
+
+    context 'when a level is specified' do
+      before do
+        stub_is_ee(true)
+        stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+      end
+
+      it 'returns recent tag at specified position' do
+        expect(described_class.latest_stable_tag(level: 2)).to eq('15.11.1+ee.0')
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build/info_spec.rb b/spec/lib/gitlab/build/info_spec.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2luZm9fc3BlYy5yYg==..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2luZm9fc3BlYy5yYg== 100644
--- a/spec/lib/gitlab/build/info_spec.rb
+++ b/spec/lib/gitlab/build/info_spec.rb
@@ -49,8 +49,8 @@
     it 'defaults to an initial build version when there are no matching tags' do
       allow(Build::Check).to receive(:on_tag?).and_return(false)
       allow(Build::Check).to receive(:is_nightly?).and_return(false)
-      allow(Build::Info).to receive(:latest_tag).and_return('')
-      allow(Build::Info).to receive(:commit_sha).and_return('ffffffff')
+      allow(Build::Info::Git).to receive(:latest_tag).and_return('')
+      allow(Build::Info::Git).to receive(:commit_sha).and_return('ffffffff')
       stub_env_var('CI_PIPELINE_ID', '5555')
 
       expect(described_class.release_version).to eq('0.0.1+rfbranch.5555.ffffffff-ce.1')
@@ -91,226 +91,6 @@
     end
   end
 
-  describe '.latest_tag' do
-    context 'on CE edition' do
-      before do
-        stub_is_ee(false)
-      end
-
-      context 'on stable branch' do
-        context 'when tags already exist in the stable version series' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '15-10-stable')
-          end
-
-          it 'returns the latest tag in the stable version series' do
-            expect(described_class.latest_tag).to eq('15.10.0+ce.0')
-          end
-        end
-
-        context 'when tags does not exist in the stable version series' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '16-5-stable')
-          end
-
-          it 'returns the latest available tag' do
-            expect(described_class.latest_tag).to eq('16.1.1+ce.0')
-          end
-        end
-
-        context 'when latest tag in the series is an RC tag' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '16-0-stable')
-          end
-
-          it 'returns the RC tag' do
-            expect(described_class.latest_tag).to eq('16.0.0+rc42.ce.0')
-          end
-        end
-      end
-
-      context 'on feature branch' do
-        before do
-          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
-        end
-
-        it 'returns the latest available tag' do
-          expect(described_class.latest_tag).to eq('16.1.1+ce.0')
-        end
-      end
-    end
-
-    context 'on EE edition' do
-      before do
-        stub_is_ee(true)
-      end
-
-      context 'on stable branch' do
-        context 'when tags already exist in the stable version series' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '15-10-stable')
-          end
-
-          it 'returns the latest tag in the stable version series' do
-            expect(described_class.latest_tag).to eq('15.10.0+ee.0')
-          end
-        end
-
-        context 'when tags does not exist in the stable version series' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '16-5-stable')
-          end
-
-          it 'returns the latest available tag' do
-            expect(described_class.latest_tag).to eq('16.1.1+ee.0')
-          end
-        end
-
-        context 'when latest tag in the series is an RC tag' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '16-0-stable')
-          end
-
-          it 'returns the RC tag' do
-            expect(described_class.latest_tag).to eq('16.0.0+rc42.ee.0')
-          end
-        end
-      end
-
-      context 'on feature branch' do
-        before do
-          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
-        end
-
-        it 'returns the latest available tag' do
-          expect(described_class.latest_tag).to eq('16.1.1+ee.0')
-        end
-      end
-    end
-  end
-
-  describe '.latest_stable_tag' do
-    context 'on CE edition' do
-      before do
-        stub_is_ee(false)
-      end
-
-      context 'on stable branch' do
-        context 'when tags already exist in the stable version series' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '15-10-stable')
-          end
-
-          it 'returns the latest tag in the stable version series' do
-            expect(described_class.latest_stable_tag).to eq('15.10.0+ce.0')
-          end
-        end
-
-        context 'when tags does not exist in the stable version series' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '16-5-stable')
-          end
-
-          it 'returns the latest available tag' do
-            expect(described_class.latest_stable_tag).to eq('16.1.1+ce.0')
-          end
-        end
-
-        context 'when latest tag in the series is an RC tag' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '16-0-stable')
-          end
-
-          it 'skips the RC tag and returns the latest available tag' do
-            expect(described_class.latest_stable_tag).to eq('16.1.1+ce.0')
-          end
-        end
-      end
-
-      context 'on feature branch' do
-        before do
-          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
-        end
-
-        it 'returns the latest available tag' do
-          expect(described_class.latest_stable_tag).to eq('16.1.1+ce.0')
-        end
-      end
-    end
-
-    context 'on EE edition' do
-      before do
-        stub_is_ee(true)
-      end
-
-      context 'on stable branch' do
-        context 'when tags already exist in the stable version series' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '15-10-stable')
-          end
-
-          it 'returns the latest tag in the stable version series' do
-            expect(described_class.latest_stable_tag).to eq('15.10.0+ee.0')
-          end
-        end
-
-        context 'when tags does not exist in the stable version series' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '16-5-stable')
-          end
-
-          it 'returns the latest available tag' do
-            expect(described_class.latest_stable_tag).to eq('16.1.1+ee.0')
-          end
-        end
-
-        context 'when latest tag in the series is an RC tag' do
-          before do
-            stub_env_var('CI_COMMIT_BRANCH', '16-0-stable')
-          end
-
-          it 'skips the RC tag and returns the latest available tag' do
-            expect(described_class.latest_stable_tag).to eq('16.1.1+ee.0')
-          end
-        end
-      end
-
-      context 'on feature branch' do
-        before do
-          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
-        end
-
-        it 'returns the latest available tag' do
-          expect(described_class.latest_stable_tag).to eq('16.1.1+ee.0')
-        end
-      end
-    end
-
-    context 'when a level is specified' do
-      context 'when level is less than total number of tags' do
-        before do
-          stub_is_ee(true)
-          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
-        end
-
-        it 'returns recent tag at specified position' do
-          expect(described_class.latest_stable_tag(level: 2)).to eq('15.11.1+ee.0')
-        end
-      end
-
-      context 'when level is more than total number of tags' do
-        before do
-          stub_is_ee(true)
-          stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
-        end
-
-        it 'returns last tag' do
-          expect(described_class.latest_stable_tag(level: 6)).to eq('15.10.0+ee.0')
-        end
-      end
-    end
-  end
-
   describe '.gitlab_version' do
     describe 'GITLAB_VERSION variable specified' do
       it 'returns passed value' do
@@ -327,15 +107,6 @@
     end
   end
 
-  describe '.previous_version' do
-    it 'detects previous version correctly' do
-      allow(described_class).to receive(:`).with("git describe --exact-match 2>/dev/null").and_return('10.4.0+ee.0')
-      allow(Build::Info).to receive(:`).with(/git -c versionsort/).and_return("10.4.0+ee.0\n10.3.5+ee.0")
-
-      expect(described_class.previous_version).to eq("10.3.5-ee.0")
-    end
-  end
-
   describe '.gitlab_rails repo' do
     describe 'with alternative sources channel selected' do
       before do
diff --git a/spec/lib/gitlab/tasks/qa_spec.rb b/spec/lib/gitlab/tasks/qa_spec.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_c3BlYy9saWIvZ2l0bGFiL3Rhc2tzL3FhX3NwZWMucmI=..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_c3BlYy9saWIvZ2l0bGFiL3Rhc2tzL3FhX3NwZWMucmI= 100644
--- a/spec/lib/gitlab/tasks/qa_spec.rb
+++ b/spec/lib/gitlab/tasks/qa_spec.rb
@@ -40,7 +40,7 @@
   describe 'qa:copy' do
     before do
       allow(Build::Info).to receive(:gitlab_version).and_return(gitlab_version)
-      allow(Build::Info).to receive(:commit_sha).and_return(commit_sha)
+      allow(Build::Info::Git).to receive(:commit_sha).and_return(commit_sha)
     end
 
     describe ':nightly' do
@@ -139,7 +139,7 @@
         Rake::Task['qa:push:staging'].reenable
 
         allow(Build::Info).to receive(:gitlab_version).and_return(gitlab_version)
-        allow(Build::Info).to receive(:commit_sha).and_return(commit_sha)
+        allow(Build::Info::Git).to receive(:commit_sha).and_return(commit_sha)
       end
 
       it 'pushes staging images correctly' do
diff --git a/spec/support/macros.rb b/spec/support/macros.rb
index f26af321538def1d4a72605a5b54310aeac8f5ff_c3BlYy9zdXBwb3J0L21hY3Jvcy5yYg==..9ff1734b0815b09760e2d71b3cd6b71c7ee51e44_c3BlYy9zdXBwb3J0L21hY3Jvcy5yYg== 100644
--- a/spec/support/macros.rb
+++ b/spec/support/macros.rb
@@ -51,6 +51,22 @@
       allow(ENV).to receive(:[]).with(var).and_return(value)
     end
 
+    def stub_branch(branch)
+      stub_env_var('CI_COMMIT_BRANCH', branch)
+      allow(Gitlab::Util).to receive(:shellout_stdout).with('git rev-parse --abbrev-ref HEAD').and_return(branch)
+
+      stub_env_var('CI_COMMIT_TAG', '')
+      allow(Gitlab::Util).to receive(:shellout_stdout).with('git describe --tags --exact-match').and_raise(Gitlab::Util::ShellOutExecutionError.new("git describe --tags --exact-match", 128, "", "fatal: no tag exactly matches 'foobar'"))
+    end
+
+    def stub_tag(tag)
+      stub_env_var('CI_COMMIT_TAG', tag)
+      allow(Gitlab::Util).to receive(:shellout_stdout).with('git describe --tags --exact-match').and_return(tag)
+
+      stub_env_var('CI_COMMIT_BRANCH', '')
+      allow(Gitlab::Util).to receive(:shellout_stdout).with('git rev-parse --abbrev-ref HEAD').and_return('HEAD')
+    end
+
     def stub_is_package_version(package, value = nil)
       allow(File).to receive(:read).with('VERSION').and_return(value ? "1.2.3-#{package}" : '1.2.3')
     end