diff options
Diffstat (limited to 'lib/gitlab/git/keep_around.rb')
-rw-r--r-- | lib/gitlab/git/keep_around.rb | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/lib/gitlab/git/keep_around.rb b/lib/gitlab/git/keep_around.rb new file mode 100644 index 00000000000..d58f10bdbb7 --- /dev/null +++ b/lib/gitlab/git/keep_around.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# Makes sure a commit is kept around when Git garbage collection runs. +# Git GC will delete commits from the repository that are no longer in any +# branches or tags, but we want to keep some of these commits around, for +# example if they have comments or CI builds. +# +# For Geo's sake, pass in multiple shas rather than calling it multiple times, +# to avoid unnecessary syncing. +module Gitlab + module Git + class KeepAround + def self.execute(repository, shas) + new(repository).execute(shas) + end + + def initialize(repository) + @repository = repository + end + + def execute(shas) + shas.each do |sha| + next unless sha.present? && commit_by(oid: sha) + + next if kept_around?(sha) + + # This will still fail if the file is corrupted (e.g. 0 bytes) + raw_repository.write_ref(keep_around_ref_name(sha), sha) + rescue Gitlab::Git::CommandError => ex + Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}" # rubocop:disable Gitlab/RailsLogger + end + end + + def kept_around?(sha) + ref_exists?(keep_around_ref_name(sha)) + end + + delegate :commit_by, :raw_repository, :ref_exists?, :disk_path, to: :@repository + private :commit_by, :raw_repository, :ref_exists?, :disk_path + + private + + def keep_around_ref_name(sha) + "refs/#{::Repository::REF_KEEP_AROUND}/#{sha}" + end + end + end +end |