git.rb 2.63 KB
Newer Older
1 2
# frozen_string_literal: true

3 4
require_dependency 'gitlab/encoding_helper'

5 6
module Gitlab
  module Git
Rubén Dávila's avatar
Rubén Dávila committed
7 8 9 10
    # The ID of empty tree.
    # See http://stackoverflow.com/a/40884093/1856239 and
    # https://github.com/git/git/blob/3ad8b5bf26362ac67c9020bf8c30eee54a84f56d/cache.h#L1011-L1012
    EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'.freeze
11
    BLANK_SHA = ('0' * 40).freeze
12
    COMMIT_ID = /\A[0-9a-f]{40}\z/.freeze
13 14
    TAG_REF_PREFIX = "refs/tags/".freeze
    BRANCH_REF_PREFIX = "refs/heads/".freeze
15

16 17 18 19 20
    BaseError = Class.new(StandardError)
    CommandError = Class.new(BaseError)
    CommitError = Class.new(BaseError)
    OSError = Class.new(BaseError)
    UnknownRef = Class.new(BaseError)
21

22
    class << self
23 24
      include Gitlab::EncodingHelper

25
      def ref_name(ref)
26
        encode!(ref).sub(%r{\Arefs/(tags|heads|remotes)/}, '')
27 28
      end

29 30 31 32 33 34 35 36 37
      def branch_name(ref)
        ref = ref.to_s
        if self.branch_ref?(ref)
          self.ref_name(ref)
        else
          nil
        end
      end

38
      def committer_hash(email:, name:)
39 40
        return if email.nil? || name.nil?

41 42 43 44 45 46 47
        {
          email: email,
          name: name,
          time: Time.now
        }
      end

48 49 50 51 52 53 54 55 56
      def tag_name(ref)
        ref = ref.to_s
        if self.tag_ref?(ref)
          self.ref_name(ref)
        else
          nil
        end
      end

57
      def tag_ref?(ref)
58
        ref =~ /^#{TAG_REF_PREFIX}.+/
59 60 61
      end

      def branch_ref?(ref)
62
        ref =~ /^#{BRANCH_REF_PREFIX}.+/
63 64 65 66 67
      end

      def blank_ref?(ref)
        ref == BLANK_SHA
      end
68

69 70 71 72
      def commit_id?(ref)
        COMMIT_ID.match?(ref)
      end

73
      def version
74
        Gitlab::Git::Version.git_version
75
      end
76 77 78 79 80 81 82 83 84

      def check_namespace!(*objects)
        expected_namespace = self.name + '::'
        objects.each do |object|
          unless object.class.name.start_with?(expected_namespace)
            raise ArgumentError, "expected object in #{expected_namespace}, got #{object}"
          end
        end
      end
85 86 87 88

      def diff_line_code(file_path, new_line_position, old_line_position)
        "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}"
      end
89 90 91 92 93 94 95 96 97 98 99 100

      def shas_eql?(sha1, sha2)
        return false if sha1.nil? || sha2.nil?
        return false unless sha1.class == sha2.class

        # If either of the shas is below the minimum length, we cannot be sure
        # that they actually refer to the same commit because of hash collision.
        length = [sha1.length, sha2.length].min
        return false if length < Gitlab::Git::Commit::MIN_SHA_LENGTH

        sha1[0, length] == sha2[0, length]
      end
101
    end
102 103
  end
end