class Gollum::Git::Git

Public Class Methods

new(repo) click to toggle source

Rugged does not have a Git class, but the Repository class should allows us to do what’s necessary.

# File lib/rugged_adapter/git_layer_rugged.rb, line 194
def initialize(repo)
  @repo = repo
end

Public Instance Methods

cat_file(options, sha) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 224
def cat_file(options, sha)
  @repo.lookup(sha).read_raw
end
checkout(path, ref = 'HEAD', options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 259
def checkout(path, ref = 'HEAD', options = {})
  path = path.nil? ? path : [path]
  options = options.merge({:paths => path, :strategy => :force})
  if ref == 'HEAD'
    @repo.checkout_head(**options)
  else
    ref = "refs/heads/#{ref}" unless ref =~ /^refs\/heads\//
    @repo.checkout_tree(sha_from_ref(ref), **options)
  end
end
commit_from_ref(ref) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 335
def commit_from_ref(ref)
  sha_or_commit_from_ref(ref, :commit)
end
exist?() click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 198
def exist?
  ::File.exist?(@repo.path)
end
grep(search_terms, options={}) { |path, data| ... } click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 202
def grep(search_terms, options={}, &block)
  ref   = options[:ref] ? options[:ref] : "HEAD"
  tree  = @repo.lookup(sha_from_ref(ref)).tree
  tree  = @repo.lookup(tree.path(options[:path])[:oid]) if options[:path]
  enc   = options.fetch(:encoding, 'utf-8')
  results = []
  tree.walk_blobs(:postorder) do |root, entry|
    blob  = @repo.lookup(entry[:oid])
    path  = options[:path] ? ::File.join(options[:path], root, entry[:name]) : "#{root}#{entry[:name]}"
    data  = blob.binary? ? nil : blob.content.force_encoding(enc)
    results << yield(path, data)
  end
  results.compact
end
log(ref = Gollum::Git.default_ref_for_repo(@repo), path = nil, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 270
def log(ref = Gollum::Git.default_ref_for_repo(@repo), path = nil, options = {})
  default_options = {
    :limit => options[:max_count] ? options[:max_count] : 10,
    :offset => options[:skip] ? options[:skip] : 0,
    :path => path,
    :follow => false,
    :skip_merges => false
  }
  options = default_options.merge(options)
  options[:limit] ||= 0
  options[:offset] ||= 0
  sha = sha_from_ref(ref)
  return [] if sha.nil?
  begin
    build_log(sha, options)
  rescue Rugged::OdbError, Rugged::InvalidError, Rugged::ReferenceError
  # Return an empty array if the ref wasn't found
    []
  end
end
lookup(id) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 308
def lookup(id)
  @repo.lookup(id)
end
ls_files(query, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 295
def ls_files(query, options = {})
  ref = options[:ref] || Gollum::Git.default_ref_for_repo(@repo)
  tree = @repo.lookup(sha_from_ref(ref)).tree
  tree = @repo.lookup(tree[options[:path]][:oid]) if options[:path]
  results = []
  tree.walk_blobs do |root, blob|
    next unless blob[:name] =~ /#{query}/
    path = options[:path] ? ::File.join(options[:path], root, blob[:name]) : "#{root}#{blob[:name]}"
    results << path
  end
  results
end
pull(remote, branches = nil, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 344
def pull(remote, branches = nil, options = {})
  branches = [branches].flatten.map {|branch| "refs/heads/#{branch}" unless branch =~ /^refs\/heads\//}
  r = @repo.remotes[remote]
  r.fetch(branches, **options)
  branches.each do |branch|
    branch_name = branch.match(/^refs\/heads\/(.*)/)[1]
    remote_name = remote.match(/^(refs\/heads\/)?(.*)/)[2]
    remote_ref = @repo.branches["#{remote_name}/#{branch_name}"].target
    local_ref = @repo.branches[branch].target
    index = @repo.merge_commits(local_ref, remote_ref)
    options = { author: Actor.default_actor.to_h,
      committer:  Actor.default_actor.to_h,
      message:    "Merged branch #{branch} of #{remote}.",
      parents: [local_ref, remote_ref],
      tree: index.write_tree(@repo),
      update_ref: branch
    }
    Rugged::Commit.create @repo, options
    @repo.checkout(@repo.head.name, :strategy => :force) if !@repo.bare? && branch == @repo.head.name
  end
end
push(remote, branches = nil, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 339
def push(remote, branches = nil, options = {})
  branches = [branches].flatten.map {|branch| "refs/heads/#{branch}" unless branch =~ /^refs\/heads\//}
  @repo.push(remote, branches, **options)
end
ref_to_sha(query) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 312
def ref_to_sha(query)
  return query if sha?(query)
  query = "refs/heads/#{query}" if !query.nil? && !(query =~ /^refs\/heads\//) && !(query == "HEAD")
  begin
    return @repo.rev_parse_oid(query)
  rescue Rugged::ReferenceError, Rugged::InvalidError
    return nil
  end
end
revert_commit(sha1, sha2) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 242
def revert_commit(sha1, sha2)
  diff = @repo.diff(sha2, sha1)
  index = @repo.revert_commit(sha2, sha1)
  return false unless index
  paths = []
  diff.each_delta do |delta|
    paths << delta.new_file[:path]
    paths << delta.old_file[:path]
  end
  paths.uniq!
  begin
    return index.write_tree(@repo), paths
  rescue Rugged::IndexError
    return false
  end
end
revert_path(path, sha1, sha2) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 228
def revert_path(path, sha1, sha2)
  diff = @repo.diff(sha2, sha1, {:paths => [path]}).first.diff
  begin
    result = @repo.apply(diff, {:location => :index, :path => path})
  rescue RuntimeError, Rugged::PathError
    return false
  end
  begin
    return @repo.index.write_tree
  rescue Rugged::IndexError
    return false
  end
end
rm(path, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 217
def rm(path, options = {})
  index = @repo.index
  index.write
  to_delete = ::File.join(@repo.workdir, path)
  ::File.unlink to_delete if ::File.exist?(to_delete)
end
sha_from_ref(ref, request_kind = nil)
sha_or_commit_from_ref(ref, request_kind = nil) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 322
def sha_or_commit_from_ref(ref, request_kind = nil)
  sha = ref_to_sha(ref)
  return nil if sha.nil?
  object = @repo.lookup(sha)
  if object.kind_of?(Rugged::Commit) then
    return Gollum::Git::Commit.new(object) if request_kind == :commit
    sha
  elsif object.respond_to?(:target)
    sha_or_commit_from_ref(object.target.oid, request_kind)
  end
end
Also aliased as: sha_from_ref
versions_for_path(path = nil, ref = nil, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 291
def versions_for_path(path = nil, ref = nil, options = {})
  log(ref, path, options)
end

Private Instance Methods

build_log(sha, options) click to toggle source

Return an array of log commits, given a SHA hash and a hash of options. From Gitlab::Git

# File lib/rugged_adapter/git_layer_rugged.rb, line 374
def build_log(sha, options)
  # Instantiate a Walker and add the SHA hash
  walker = Rugged::Walker.new(@repo)
  walker.push(sha)
  commits = []
  skipped = 0
  current_path = options[:path].dup if options[:path]
  current_path = nil if current_path == ''
  renamed_path = current_path.nil? ? nil : current_path.dup
  track_pathnames = true if current_path && options[:follow]
  limit = options[:limit].to_i
  offset = options[:offset].to_i
  skip_merges = options[:skip_merges]
  walker.sorting(Rugged::SORT_DATE)

    walker.each do |c|
      break if limit > 0 && commits.length >= limit
        if skip_merges
          # Skip merge commits
          next if c.parents.length > 1
        end
        if !current_path || commit_touches_path?(c, current_path, options[:follow], walker)
          # This is a commit we care about, unless we haven't skipped enough
          # yet
          skipped += 1

          commits.push(Gollum::Git::Commit.new(c, track_pathnames ? renamed_path : nil)) if skipped > offset
          renamed_path = current_path.nil? ? nil : current_path.dup
        end
    end
  walker.reset
  commits
end
commit_touches_path?(commit, path, follow, walker) click to toggle source

Returns true if commit introduced changes to path, using commit trees to make that determination. Uses the history simplification rules that ‘git log` uses by default, where a commit is omitted if it is TREESAME to any parent.

If the follow option is true and the file specified by path was renamed, then the path value is set to the old path.

# File lib/rugged_adapter/git_layer_rugged.rb, line 415
def commit_touches_path?(commit, path, follow, walker)
  entry = tree_entry(commit, path)

    if commit.parents.empty?
      # This is the root commit, return true if it has +path+ in its tree
      return entry != nil
    end

  num_treesame = 0
  commit.parents.each do |parent|
    parent_entry = tree_entry(parent, path)

    # Only follow the first TREESAME parent for merge commits
    if num_treesame > 0
      walker.hide(parent.oid)
      next
    end

    if entry.nil? && parent_entry.nil?
      num_treesame += 1
    elsif entry && parent_entry && entry[:oid] == parent_entry[:oid]
      num_treesame += 1
    end
  end

  case num_treesame
    when 0
      detect_rename(commit, commit.parents.first, path) if follow
      true
    else false
  end
end
detect_rename(commit, parent, path) click to toggle source

Compare commit and parent for path. If path is a file and was renamed in commit, then set path to the old filename.

# File lib/rugged_adapter/git_layer_rugged.rb, line 462
def detect_rename(commit, parent, path)
  diff = parent.diff(commit, paths: [path], disable_pathspec_match: true)

  # If +path+ is a filename, not a directory, then we should only have
  # one delta. We don't need to follow renames for directories.
  return nil if diff.each_delta.count > 1

  delta = diff.each_delta.first
  if delta.added?
    full_diff = parent.diff(commit)
    full_diff.find_similar!

    full_diff.each_delta do |full_delta|
      if full_delta.renamed? && path == full_delta.new_file[:path]
        # Look for the old path in ancestors
        path.replace(full_delta.old_file[:path])
      end
    end
  end
end
sha?(str) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 368
def sha?(str)
  !!(str =~ /^[0-9a-f]{40}$/)
end
tree_entry(commit, path) click to toggle source

Find the entry for path in the tree for commit

# File lib/rugged_adapter/git_layer_rugged.rb, line 449
def tree_entry(commit, path)
  pathname = Pathname.new(path)
  tmp_entry = nil

  pathname.each_filename do |dir|
    tmp_entry = tmp_entry ? @repo.lookup(tmp_entry[:oid])[dir] : commit.tree[dir]
    return nil unless tmp_entry
  end
  tmp_entry
end