class Git::Lib

Internal git operations @api private

Constants

ADD_OPTION_MAP
ARCHIVE_OPTION_MAP
BRANCH_LINE_REGEXP
CAT_FILE_HEADER_LINE
CHECKOUT_INDEX_OPTION_MAP
CHECKOUT_OPTION_MAP
CLEAN_OPTION_MAP
CLONE_OPTION_MAP
COMMAND_ARG_DEFAULTS
COMMIT_OPTION_MAP
COMMIT_TREE_OPTION_MAP
CONFIG_SET_OPTION_MAP

WRITE COMMANDS ##

DESCRIBE_OPTION_MAP

The map defining how to translate user options to git command arguments.

DIFF_FULL_OPTION_MAP
DIFF_PATH_STATUS_OPTION_MAP
DIFF_STATS_OPTION_MAP
FETCH_OPTION_MAP
FULL_LOG_EXTRA_OPTIONS_MAP
GREP_OPTION_MAP
HeadState

The state and name of branch pointed to by ‘HEAD`

HEAD can be in the following states:

:active: ‘HEAD` points to a branch reference which in turn points to a commit representing the tip of that branch. This is the typical state when working on a branch.

:unborn: ‘HEAD` points to a branch reference that does not yet exist because no commits have been made on that branch. This state occurs in two scenarios:

  • When a repository is newly initialized, and no commits have been made on the initial branch.

  • When a new branch is created using ‘git checkout –orphan <branch>`, starting a new branch with no history.

:detached: ‘HEAD` points directly to a specific commit (identified by its SHA) rather than a branch reference. This state occurs when you check out a commit, a tag, or any state that is not directly associated with a branch. The branch name in this case is `HEAD`.

INIT_OPTION_MAP
LOG_OPTION_MAP
LS_REMOTE_OPTION_MAP
LS_TREE_OPTION_MAP
MERGE_BASE_OPTION_MAP
MERGE_OPTION_MAP
PULL_OPTION_MAP
PUSH_OPTION_MAP
READ_TREE_OPTION_MAP
REMOTE_ADD_OPTION_MAP
RESET_OPTION_MAP
REVERT_OPTION_MAP
RM_OPTION_MAP
STATIC_GLOBAL_OPTS
TAG_OPTION_MAP

Attributes

git_dir[R]

The path to the Git repository directory. The default is ‘“#{git_work_dir}/.git”`.

@return [Pathname] the Git repository directory.

@see [Git repository](git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefrepositoryarepository)

git_index_file[R]

The Git index file used to stage changes (using ‘git add`) before they are committed.

@return [Pathname] the Git index file

@see [Git index file](git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefindexaindex)

git_work_dir[R]

The path to the Git working copy. The default is ‘“./.git”’.

@return [Pathname] the path to the Git working copy.

@see [Git working tree](git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefworkingtreeaworkingtree)

Public Class Methods

new(base = nil, logger = nil) click to toggle source

Create a new Git::Lib object

@overload initialize(base, logger)

@param base [Hash] the hash containing paths to the Git working copy,
  the Git repository directory, and the Git index file.

@option base [Pathname] :working_directory
@option base [Pathname] :repository
@option base [Pathname] :index

@param [Logger] logger

@overload initialize(base, logger)

@param base [#dir, #repo, #index] an object with methods to get the Git worktree (#dir),
  the Git repository directory (#repo), and the Git index file (#index).

@param [Logger] logger
# File lib/git/lib.rb, line 65
def initialize(base = nil, logger = nil)
  @logger = logger || Logger.new(nil)

  case base
  when Git::Base
    initialize_from_base(base)
  when Hash
    initialize_from_hash(base)
  end
end
warn_if_old_command(lib) click to toggle source
# File lib/git/lib.rb, line 1555
def self.warn_if_old_command(lib) # rubocop:disable Naming/PredicateMethod
  Git::Deprecation.warn('Git::Lib#warn_if_old_command is deprecated. Use meets_required_version?.')

  return true if @version_checked

  @version_checked = true
  unless lib.meets_required_version?
    warn "[WARNING] The git gem requires git #{lib.required_command_version.join('.')} or later, " \
         "but only found #{lib.current_command_version.join('.')}. You should probably upgrade."
  end
  true
end

Public Instance Methods

add(paths = '.', options = {}) click to toggle source

Update the index from the current worktree to prepare the for the next commit

@example

lib.add('path/to/file')
lib.add(['path/to/file1','path/to/file2'])
lib.add(:all => true)

@param [String, Array<String>] paths files to be added to the repository (relative to the worktree root) @param [Hash] options

@option options [Boolean] :all Add, modify, and remove index entries to match the worktree @option options [Boolean] :force Allow adding otherwise ignored files

# File lib/git/lib.rb, line 1048
def add(paths = '.', options = {})
  args = build_args(options, ADD_OPTION_MAP)

  args << '--'
  args.concat(Array(paths))

  command('add', *args)
end
apply(patch_file) click to toggle source
# File lib/git/lib.rb, line 1170
def apply(patch_file)
  arr_opts = []
  arr_opts << '--' << patch_file if patch_file
  command('apply', *arr_opts)
end
apply_mail(patch_file) click to toggle source
# File lib/git/lib.rb, line 1176
def apply_mail(patch_file)
  arr_opts = []
  arr_opts << '--' << patch_file if patch_file
  command('am', *arr_opts)
end
archive(sha, file = nil, opts = {}) click to toggle source
# File lib/git/lib.rb, line 1507
def archive(sha, file = nil, opts = {})
  ArgsBuilder.validate!(opts, ARCHIVE_OPTION_MAP)
  file ||= temp_file_name
  format, gzip = parse_archive_format_options(opts)

  args = build_args(opts, ARCHIVE_OPTION_MAP)
  args.unshift("--format=#{format}")
  args << sha
  args.push('--', opts[:path]) if opts[:path]

  File.open(file, 'wb') { |f| command('archive', *args, out: f) }
  apply_gzip(file) if gzip

  file
end
assert_args_are_not_options(arg_name, *args) click to toggle source

Validate that the given arguments cannot be mistaken for a command-line option

@param arg_name [String] the name of the arguments to mention in the error message @param args [Array<String, nil>] the arguments to validate

@raise [ArgumentError] if any of the parameters are a string starting with a hyphen @return [void]

# File lib/git/lib.rb, line 820
def assert_args_are_not_options(arg_name, *args)
  invalid_args = args.select { |arg| arg&.start_with?('-') }
  return unless invalid_args.any?

  raise ArgumentError, "Invalid #{arg_name}: '#{invalid_args.join("', '")}'"
end
branch_contains(commit, branch_name = '') click to toggle source
# File lib/git/lib.rb, line 781
def branch_contains(commit, branch_name = '')
  command('branch',  branch_name, '--contains', commit)
end
branch_current() click to toggle source
# File lib/git/lib.rb, line 776
def branch_current
  branch_name = command('branch', '--show-current')
  branch_name.empty? ? 'HEAD' : branch_name
end
branch_delete(branch) click to toggle source
# File lib/git/lib.rb, line 1213
def branch_delete(branch)
  command('branch', '-D', branch)
end
branch_new(branch) click to toggle source
# File lib/git/lib.rb, line 1209
def branch_new(branch)
  command('branch', branch)
end
branches_all() click to toggle source
# File lib/git/lib.rb, line 694
def branches_all
  lines = command_lines('branch', '-a')
  lines.each_with_index.filter_map do |line, index|
    parse_branch_line(line, index, lines)
  end
end
cat_file_commit(object) click to toggle source

Return a hash of commit data

@see git-scm.com/docs/git-cat-file git-cat-file

@param object [String] the object to get the type

@return [Hash] commit data

The returned commit data has the following keys:

* tree [String]
* parent [Array<String>]
* author [String] the author name, email, and commit timestamp
* committer [String] the committer name, email, and merge timestamp
* message [String] the commit message
* gpgsig [String] the public signing key of the commit (if signed)

@raise [ArgumentError] if object is a string starting with a hyphen

# File lib/git/lib.rb, line 482
def cat_file_commit(object)
  assert_args_are_not_options('object', object)

  cdata = command_lines('cat-file', 'commit', object)
  process_commit_data(cdata, object)
end
Also aliased as: commit_data
cat_file_contents(object) { |file| ... } click to toggle source

Output the contents or other properties of one or more objects.

@see git-scm.com/docs/git-cat-file git-cat-file

@example Get the contents of a file without a block

lib.cat_file_contents('README.md') # => "This is a README file\n"

@example Get the contents of a file with a block

lib.cat_file_contents('README.md') { |f| f.read } # => "This is a README file\n"

@param object [String] the object whose contents to return

@return [String] the object contents

@raise [ArgumentError] if object is a string starting with a hyphen

# File lib/git/lib.rb, line 408
def cat_file_contents(object)
  assert_args_are_not_options('object', object)

  if block_given?
    Tempfile.create do |file|
      # If a block is given, write the output from the process to a temporary
      # file and then yield the file to the block
      #
      command('cat-file', '-p', object, out: file, err: file)
      file.rewind
      yield file
    end
  else
    # If a block is not given, return the file contents as a string
    command('cat-file', '-p', object)
  end
end
Also aliased as: object_contents
cat_file_size(object) click to toggle source

Get the size for the given object

@see git-scm.com/docs/git-cat-file git-cat-file

@param object [String] the object to get the type

@return [String] the object type

@raise [ArgumentError] if object is a string starting with a hyphen

# File lib/git/lib.rb, line 456
def cat_file_size(object)
  assert_args_are_not_options('object', object)

  command('cat-file', '-s', object).to_i
end
Also aliased as: object_size
cat_file_tag(object) click to toggle source

Return a hash of annotated tag data

Does not work with lightweight tags. List all annotated tags in your repository with the following command:

“‘sh git for-each-ref –format=’%(refname:strip=2)‘ refs/tags | \

while read tag; do git cat-file tag $tag >/dev/null 2>&1 && echo $tag; done

“‘

@see git-scm.com/docs/git-cat-file git-cat-file

@param object [String] the tag to retrieve

@return [Hash] tag data

Example tag data returned:
```ruby
{
  "name" => "annotated_tag",
  "object" => "46abbf07e3c564c723c7c039a43ab3a39e5d02dd",
  "type" => "commit",
  "tag" => "annotated_tag",
  "tagger" => "Scott Chacon <schacon@gmail.com> 1724799270 -0700",
  "message" => "Creating an annotated tag\n"
}
```

The returned commit data has the following keys:

* object [String] the sha of the tag object
* type [String]
* tag [String] tag name
* tagger [String] the name and email of the user who created the tag
  and the timestamp of when the tag was created
* message [String] the tag message

@raise [ArgumentError] if object is a string starting with a hyphen

# File lib/git/lib.rb, line 551
def cat_file_tag(object)
  assert_args_are_not_options('object', object)

  tdata = command_lines('cat-file', 'tag', object)
  process_tag_data(tdata, object)
end
Also aliased as: tag_data
cat_file_type(object) click to toggle source

Get the type for the given object

@see git-scm.com/docs/git-cat-file git-cat-file

@param object [String] the object to get the type

@return [String] the object type

@raise [ArgumentError] if object is a string starting with a hyphen

# File lib/git/lib.rb, line 438
def cat_file_type(object)
  assert_args_are_not_options('object', object)

  command('cat-file', '-t', object)
end
Also aliased as: object_type
change_head_branch(branch_name) click to toggle source
# File lib/git/lib.rb, line 666
def change_head_branch(branch_name)
  command('symbolic-ref', 'HEAD', "refs/heads/#{branch_name}")
end
checkout(branch = nil, opts = {}) click to toggle source

Runs checkout command to checkout or create branch

accepts options:

:new_branch
:force
:start_point

@param [String] branch @param [Hash] opts

# File lib/git/lib.rb, line 1232
def checkout(branch = nil, opts = {})
  if branch.is_a?(Hash) && opts.empty?
    opts = branch
    branch = nil
  end
  ArgsBuilder.validate!(opts, CHECKOUT_OPTION_MAP)

  flags = build_args(opts, CHECKOUT_OPTION_MAP)
  positional_args = build_checkout_positional_args(branch, opts)

  command('checkout', *flags, *positional_args)
end
checkout_file(version, file) click to toggle source
# File lib/git/lib.rb, line 1245
def checkout_file(version, file)
  arr_opts = []
  arr_opts << version
  arr_opts << file
  command('checkout', *arr_opts)
end
checkout_index(opts = {}) click to toggle source
# File lib/git/lib.rb, line 1487
def checkout_index(opts = {})
  ArgsBuilder.validate!(opts, CHECKOUT_INDEX_OPTION_MAP)
  args = build_args(opts, CHECKOUT_INDEX_OPTION_MAP)

  if (path = opts[:path_limiter]) && path.is_a?(String)
    args.push('--', path)
  end

  command('checkout-index', *args)
end
clean(opts = {}) click to toggle source
# File lib/git/lib.rb, line 1151
def clean(opts = {})
  args = build_args(opts, CLEAN_OPTION_MAP)
  command('clean', *args)
end
clone(repository_url, directory, opts = {}) click to toggle source

Clones a repository into a newly created directory

@param [String] repository_url the URL of the repository to clone

@param [String, nil] directory the directory to clone into

If nil, the repository is cloned into a directory with the same name as
the repository.

@param [Hash] opts the options for this command

@option opts [Boolean] :bare (false) if true, clone as a bare repository

@option opts [String] :branch the branch to checkout

@option opts [String, Array] :config one or more configuration options to set

@option opts [Integer] :depth the number of commits back to pull

@option opts [String] :filter specify partial clone

@option opts [String] :mirror set up a mirror of the source repository

@option opts [String] :origin the name of the remote

@option opts [String] :path an optional prefix for the directory parameter

@option opts [String] :remote the name of the remote

@option opts [Boolean] :recursive after the clone is created, initialize all

within, using their default settings

@option opts [Numeric, nil] :timeout the number of seconds to wait for the

command to complete

See {Git::Lib#command} for more information about :timeout

@return [Hash] the options to pass to {Git::Base.new}

@todo make this work with SSH password or auth_key

# File lib/git/lib.rb, line 149
def clone(repository_url, directory, opts = {})
  @path = opts[:path] || '.'
  clone_dir = opts[:path] ? File.join(@path, directory) : directory

  args = build_args(opts, CLONE_OPTION_MAP)
  args.push('--', repository_url, clone_dir)

  command('clone', *args, timeout: opts[:timeout])

  return_base_opts_from_clone(clone_dir, opts)
end
commit(message, opts = {}) click to toggle source

Takes the commit message with the options and executes the commit command

accepts options:

:amend
:all
:allow_empty
:author
:date
:no_verify
:allow_empty_message
:gpg_sign (accepts true or a gpg key ID as a String)
:no_gpg_sign (conflicts with :gpg_sign)

@param [String] message the commit message to be used @param [Hash] opts the commit options to be used

# File lib/git/lib.rb, line 1123
def commit(message, opts = {})
  opts[:message] = message if message # Handle message arg for backward compatibility

  # Perform cross-option validation before building args
  raise ArgumentError, 'cannot specify :gpg_sign and :no_gpg_sign' if opts[:gpg_sign] && opts[:no_gpg_sign]

  ArgsBuilder.validate!(opts, COMMIT_OPTION_MAP)

  args = build_args(opts, COMMIT_OPTION_MAP)
  command('commit', *args)
end
commit_data(object)
Alias for: cat_file_commit
commit_tree(tree, opts = {}) click to toggle source
# File lib/git/lib.rb, line 1468
def commit_tree(tree, opts = {})
  opts[:message] ||= "commit tree #{tree}"
  ArgsBuilder.validate!(opts, COMMIT_TREE_OPTION_MAP)

  flags = build_args(opts, COMMIT_TREE_OPTION_MAP)
  command('commit-tree', tree, *flags)
end
compare_version_to(*other_version) click to toggle source

Returns current_command_version <=> other_version

@example

lib.current_command_version #=> [2, 42, 0]

lib.compare_version_to(2, 41, 0) #=> 1
lib.compare_version_to(2, 42, 0) #=> 0
lib.compare_version_to(2, 43, 0) #=> -1

@param other_version [Array<Object>] the other version to compare to @return [Integer] -1 if this version is less than other_version, 0 if equal, or 1 if greater than

# File lib/git/lib.rb, line 1543
def compare_version_to(*other_version)
  current_command_version <=> other_version
end
config_get(name) click to toggle source
# File lib/git/lib.rb, line 972
def config_get(name)
  command('config', '--get', name, chdir: @git_dir)
end
config_list() click to toggle source
# File lib/git/lib.rb, line 980
def config_list
  parse_config_list command_lines('config', '--list', chdir: @git_dir)
end
config_remote(name) click to toggle source
# File lib/git/lib.rb, line 964
def config_remote(name)
  hsh = {}
  config_list.each do |key, value|
    hsh[key.gsub("remote.#{name}.", '')] = value if /remote.#{name}/.match(key)
  end
  hsh
end
config_set(name, value, options = {}) click to toggle source
# File lib/git/lib.rb, line 1020
def config_set(name, value, options = {})
  ArgsBuilder.validate!(options, CONFIG_SET_OPTION_MAP)
  flags = build_args(options, CONFIG_SET_OPTION_MAP)
  command('config', *flags, name, value)
end
conflicts() { |file, your, their| ... } click to toggle source
# File lib/git/lib.rb, line 1294
def conflicts # :yields: file, your, their
  unmerged.each do |file_path|
    Tempfile.create(['YOUR-', File.basename(file_path)]) do |your_file|
      write_staged_content(file_path, 2, your_file).flush

      Tempfile.create(['THEIR-', File.basename(file_path)]) do |their_file|
        write_staged_content(file_path, 3, their_file).flush
        yield(file_path, your_file.path, their_file.path)
      end
    end
  end
end
current_branch_state() click to toggle source

The current branch state which is the state of ‘HEAD`

@return [HeadState] the state and name of the current branch

# File lib/git/lib.rb, line 768
def current_branch_state
  branch_name = command('branch', '--show-current')
  return HeadState.new(:detached, 'HEAD') if branch_name.empty?

  state = get_branch_state(branch_name)
  HeadState.new(state, branch_name)
end
current_command_version() click to toggle source

returns the current version of git, as an Array of Fixnums.

# File lib/git/lib.rb, line 1524
def current_command_version
  output = command('version')
  version = output[/\d+(\.\d+)+/]
  version_parts = version.split('.').collect(&:to_i)
  version_parts.fill(0, version_parts.length...3)
end
describe(commit_ish = nil, opts = {}) click to toggle source

Finds most recent tag that is reachable from a commit

@see git-scm.com/docs/git-describe git-describe

@param commit_ish [String, nil] target commit sha or object name

@param opts [Hash] the given options

@option opts :all [Boolean] @option opts :tags [Boolean] @option opts :contains [Boolean] @option opts :debug [Boolean] @option opts :long [Boolean] @option opts :always [Boolean] @option opts :exact_match [Boolean] @option opts :dirty [true, String] @option opts :abbrev [String] @option opts :candidates [String] @option opts :match [String]

@return [String] the tag name

@raise [ArgumentError] if the commit_ish is a string starting with a hyphen

# File lib/git/lib.rb, line 228
def describe(commit_ish = nil, opts = {})
  assert_args_are_not_options('commit-ish object', commit_ish)

  args = build_args(opts, DESCRIBE_OPTION_MAP)
  args << commit_ish if commit_ish

  command('describe', *args)
end
diff_files() click to toggle source

compares the index and the working directory

# File lib/git/lib.rb, line 883
def diff_files
  diff_as_hash('diff-files')
end
diff_full(obj1 = 'HEAD', obj2 = nil, opts = {}) click to toggle source
# File lib/git/lib.rb, line 832
def diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})
  assert_args_are_not_options('commit or commit range', obj1, obj2)
  ArgsBuilder.validate!(opts, DIFF_FULL_OPTION_MAP)

  args = build_args(opts, DIFF_FULL_OPTION_MAP)
  args.push(obj1, obj2).compact!

  if (path = opts[:path_limiter]) && path.is_a?(String)
    args.push('--', path)
  end

  command('diff', *args)
end
diff_index(treeish) click to toggle source

compares the index and the repository

# File lib/git/lib.rb, line 888
def diff_index(treeish)
  diff_as_hash('diff-index', treeish)
end
diff_path_status(reference1 = nil, reference2 = nil, opts = {}) click to toggle source
# File lib/git/lib.rb, line 871
def diff_path_status(reference1 = nil, reference2 = nil, opts = {})
  assert_args_are_not_options('commit or commit range', reference1, reference2)
  ArgsBuilder.validate!(opts, DIFF_PATH_STATUS_OPTION_MAP)

  args = build_args(opts, DIFF_PATH_STATUS_OPTION_MAP)
  args.push(reference1, reference2).compact!
  args.push('--', opts[:path]) if opts[:path]

  parse_diff_path_status(args)
end
diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {}) click to toggle source
# File lib/git/lib.rb, line 851
def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
  assert_args_are_not_options('commit or commit range', obj1, obj2)
  ArgsBuilder.validate!(opts, DIFF_STATS_OPTION_MAP)

  args = build_args(opts, DIFF_STATS_OPTION_MAP)
  args.push(obj1, obj2).compact!

  if (path = opts[:path_limiter]) && path.is_a?(String)
    args.push('--', path)
  end

  output_lines = command_lines('diff', *args)
  parse_diff_stats_output(output_lines)
end
each_cat_file_header(data) { |key, join("\n")| ... } click to toggle source
# File lib/git/lib.rb, line 502
def each_cat_file_header(data)
  while (match = CAT_FILE_HEADER_LINE.match(data.shift))
    key = match[:key]
    value_lines = [match[:value]]

    value_lines << data.shift.lstrip while data.first.start_with?(' ')

    yield key, value_lines.join("\n")
  end
end
empty?() click to toggle source

Returns true if the repository is empty (meaning it has no commits)

@return [Boolean]

# File lib/git/lib.rb, line 1076
def empty?
  command('rev-parse', '--verify', 'HEAD')
  false
rescue Git::FailedError => e
  raise unless e.result.status.exitstatus == 128 &&
               e.result.stderr == 'fatal: Needed a single revision'

  true
end
fetch(remote, opts) click to toggle source
# File lib/git/lib.rb, line 1375
def fetch(remote, opts)
  ArgsBuilder.validate!(opts, FETCH_OPTION_MAP)
  args = build_args(opts, FETCH_OPTION_MAP)

  if remote || opts[:ref]
    args << '--'
    args << remote if remote
    args << opts[:ref] if opts[:ref]
  end

  command('fetch', *args, merge: true)
end
full_log_commits(opts = {}) click to toggle source

Return the commits that are within the given revision range

@see git-scm.com/docs/git-log git-log

@param opts [Hash] the given options

@option opts :count [Integer] the maximum number of commits to return (maps to

max-count)

@option opts :all [Boolean]

@option opts :cherry [Boolean]

@option opts :since [String]

@option opts :until [String]

@option opts :grep [String]

@option opts :author [String]

@option opts :between [Array<String>] an array of two commit-ish strings to

specify a revision range

Only :between or :object options can be used, not both.

@option opts :object [String] the revision range for the git log command

Only :between or :object options can be used, not both.

@option opts :path_limiter [Array<String>, String] only include commits that

impact files from the specified paths

@option opts :skip [Integer]

@return [Array<Hash>] the log output parsed into an array of hashs for each commit

Each hash contains the following keys:

* 'sha' [String] the commit sha
* 'author' [String] the author of the commit
* 'message' [String] the commit message
* 'parent' [Array<String>] the commit shas of the parent commits
* 'tree' [String] the tree sha
* 'author' [String] the author of the commit and timestamp of when the
  changes were created
* 'committer' [String] the committer of the commit and timestamp of when the
  commit was applied
* 'merges' [Boolean] if truthy, only include merge commits (aka commits with
  2 or more parents)

@raise [ArgumentError] if the revision range (specified with :between or

:object) is a string starting with a hyphen
# File lib/git/lib.rb, line 337
def full_log_commits(opts = {})
  assert_args_are_not_options('between', opts[:between]&.first)
  assert_args_are_not_options('object', opts[:object])

  args = log_common_options(opts)
  args += build_args(opts, FULL_LOG_EXTRA_OPTIONS_MAP)
  args += log_path_options(opts)

  full_log = command_lines('log', *args)
  process_commit_log_data(full_log)
end
full_tree(sha) click to toggle source
# File lib/git/lib.rb, line 658
def full_tree(sha)
  command_lines('ls-tree', '-r', sha)
end
gc() click to toggle source
# File lib/git/lib.rb, line 1445
def gc
  command('gc', '--prune', '--aggressive', '--auto')
end
global_config_get(name) click to toggle source
# File lib/git/lib.rb, line 976
def global_config_get(name)
  command('config', '--global', '--get', name)
end
global_config_list() click to toggle source
# File lib/git/lib.rb, line 984
def global_config_list
  parse_config_list command_lines('config', '--global', '--list')
end
global_config_set(name, value) click to toggle source
# File lib/git/lib.rb, line 1026
def global_config_set(name, value)
  command('config', '--global', name, value)
end
grep(string, opts = {}) click to toggle source

returns hash

tree-ish

[[line_no, match], [line_no, match2]] ↑

tree-ish

[[line_no, match], [line_no, match2]] ↑

# File lib/git/lib.rb, line 797
def grep(string, opts = {})
  opts[:object] ||= 'HEAD'
  ArgsBuilder.validate!(opts, GREP_OPTION_MAP)

  boolean_flags = build_args(opts, GREP_OPTION_MAP)
  args = ['-n', *boolean_flags, '-e', string, opts[:object]]

  if (limiter = opts[:path_limiter])
    args.push('--', *Array(limiter))
  end

  lines = execute_grep_command(args)
  parse_grep_output(lines)
end
ignored_files() click to toggle source
# File lib/git/lib.rb, line 954
def ignored_files
  command_lines('ls-files', '--others', '-i', '--exclude-standard').map { |f| unescape_quoted_path(f) }
end
init(opts = {}) click to toggle source

creates or reinitializes the repository

options:

:bare
:working_directory
:initial_branch
# File lib/git/lib.rb, line 88
def init(opts = {})
  args = build_args(opts, INIT_OPTION_MAP)
  command('init', *args)
end
list_files(ref_dir) click to toggle source
# File lib/git/lib.rb, line 735
def list_files(ref_dir)
  dir = File.join(@git_dir, 'refs', ref_dir)
  Dir.glob('**/*', base: dir).select { |f| File.file?(File.join(dir, f)) }
end
log_commits(opts = {}) click to toggle source

Return the commits that are within the given revision range

@see git-scm.com/docs/git-log git-log

@param opts [Hash] the given options

@option opts :count [Integer] the maximum number of commits to return (maps to max-count) @option opts :all [Boolean] @option opts :cherry [Boolean] @option opts :since [String] @option opts :until [String] @option opts :grep [String] @option opts :author [String] @option opts :between [Array<String>] an array of two commit-ish strings to specify a revision range

Only :between or :object options can be used, not both.

@option opts :object [String] the revision range for the git log command

Only :between or :object options can be used, not both.

@option opts :path_limiter [Array<String>, String] only include commits that impact files from the specified paths

@return [Array<String>] the log output

@raise [ArgumentError] if the resulting revision range is a string starting with a hyphen

# File lib/git/lib.rb, line 264
def log_commits(opts = {})
  assert_args_are_not_options('between', opts[:between]&.first)
  assert_args_are_not_options('object', opts[:object])

  arr_opts = log_common_options(opts)

  arr_opts << '--pretty=oneline'

  arr_opts += log_path_options(opts)

  command_lines('log', *arr_opts).map { |l| l.split.first }
end
ls_files(location = nil) click to toggle source

List all files that are in the index

@param location [String] the location to list the files from

@return [Hash<String, Hash>] a hash of files in the index

* key: file [String] the file path
* value: file_info [Hash] the file information containing the following keys:
  * :path [String] the file path
  * :mode_index [String] the file mode
  * :sha_index [String] the file sha
  * :stage [String] the file stage
# File lib/git/lib.rb, line 904
def ls_files(location = nil)
  location ||= '.'
  {}.tap do |files|
    command_lines('ls-files', '--stage', location).each do |line|
      (info, file) = split_status_line(line)
      (mode, sha, stage) = info.split
      files[file] = {
        path: file, mode_index: mode, sha_index: sha, stage: stage
      }
    end
  end
end
ls_remote(location = nil, opts = {}) click to toggle source
# File lib/git/lib.rb, line 944
def ls_remote(location = nil, opts = {})
  ArgsBuilder.validate!(opts, LS_REMOTE_OPTION_MAP)

  flags = build_args(opts, LS_REMOTE_OPTION_MAP)
  positional_arg = location || '.'

  output_lines = command_lines('ls-remote', *flags, positional_arg)
  parse_ls_remote_output(output_lines)
end
ls_tree(sha, opts = {}) click to toggle source
# File lib/git/lib.rb, line 638
def ls_tree(sha, opts = {})
  data = { 'blob' => {}, 'tree' => {}, 'commit' => {} }
  args = build_args(opts, LS_TREE_OPTION_MAP)

  args.unshift(sha)
  args << opts[:path] if opts[:path]

  command_lines('ls-tree', *args).each do |line|
    (info, filenm) = split_status_line(line)
    (mode, type, sha) = info.split
    data[type][filenm] = { mode: mode, sha: sha }
  end

  data
end
meets_required_version?() click to toggle source
# File lib/git/lib.rb, line 1551
def meets_required_version?
  (current_command_version <=> required_command_version) >= 0
end
merge(branch, message = nil, opts = {}) click to toggle source
# File lib/git/lib.rb, line 1258
def merge(branch, message = nil, opts = {})
  # For backward compatibility, treat the message arg as the :m option.
  opts[:m] = message if message
  ArgsBuilder.validate!(opts, MERGE_OPTION_MAP)

  args = build_args(opts, MERGE_OPTION_MAP)
  args.concat(Array(branch))

  command('merge', *args)
end
merge_base(*args) click to toggle source
# File lib/git/lib.rb, line 1276
def merge_base(*args)
  opts = args.last.is_a?(Hash) ? args.pop : {}
  ArgsBuilder.validate!(opts, MERGE_BASE_OPTION_MAP)

  flags = build_args(opts, MERGE_BASE_OPTION_MAP)
  command_args = flags + args

  command('merge-base', *command_args).lines.map(&:strip)
end
mv(file1, file2) click to toggle source
# File lib/git/lib.rb, line 654
def mv(file1, file2)
  command_lines('mv', '--', file1, file2)
end
name_rev(commit_ish) click to toggle source

Find the first symbolic name for given commit_ish

@param commit_ish [String] the commit_ish to find the symbolic name of

@return [String, nil] the first symbolic name or nil if the commit_ish isn’t found

@raise [ArgumentError] if the commit_ish is a string starting with a hyphen

# File lib/git/lib.rb, line 384
def name_rev(commit_ish)
  assert_args_are_not_options('commit_ish', commit_ish)

  command('name-rev', commit_ish).split[1]
end
Also aliased as: namerev
namerev(commit_ish)
Alias for: name_rev
object_contents(object)
Alias for: cat_file_contents
object_size(object)
Alias for: cat_file_size
object_type(object)
Alias for: cat_file_type
parse_config(file) click to toggle source
# File lib/git/lib.rb, line 997
def parse_config(file)
  parse_config_list command_lines('config', '--list', '--file', file)
end
parse_config_list(lines) click to toggle source
# File lib/git/lib.rb, line 988
def parse_config_list(lines)
  hsh = {}
  lines.each do |line|
    (key, *values) = line.split('=')
    hsh[key] = values.join('=')
  end
  hsh
end
process_commit_data(data, sha) click to toggle source
# File lib/git/lib.rb, line 491
def process_commit_data(data, sha)
  # process_commit_headers consumes the header lines from the `data` array,
  # leaving only the message lines behind.
  headers = process_commit_headers(data)
  message = "#{data.join("\n")}\n"

  { 'sha' => sha, 'message' => message }.merge(headers)
end
process_commit_log_data(data) click to toggle source
# File lib/git/lib.rb, line 572
def process_commit_log_data(data)
  RawLogParser.new(data).parse
end
process_tag_data(data, name) click to toggle source
# File lib/git/lib.rb, line 560
def process_tag_data(data, name)
  hsh = { 'name' => name }

  each_cat_file_header(data) do |key, value|
    hsh[key] = value
  end

  hsh['message'] = "#{data.join("\n")}\n"

  hsh
end
pull(remote = nil, branch = nil, opts = {}) click to toggle source
# File lib/git/lib.rb, line 1417
def pull(remote = nil, branch = nil, opts = {})
  raise ArgumentError, 'You must specify a remote if a branch is specified' if remote.nil? && !branch.nil?

  ArgsBuilder.validate!(opts, PULL_OPTION_MAP)

  flags = build_args(opts, PULL_OPTION_MAP)
  positional_args = [remote, branch].compact

  command('pull', *flags, *positional_args)
end
push(remote = nil, branch = nil, opts = nil) click to toggle source
# File lib/git/lib.rb, line 1397
def push(remote = nil, branch = nil, opts = nil)
  remote, branch, opts = normalize_push_args(remote, branch, opts)
  ArgsBuilder.validate!(opts, PUSH_OPTION_MAP)

  raise ArgumentError, 'remote is required if branch is specified' if !remote && branch

  args = build_push_args(remote, branch, opts)

  if opts[:mirror]
    command('push', *args)
  else
    command('push', *args)
    command('push', '--tags', *(args - [branch].compact)) if opts[:tags]
  end
end
read_tree(treeish, opts = {}) click to toggle source
# File lib/git/lib.rb, line 1453
def read_tree(treeish, opts = {})
  ArgsBuilder.validate!(opts, READ_TREE_OPTION_MAP)
  flags = build_args(opts, READ_TREE_OPTION_MAP)
  command('read-tree', *flags, treeish)
end
remote_add(name, url, opts = {}) click to toggle source
# File lib/git/lib.rb, line 1312
def remote_add(name, url, opts = {})
  ArgsBuilder.validate!(opts, REMOTE_ADD_OPTION_MAP)

  flags = build_args(opts, REMOTE_ADD_OPTION_MAP)
  positional_args = ['--', name, url]
  command_args = ['add'] + flags + positional_args

  command('remote', *command_args)
end
remote_remove(name) click to toggle source
# File lib/git/lib.rb, line 1330
def remote_remove(name)
  command('remote', 'rm', name)
end
remote_set_url(name, url) click to toggle source
# File lib/git/lib.rb, line 1322
def remote_set_url(name, url)
  arr_opts = ['set-url']
  arr_opts << name
  arr_opts << url

  command('remote', *arr_opts)
end
remotes() click to toggle source
# File lib/git/lib.rb, line 1334
def remotes
  command_lines('remote')
end
repack() click to toggle source
# File lib/git/lib.rb, line 1441
def repack
  command('repack', '-a', '-d')
end
repository_default_branch(repository) click to toggle source

Returns the name of the default branch of the given repository

@param repository [URI, Pathname, String] The (possibly remote) repository to clone from

@return [String] the name of the default branch

# File lib/git/lib.rb, line 167
def repository_default_branch(repository)
  output = command('ls-remote', '--symref', '--', repository, 'HEAD')

  match_data = output.match(%r{^ref: refs/remotes/origin/(?<default_branch>[^\t]+)\trefs/remotes/origin/HEAD$})
  return match_data[:default_branch] if match_data

  match_data = output.match(%r{^ref: refs/heads/(?<default_branch>[^\t]+)\tHEAD$})
  return match_data[:default_branch] if match_data

  raise Git::UnexpectedResultError, 'Unable to determine the default branch'
end
required_command_version() click to toggle source
# File lib/git/lib.rb, line 1547
def required_command_version
  [2, 28]
end
reset(commit, opts = {}) click to toggle source
# File lib/git/lib.rb, line 1138
def reset(commit, opts = {})
  args = build_args(opts, RESET_OPTION_MAP)
  args << commit if commit
  command('reset', *args)
end
rev_parse(revision) click to toggle source

Verify and resolve a Git revision to its full SHA

@see git-scm.com/docs/git-rev-parse git-rev-parse @see git-scm.com/docs/git-rev-parse#_specifying_revisions Valid ways to specify revisions @see git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt-emltrefnamegtemegemmasterememheadsmasterememrefsheadsmasterem

Ref disambiguation rules

@example

lib.rev_parse('HEAD') # => '9b9b31e704c0b85ffdd8d2af2ded85170a5af87d'
lib.rev_parse('9b9b31e') # => '9b9b31e704c0b85ffdd8d2af2ded85170a5af87d'

@param revision [String] the revision to resolve

@return [String] the full commit hash

@raise [Git::FailedError] if the revision cannot be resolved @raise [ArgumentError] if the revision is a string starting with a hyphen

# File lib/git/lib.rb, line 367
def rev_parse(revision)
  assert_args_are_not_options('rev', revision)

  command('rev-parse', '--revs-only', '--end-of-options', revision, '--')
end
Also aliased as: revparse
revert(commitish, opts = {}) click to toggle source
# File lib/git/lib.rb, line 1160
def revert(commitish, opts = {})
  # Forcing --no-edit as default since it's not an interactive session.
  opts = { no_edit: true }.merge(opts)

  args = build_args(opts, REVERT_OPTION_MAP)
  args << commitish

  command('revert', *args)
end
revparse(revision)

For backwards compatibility with the old method name

Alias for: rev_parse
rm(path = '.', opts = {}) click to toggle source
# File lib/git/lib.rb, line 1063
def rm(path = '.', opts = {})
  args = build_args(opts, RM_OPTION_MAP)

  args << '--'
  args.concat(Array(path))

  command('rm', *args)
end
show(objectish = nil, path = nil) click to toggle source

Shows objects

@param [String|NilClass] objectish the target object reference (nil == HEAD) @param [String|NilClass] path the path of the file to be shown @return [String] the object information

# File lib/git/lib.rb, line 1006
def show(objectish = nil, path = nil)
  arr_opts = []

  arr_opts << (path ? "#{objectish}:#{path}" : objectish)

  command('show', *arr_opts.compact, chomp: false)
end
stash_apply(id = nil) click to toggle source
# File lib/git/lib.rb, line 1193
def stash_apply(id = nil)
  if id
    command('stash', 'apply', id)
  else
    command('stash', 'apply')
  end
end
stash_clear() click to toggle source
# File lib/git/lib.rb, line 1201
def stash_clear
  command('stash', 'clear')
end
stash_list() click to toggle source
# File lib/git/lib.rb, line 1205
def stash_list
  command('stash', 'list')
end
stash_save(message) click to toggle source
# File lib/git/lib.rb, line 1188
def stash_save(message)
  output = command('stash', 'save', message)
  output =~ /HEAD is now at/
end
stashes_all() click to toggle source
# File lib/git/lib.rb, line 1182
def stashes_all
  stash_log_lines.each_with_index.map do |line, index|
    parse_stash_log_line(line, index)
  end
end
tag(name, *args) click to toggle source
# File lib/git/lib.rb, line 1350
def tag(name, *args)
  opts = args.last.is_a?(Hash) ? args.pop : {}
  target = args.first

  validate_tag_options!(opts)
  ArgsBuilder.validate!(opts, TAG_OPTION_MAP)

  flags = build_args(opts, TAG_OPTION_MAP)
  positional_args = [name, target].compact

  command('tag', *flags, *positional_args)
end
tag_data(object)
Alias for: cat_file_tag
tag_sha(tag_name) click to toggle source
# File lib/git/lib.rb, line 1428
def tag_sha(tag_name)
  head = File.join(@git_dir, 'refs', 'tags', tag_name)
  return File.read(head).chomp if File.exist?(head)

  begin
    command('show-ref', '--tags', '-s', tag_name)
  rescue Git::FailedError => e
    raise unless e.result.status.exitstatus == 1 && e.result.stderr == ''

    ''
  end
end
tags() click to toggle source
# File lib/git/lib.rb, line 1338
def tags
  command_lines('tag')
end
tree_depth(sha) click to toggle source
# File lib/git/lib.rb, line 662
def tree_depth(sha)
  full_tree(sha).size
end
unescape_quoted_path(path) click to toggle source

Unescape a path if it is quoted

Git commands that output paths (e.g. ls-files, diff), will escape unusual characters.

@example

lib.unescape_if_quoted('"quoted_file_\\342\\230\\240"') # => 'quoted_file_☠'
lib.unescape_if_quoted('unquoted_file')   # => 'unquoted_file'

@param path [String] the path to unescape if quoted

@return [String] the unescaped path if quoted otherwise the original path

@api private

# File lib/git/lib.rb, line 932
def unescape_quoted_path(path)
  if path.start_with?('"') && path.end_with?('"')
    Git::EscapedPath.new(path[1..-2]).unescape
  else
    path
  end
end
unmerged() click to toggle source
# File lib/git/lib.rb, line 1286
def unmerged
  unmerged = []
  command_lines('diff', '--cached').each do |line|
    unmerged << ::Regexp.last_match(1) if line =~ /^\* Unmerged path (.*)/
  end
  unmerged
end
untracked_files() click to toggle source
# File lib/git/lib.rb, line 958
def untracked_files
  command_lines('ls-files', '--others', '--exclude-standard', chdir: @git_work_dir).map do |f|
    unescape_quoted_path(f)
  end
end
update_ref(ref, commit) click to toggle source
# File lib/git/lib.rb, line 1476
def update_ref(ref, commit)
  command('update-ref', ref, commit)
end
worktree_add(dir, commitish = nil) click to toggle source
# File lib/git/lib.rb, line 721
def worktree_add(dir, commitish = nil)
  return command('worktree', 'add', dir, commitish) unless commitish.nil?

  command('worktree', 'add', dir)
end
worktree_prune() click to toggle source
# File lib/git/lib.rb, line 731
def worktree_prune
  command('worktree', 'prune')
end
worktree_remove(dir) click to toggle source
# File lib/git/lib.rb, line 727
def worktree_remove(dir)
  command('worktree', 'remove', dir)
end
worktrees_all() click to toggle source
# File lib/git/lib.rb, line 701
def worktrees_all
  arr = []
  directory = ''
  # Output example for `worktree list --porcelain`:
  # worktree /code/public/ruby-git
  # HEAD 4bef5abbba073c77b4d0ccc1ffcd0ed7d48be5d4
  # branch refs/heads/master
  #
  # worktree /tmp/worktree-1
  # HEAD b8c63206f8d10f57892060375a86ae911fad356e
  # detached
  #
  command_lines('worktree', 'list', '--porcelain').each do |w|
    s = w.split
    directory = s[1] if s[0] == 'worktree'
    arr << [directory, s[1]] if s[0] == 'HEAD'
  end
  arr
end
write_tree() click to toggle source
# File lib/git/lib.rb, line 1459
def write_tree
  command('write-tree')
end

Private Instance Methods

apply_gzip(file) click to toggle source
# File lib/git/lib.rb, line 1871
def apply_gzip(file)
  file_content = File.read(file)
  Zlib::GzipWriter.open(file) { |gz| gz.write(file_content) }
end
build_args(opts, option_map) click to toggle source
# File lib/git/lib.rb, line 1623
def build_args(opts, option_map)
  Git::ArgsBuilder.new(opts, option_map).build
end
build_checkout_positional_args(branch, opts) click to toggle source
# File lib/git/lib.rb, line 1612
def build_checkout_positional_args(branch, opts)
  args = []
  if opts[:new_branch] || opts[:b]
    args.push('-b', branch)
    args << opts[:start_point] if opts[:start_point]
  elsif branch
    args << branch
  end
  args
end
build_files_hash(file_stats) click to toggle source
# File lib/git/lib.rb, line 1765
def build_files_hash(file_stats)
  file_stats.to_h { |s| [s[:filename], s.slice(:insertions, :deletions)] }
end
build_final_stats_hash(file_stats) click to toggle source
# File lib/git/lib.rb, line 1747
def build_final_stats_hash(file_stats)
  {
    total: build_total_stats(file_stats),
    files: build_files_hash(file_stats)
  }
end
build_push_args(remote, branch, opts) click to toggle source
# File lib/git/lib.rb, line 1846
def build_push_args(remote, branch, opts)
  # Build the simple flags using the ArgsBuilder
  args = build_args(opts, PUSH_OPTION_MAP)

  # Manually handle the flag with external dependencies and positional args
  args << '--all' if opts[:all] && remote
  args << remote if remote
  args << branch if branch
  args
end
build_total_stats(file_stats) click to toggle source
# File lib/git/lib.rb, line 1754
def build_total_stats(file_stats)
  insertions = file_stats.sum { |s| s[:insertions] }
  deletions = file_stats.sum { |s| s[:deletions] }
  {
    insertions: insertions,
    deletions: deletions,
    lines: insertions + deletions,
    files: file_stats.size
  }
end
command(*, **options_hash) click to toggle source

Runs a git command and returns the output

Additional args are passed to the command line. They should exclude the ‘git’ command itself and global options. Remember to splat the the arguments if given as an array.

For example, to run ‘git log –pretty=oneline`, you would create the array `args = [’log’, ‘–pretty=oneline’]‘ and call `command(*args)`.

@param options_hash [Hash] the options to pass to the command @option options_hash [IO, String, write, nil] :out the destination for captured stdout @option options_hash [IO, String, write, nil] :err the destination for captured stderr @option options_hash [Boolean] :normalize true to normalize the output encoding to UTF-8 @option options_hash [Boolean] :chomp true to remove trailing newlines from the output @option options_hash [Boolean] :merge true to merge stdout and stderr into a single output @option options_hash [String, nil] :chdir the directory to run the command in @option options_hash [Numeric, nil] :timeout the maximum seconds to wait for the command to complete

If timeout is nil, the global timeout from {Git::Config} is used.

If timeout is zero, the timeout will not be enforced.

If the command times out, it is killed via a `SIGKILL` signal and `Git::TimeoutError` is raised.

If the command does not respond to SIGKILL, it will hang this method.

@see Git::CommandLine#run

@return [String] the command’s stdout (or merged stdout and stderr if ‘merge` is true)

@raise [ArgumentError] if an unknown option is passed

@raise [Git::FailedError] if the command failed

@raise [Git::SignaledError] if the command was signaled

@raise [Git::TimeoutError] if the command times out

@raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output

The exception's `result` attribute is a {Git::CommandLineResult} which will
contain the result of the command including the exit status, stdout, and
stderr.

@api private

# File lib/git/lib.rb, line 1956
def command(*, **options_hash)
  options_hash = COMMAND_ARG_DEFAULTS.merge(options_hash)
  options_hash[:timeout] ||= Git.config.timeout

  extra_options = options_hash.keys - COMMAND_ARG_DEFAULTS.keys
  raise ArgumentError, "Unknown options: #{extra_options.join(', ')}" if extra_options.any?

  result = command_line.run(*, **options_hash)
  result.stdout
end
command_line() click to toggle source
# File lib/git/lib.rb, line 1904
def command_line
  @command_line ||=
    Git::CommandLine.new(env_overrides, Git::Base.config.binary_path, global_opts, @logger)
end
command_lines(cmd, *opts, chdir: nil) click to toggle source
# File lib/git/lib.rb, line 1876
def command_lines(cmd, *opts, chdir: nil)
  cmd_op = command(cmd, *opts, chdir: chdir)
  op = if cmd_op.encoding.name == 'UTF-8'
         cmd_op
       else
         cmd_op.encode('UTF-8', 'binary', invalid: :replace, undef: :replace)
       end
  op.split("\n")
end
diff_as_hash(diff_command, opts = []) click to toggle source

Takes the diff command line output (as Array) and parse it into a Hash

@param [String] diff_command the diff commadn to be used @param [Array] opts the diff options to be used @return [Hash] the diff as Hash

# File lib/git/lib.rb, line 1972
def diff_as_hash(diff_command, opts = [])
  # update index before diffing to avoid spurious diffs
  command('status')
  command_lines(diff_command, *opts).each_with_object({}) do |line, memo|
    info, file = split_status_line(line)
    mode_src, mode_dest, sha_src, sha_dest, type = info.split

    memo[file] = {
      mode_index: mode_dest, mode_repo: mode_src.to_s[1, 7],
      path: file, sha_repo: sha_src, sha_index: sha_dest,
      type: type
    }
  end
end
env_overrides() click to toggle source
# File lib/git/lib.rb, line 1886
def env_overrides
  {
    'GIT_DIR' => @git_dir,
    'GIT_WORK_TREE' => @git_work_dir,
    'GIT_INDEX_FILE' => @git_index_file,
    'GIT_SSH' => Git::Base.config.git_ssh,
    'LC_ALL' => 'en_US.UTF-8'
  }
end
execute_grep_command(args) click to toggle source
# File lib/git/lib.rb, line 1706
def execute_grep_command(args)
  command_lines('grep', *args)
rescue Git::FailedError => e
  # `git grep` returns 1 when no lines are selected.
  raise unless e.result.status.exitstatus == 1 && e.result.stderr.empty?

  [] # Return an empty array for "no matches found"
end
format_branch_data(match_data) click to toggle source
# File lib/git/lib.rb, line 1674
def format_branch_data(match_data)
  [
    match_data[:refname],
    !match_data[:current].nil?,
    !match_data[:worktree].nil?,
    match_data[:symref]
  ]
end
get_branch_state(branch_name) click to toggle source
# File lib/git/lib.rb, line 1695
def get_branch_state(branch_name)
  command('rev-parse', '--verify', '--quiet', branch_name)
  :active
rescue Git::FailedError => e
  # An exit status of 1 with empty stderr from `rev-parse --verify`
  # indicates a ref that exists but does not yet point to a commit.
  raise unless e.result.status.exitstatus == 1 && e.result.stderr.empty?

  :unborn
end
global_opts() click to toggle source
# File lib/git/lib.rb, line 1896
def global_opts
  [].tap do |global_opts|
    global_opts << "--git-dir=#{@git_dir}" unless @git_dir.nil?
    global_opts << "--work-tree=#{@git_work_dir}" unless @git_work_dir.nil?
    global_opts.concat(STATIC_GLOBAL_OPTS)
  end
end
initialize_from_base(base_object) click to toggle source
# File lib/git/lib.rb, line 1627
def initialize_from_base(base_object)
  @git_dir = base_object.repo.path
  @git_index_file = base_object.index&.path
  @git_work_dir = base_object.dir&.path
end
initialize_from_hash(base_hash) click to toggle source
# File lib/git/lib.rb, line 1633
def initialize_from_hash(base_hash)
  @git_dir = base_hash[:repository]
  @git_index_file = base_hash[:index]
  @git_work_dir = base_hash[:working_directory]
end
log_common_options(opts) click to toggle source

Returns an array holding the common options for the log commands

@param [Hash] opts the given options @return [Array] the set of common options that the log command will use

# File lib/git/lib.rb, line 1991
def log_common_options(opts)
  if opts[:count] && !opts[:count].is_a?(Integer)
    raise ArgumentError, "The log count option must be an Integer but was #{opts[:count].inspect}"
  end

  build_args(opts, LOG_OPTION_MAP)
end
log_path_options(opts) click to toggle source

Retrurns an array holding path options for the log commands

@param [Hash] opts the given options @return [Array] the set of path options that the log command will use

# File lib/git/lib.rb, line 2003
def log_path_options(opts)
  arr_opts = []

  arr_opts << opts[:object] if opts[:object].is_a? String
  if opts[:path_limiter]
    arr_opts << '--'
    arr_opts += Array(opts[:path_limiter])
  end
  arr_opts
end
match_branch_line(line, index, all_lines) click to toggle source
# File lib/git/lib.rb, line 1667
def match_branch_line(line, index, all_lines)
  match_data = line.match(BRANCH_LINE_REGEXP)
  raise Git::UnexpectedResultError, unexpected_branch_line_error(all_lines, line, index) unless match_data

  match_data
end
normalize_push_args(remote, branch, opts) click to toggle source
# File lib/git/lib.rb, line 1831
def normalize_push_args(remote, branch, opts)
  if branch.is_a?(Hash)
    opts = branch
    branch = nil
  elsif remote.is_a?(Hash)
    opts = remote
    remote = nil
  end

  opts ||= {}
  # Backwards compatibility for `push(remote, branch, true)`
  opts = { tags: opts } if [true, false].include?(opts)
  [remote, branch, opts]
end
parse_archive_format_options(opts) click to toggle source
# File lib/git/lib.rb, line 1864
def parse_archive_format_options(opts)
  format = opts[:format] || 'zip'
  gzip = opts[:add_gzip] == true || format == 'tgz'
  format = 'tar' if format == 'tgz'
  [format, gzip]
end
parse_branch_line(line, index, all_lines) click to toggle source
# File lib/git/lib.rb, line 1659
def parse_branch_line(line, index, all_lines)
  match_data = match_branch_line(line, index, all_lines)

  return nil if match_data[:not_a_branch] || match_data[:detached_ref]

  format_branch_data(match_data)
end
parse_diff_path_status(args) click to toggle source
# File lib/git/lib.rb, line 1605
def parse_diff_path_status(args)
  command_lines('diff', *args).each_with_object({}) do |line, memo|
    status, path = split_status_line(line)
    memo[path] = status
  end
end
parse_diff_stats_output(lines) click to toggle source
# File lib/git/lib.rb, line 1725
def parse_diff_stats_output(lines)
  file_stats = parse_stat_lines(lines)
  build_final_stats_hash(file_stats)
end
parse_grep_output(lines) click to toggle source
# File lib/git/lib.rb, line 1715
def parse_grep_output(lines)
  lines.each_with_object(Hash.new { |h, k| h[k] = [] }) do |line, hsh|
    match = line.match(/\A(.*?):(\d+):(.*)/)
    next unless match

    _full, filename, line_num, text = match.to_a
    hsh[filename] << [line_num.to_i, text]
  end
end
parse_ls_remote_line(line) click to toggle source
# File lib/git/lib.rb, line 1780
def parse_ls_remote_line(line)
  sha, info = line.split("\t", 2)
  ref, type, name = info.split('/', 3)

  type ||= 'head'
  type = 'branches' if type == 'heads'

  value = { ref: ref, sha: sha }

  [type, name, value]
end
parse_ls_remote_output(lines) click to toggle source
# File lib/git/lib.rb, line 1769
def parse_ls_remote_output(lines)
  lines.each_with_object(Hash.new { |h, k| h[k] = {} }) do |line, hsh|
    type, name, value = parse_ls_remote_line(line)
    if name
      hsh[type][name] = value
    else # Handles the HEAD entry, which has no name
      hsh[type].update(value)
    end
  end
end
parse_stash_log_line(line, index) click to toggle source
# File lib/git/lib.rb, line 1799
def parse_stash_log_line(line, index)
  full_message = line.split("\t", 2).last
  match_data = full_message.match(/^[^:]+:(.*)$/)
  message = match_data ? match_data[1] : full_message

  [index, message.strip]
end
parse_stat_lines(lines) click to toggle source
# File lib/git/lib.rb, line 1730
def parse_stat_lines(lines)
  lines.map do |line|
    insertions_s, deletions_s, filename = split_status_line(line)
    {
      filename: filename,
      insertions: insertions_s.to_i,
      deletions: deletions_s.to_i
    }
  end
end
process_commit_headers(data) click to toggle source
# File lib/git/lib.rb, line 1647
def process_commit_headers(data)
  headers = { 'parent' => [] } # Pre-initialize for multiple parents
  each_cat_file_header(data) do |key, value|
    if key == 'parent'
      headers['parent'] << value
    else
      headers[key] = value
    end
  end
  headers
end
return_base_opts_from_clone(clone_dir, opts) click to toggle source
# File lib/git/lib.rb, line 1639
def return_base_opts_from_clone(clone_dir, opts)
  base_opts = {}
  base_opts[:repository] = clone_dir if opts[:bare] || opts[:mirror]
  base_opts[:working_directory] = clone_dir unless opts[:bare] || opts[:mirror]
  base_opts[:log] = opts[:log] if opts[:log]
  base_opts
end
split_status_line(line) click to toggle source
# File lib/git/lib.rb, line 1741
def split_status_line(line)
  parts = line.split("\t")
  parts[-1] = unescape_quoted_path(parts[-1]) if parts.any?
  parts
end
stash_log_lines() click to toggle source
# File lib/git/lib.rb, line 1792
def stash_log_lines
  path = File.join(@git_dir, 'logs/refs/stash')
  return [] unless File.exist?(path)

  File.readlines(path, chomp: true)
end
temp_file_name() click to toggle source
# File lib/git/lib.rb, line 1857
def temp_file_name
  tempfile = Tempfile.new('archive')
  file = tempfile.path
  tempfile.close! # Prevents Ruby from deleting the file on garbage collection
  file
end
unexpected_branch_line_error(lines, line, index) click to toggle source
# File lib/git/lib.rb, line 1683
    def unexpected_branch_line_error(lines, line, index)
      <<~ERROR
        Unexpected line in output from `git branch -a`, line #{index + 1}

        Full output:
          #{lines.join("\n  ")}

        Line #{index + 1}:
          "#{line}"
      ERROR
    end
validate_tag_options!(opts) click to toggle source
# File lib/git/lib.rb, line 1822
def validate_tag_options!(opts)
  is_annotated = opts[:a] || opts[:annotate]
  has_message = opts[:m] || opts[:message]

  return unless is_annotated && !has_message

  raise ArgumentError, 'Cannot create an annotated tag without a message.'
end
write_staged_content(path, stage, out_io) click to toggle source

Writes the staged content of a conflicted file to an IO stream

@param path [String] the path to the file in the index

@param stage [Integer] the stage of the file to show (e.g., 2 for ‘ours’, 3 for ‘theirs’)

@param out_io [IO] the IO object to write the staged content to

@return [IO] the IO object that was written to

# File lib/git/lib.rb, line 1817
def write_staged_content(path, stage, out_io)
  command('show', ":#{stage}:#{path}", out: out_io)
  out_io
end