Class: Git::Lib

Inherits:
Object
  • Object
show all
Defined in:
lib/git/lib.rb

Defined Under Namespace

Classes: HeadState

Constant Summary collapse

CAT_FILE_HEADER_LINE =
/\A(?<key>\w+) (?<value>.*)\z/
BRANCH_LINE_REGEXP =
/
  ^
    # Prefix indicates if this branch is checked out. The prefix is one of:
    (?:
      (?<current>\*[[:blank:]]) |  # Current branch (checked out in the current worktree)
      (?<worktree>\+[[:blank:]]) | # Branch checked out in a different worktree
      [[:blank:]]{2}               # Branch not checked out
    )

    # The branch's full refname
    (?:
      (?<not_a_branch>\(not[[:blank:]]a[[:blank:]]branch\)) |
      (?:\(HEAD[[:blank:]]detached[[:blank:]]at[[:blank:]](?<detached_ref>[^\)]+)\)) |
      (?<refname>[^[[:blank:]]]+)
    )

    # Optional symref
    # If this ref is a symbolic reference, this is the ref referenced
    (?:
      [[:blank:]]->[[:blank:]](?<symref>.*)
    )?
  $
/x

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base, logger) ⇒ Lib #initialize(base, logger) ⇒ Lib

Create a new Git::Lib object

Overloads:

  • #initialize(base, logger) ⇒ Lib

    Parameters:

    • base (Hash)

      the hash containing paths to the Git working copy, the Git repository directory, and the Git index file.

    • logger (Logger)

    Options Hash (base):

    • :working_directory (Pathname)
    • :repository (Pathname)
    • :index (Pathname)
  • #initialize(base, logger) ⇒ Lib

    Parameters:

    • 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).

    • logger (Logger)
[View source]

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/git/lib.rb', line 61

def initialize(base = nil, logger = nil)
  @git_dir = nil
  @git_index_file = nil
  @git_work_dir = nil
  @path = nil
  @logger = logger || Logger.new(nil)

  if base.is_a?(Git::Base)
    @git_dir = base.repo.path
    @git_index_file = base.index.path if base.index
    @git_work_dir = base.dir.path if base.dir
  elsif base.is_a?(Hash)
    @git_dir = base[:repository]
    @git_index_file = base[:index]
    @git_work_dir = base[:working_directory]
  end
end

Instance Attribute Details

#git_dirPathname (readonly)

The path to the Git repository directory. The default is "#{git_work_dir}/.git".

Returns:

  • (Pathname)

    the Git repository directory.

See Also:

  • repository](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefrepositoryarepository)

30
31
32
# File 'lib/git/lib.rb', line 30

def git_dir
  @git_dir
end

#git_index_filePathname (readonly)

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

Returns:

  • (Pathname)

    the Git index file

See Also:

  • index file](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefindexaindex)

39
40
41
# File 'lib/git/lib.rb', line 39

def git_index_file
  @git_index_file
end

#git_work_dirPathname (readonly)

The path to the Git working copy. The default is '"./.git"'.

Returns:

  • (Pathname)

    the path to the Git working copy.

See Also:

  • working tree](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefworkingtreeaworkingtree)

21
22
23
# File 'lib/git/lib.rb', line 21

def git_work_dir
  @git_work_dir
end

Class Method Details

.warn_if_old_command(lib)

[View source]

1524
1525
1526
1527
1528
1529
1530
1531
# File 'lib/git/lib.rb', line 1524

def self.warn_if_old_command(lib)
  return true if @version_checked
  @version_checked = true
  unless lib.meets_required_version?
    $stderr.puts "[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

Instance Method Details

#add(paths = '.', options = {})

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

Examples:

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

Parameters:

  • paths (String, Array<String>) (defaults to: '.')

    files to be added to the repository (relative to the worktree root)

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :all (Boolean)

    Add, modify, and remove index entries to match the worktree

  • :force (Boolean)

    Allow adding otherwise ignored files

[View source]

1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
# File 'lib/git/lib.rb', line 1028

def add(paths='.',options={})
  arr_opts = []

  arr_opts << '--all' if options[:all]
  arr_opts << '--force' if options[:force]

  arr_opts << '--'

  arr_opts << paths

  arr_opts.flatten!

  command('add', *arr_opts)
end

#apply(patch_file)

[View source]

1136
1137
1138
1139
1140
# File 'lib/git/lib.rb', line 1136

def apply(patch_file)
  arr_opts = []
  arr_opts << '--' << patch_file if patch_file
  command('apply', *arr_opts)
end

#apply_mail(patch_file)

[View source]

1142
1143
1144
1145
1146
# File 'lib/git/lib.rb', line 1142

def apply_mail(patch_file)
  arr_opts = []
  arr_opts << '--' << patch_file if patch_file
  command('am', *arr_opts)
end

#archive(sha, file = nil, opts = {})

creates an archive file

options :format (zip, tar) :prefix :remote :path

[View source]

1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
# File 'lib/git/lib.rb', line 1456

def archive(sha, file = nil, opts = {})
  opts[:format] ||= 'zip'

  if opts[:format] == 'tgz'
    opts[:format] = 'tar'
    opts[:add_gzip] = true
  end

  if !file
    tempfile = Tempfile.new('archive')
    file = tempfile.path
    # delete it now, before we write to it, so that Ruby doesn't delete it
    # when it finalizes the Tempfile.
    tempfile.close!
  end

  arr_opts = []
  arr_opts << "--format=#{opts[:format]}" if opts[:format]
  arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
  arr_opts << "--remote=#{opts[:remote]}" if opts[:remote]
  arr_opts << sha
  arr_opts << '--' << opts[:path] if opts[:path]

  f = File.open(file, 'wb')
  command('archive', *arr_opts, out: f)
  f.close

  if opts[:add_gzip]
    file_content = File.read(file)
    Zlib::GzipWriter.open(file) do |gz|
      gz.write(file_content)
    end
  end
  return file
end

#assert_args_are_not_options(arg_name, *args)

This method returns an undefined value.

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

Parameters:

  • arg_name (String)

    the name of the arguments to mention in the error message

  • args (Array<String, nil>)

    the arguments to validate

Raises:

  • (ArgumentError)

    if any of the parameters are a string starting with a hyphen

[View source]

809
810
811
812
813
814
# File 'lib/git/lib.rb', line 809

def assert_args_are_not_options(arg_name, *args)
  invalid_args = args.select { |arg| arg&.start_with?('-') }
  if invalid_args.any?
    raise ArgumentError, "Invalid #{arg_name}: '#{invalid_args.join("', '")}'"
  end
end

#branch_contains(commit, branch_name = "")

[View source]

767
768
769
# File 'lib/git/lib.rb', line 767

def branch_contains(commit, branch_name="")
  command("branch",  branch_name, "--contains", commit)
end

#branch_current

[View source]

762
763
764
765
# File 'lib/git/lib.rb', line 762

def branch_current
  branch_name = command('branch', '--show-current')
  branch_name.empty? ? 'HEAD' : branch_name
end

#branch_delete(branch)

[View source]

1189
1190
1191
# File 'lib/git/lib.rb', line 1189

def branch_delete(branch)
  command('branch', '-D', branch)
end

#branch_new(branch)

[View source]

1185
1186
1187
# File 'lib/git/lib.rb', line 1185

def branch_new(branch)
  command('branch', branch)
end

#branches_all

[View source]

645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
# File 'lib/git/lib.rb', line 645

def branches_all
  lines = command_lines('branch', '-a')
  lines.each_with_index.map do |line, line_index|
    match_data = line.match(BRANCH_LINE_REGEXP)

    raise Git::UnexpectedResultError, unexpected_branch_line_error(lines, line, line_index) unless match_data
    next nil if match_data[:not_a_branch] || match_data[:detached_ref]

    [
      match_data[:refname],
      !match_data[:current].nil?,
      !match_data[:worktree].nil?,
      match_data[:symref]
    ]
  end.compact
end

#cat_file_commit(object) ⇒ Hash Also known as: commit_data

Return a hash of commit data

The returned commit data has the following keys:

  • tree [String]
  • parent [Array]
  • 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)

Parameters:

  • object (String)

    the object to get the type

Returns:

  • (Hash)

    commit data

Raises:

  • (ArgumentError)

    if object is a string starting with a hyphen

See Also:

[View source]

448
449
450
451
452
453
# File 'lib/git/lib.rb', line 448

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

#cat_file_contents(object, &block) ⇒ String Also known as: object_contents

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

Examples:

Get the contents of a file without a block

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

Get the contents of a file with a block

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

Parameters:

  • object (String)

    the object whose contents to return

Returns:

  • (String)

    the object contents

Raises:

  • (ArgumentError)

    if object is a string starting with a hyphen

See Also:

[View source]

374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/git/lib.rb', line 374

def cat_file_contents(object, &block)
  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

#cat_file_size(object) ⇒ String Also known as: object_size

Get the size for the given object

Parameters:

  • object (String)

    the object to get the type

Returns:

  • (String)

    the object type

Raises:

  • (ArgumentError)

    if object is a string starting with a hyphen

See Also:

[View source]

422
423
424
425
426
# File 'lib/git/lib.rb', line 422

def cat_file_size(object)
  assert_args_are_not_options('object', object)

  command('cat-file', '-s', object).to_i
end

#cat_file_tag(object) ⇒ Hash Also known as: tag_data

Return a hash of annotated tag data

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

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

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

Parameters:

  • object (String)

    the tag to retrieve

Returns:

  • (Hash)

    tag data

    Example tag data returned:

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

Raises:

  • (ArgumentError)

    if object is a string starting with a hyphen

See Also:

[View source]

526
527
528
529
530
531
# File 'lib/git/lib.rb', line 526

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

#cat_file_type(object) ⇒ String Also known as: object_type

Get the type for the given object

Parameters:

  • object (String)

    the object to get the type

Returns:

  • (String)

    the object type

Raises:

  • (ArgumentError)

    if object is a string starting with a hyphen

See Also:

[View source]

404
405
406
407
408
# File 'lib/git/lib.rb', line 404

def cat_file_type(object)
  assert_args_are_not_options('object', object)

  command('cat-file', '-t', object)
end

#change_head_branch(branch_name)

[View source]

617
618
619
# File 'lib/git/lib.rb', line 617

def change_head_branch(branch_name)
  command('symbolic-ref', 'HEAD', "refs/heads/#{branch_name}")
end

#checkout(branch = nil, opts = {})

Runs checkout command to checkout or create branch

accepts options: :new_branch :force :start_point

Parameters:

  • branch (String) (defaults to: nil)
  • opts (Hash) (defaults to: {})
[View source]

1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
# File 'lib/git/lib.rb', line 1202

def checkout(branch = nil, opts = {})
  if branch.is_a?(Hash) && opts == {}
    opts = branch
    branch = nil
  end

  arr_opts = []
  arr_opts << '-b' if opts[:new_branch] || opts[:b]
  arr_opts << '--force' if opts[:force] || opts[:f]
  arr_opts << branch if branch
  arr_opts << opts[:start_point] if opts[:start_point] && arr_opts.include?('-b')

  command('checkout', *arr_opts)
end

#checkout_file(version, file)

[View source]

1217
1218
1219
1220
1221
1222
# File 'lib/git/lib.rb', line 1217

def checkout_file(version, file)
  arr_opts = []
  arr_opts << version
  arr_opts << file
  command('checkout', *arr_opts)
end

#checkout_index(opts = {})

[View source]

1439
1440
1441
1442
1443
1444
1445
1446
1447
# File 'lib/git/lib.rb', line 1439

def checkout_index(opts = {})
  arr_opts = []
  arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
  arr_opts << "--force" if opts[:force]
  arr_opts << "--all" if opts[:all]
  arr_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String

  command('checkout-index', *arr_opts)
end

#clean(opts = {})

[View source]

1115
1116
1117
1118
1119
1120
1121
1122
1123
# File 'lib/git/lib.rb', line 1115

def clean(opts = {})
  arr_opts = []
  arr_opts << '--force' if opts[:force]
  arr_opts << '-ff' if opts[:ff]
  arr_opts << '-d' if opts[:d]
  arr_opts << '-x' if opts[:x]

  command('clean', *arr_opts)
end

#clone(repository_url, directory, opts = {}) ⇒ Hash

TODO:

make this work with SSH password or auth_key

Clones a repository into a newly created directory

Parameters:

  • repository_url (String)

    the URL of the repository to clone

  • directory (String, nil)

    the directory to clone into

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

  • opts (Hash) (defaults to: {})

    the options for this command

Options Hash (opts):

  • :bare (Boolean) — default: false

    if true, clone as a bare repository

  • :branch (String)

    the branch to checkout

  • :config (String, Array)

    one or more configuration options to set

  • :depth (Integer)

    the number of commits back to pull

  • :filter (String)

    specify partial clone

  • :mirror (String)

    set up a mirror of the source repository

  • :origin (String)

    the name of the remote

  • :path (String)

    an optional prefix for the directory parameter

  • :remote (String)

    the name of the remote

  • :recursive (Boolean)

    after the clone is created, initialize all submodules within, using their default settings

  • :timeout (Numeric, nil)

    the number of seconds to wait for the command to complete

    See #command for more information about :timeout

Returns:

  • (Hash)

    the options to pass to Base.new

[View source]

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/git/lib.rb', line 122

def clone(repository_url, directory, opts = {})
  @path = opts[:path] || '.'
  clone_dir = opts[:path] ? File.join(@path, directory) : directory

  arr_opts = []
  arr_opts << '--bare' if opts[:bare]
  arr_opts << '--branch' << opts[:branch] if opts[:branch]
  arr_opts << '--depth' << opts[:depth].to_i if opts[:depth] && opts[:depth].to_i > 0
  arr_opts << '--filter' << opts[:filter] if opts[:filter]
  Array(opts[:config]).each { |c| arr_opts << '--config' << c }
  arr_opts << '--origin' << opts[:remote] || opts[:origin] if opts[:remote] || opts[:origin]
  arr_opts << '--recursive' if opts[:recursive]
  arr_opts << '--mirror' if opts[:mirror]

  arr_opts << '--'

  arr_opts << repository_url
  arr_opts << clone_dir

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

  return_base_opts_from_clone(clone_dir, opts)
end

#commit(message, opts = {})

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)

Parameters:

  • message (String)

    the commit message to be used

  • opts (Hash) (defaults to: {})

    the commit options to be used

[View source]

1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
# File 'lib/git/lib.rb', line 1081

def commit(message, opts = {})
  arr_opts = []
  arr_opts << "--message=#{message}" if message
  arr_opts << '--amend' << '--no-edit' if opts[:amend]
  arr_opts << '--all' if opts[:add_all] || opts[:all]
  arr_opts << '--allow-empty' if opts[:allow_empty]
  arr_opts << "--author=#{opts[:author]}" if opts[:author]
  arr_opts << "--date=#{opts[:date]}" if opts[:date].is_a? String
  arr_opts << '--no-verify' if opts[:no_verify]
  arr_opts << '--allow-empty-message' if opts[:allow_empty_message]

  if opts[:gpg_sign] && opts[:no_gpg_sign]
    raise ArgumentError, 'cannot specify :gpg_sign and :no_gpg_sign'
  elsif opts[:gpg_sign]
    arr_opts <<
      if opts[:gpg_sign] == true
        '--gpg-sign'
      else
        "--gpg-sign=#{opts[:gpg_sign]}"
      end
  elsif opts[:no_gpg_sign]
    arr_opts << '--no-gpg-sign'
  end

  command('commit', *arr_opts)
end

#commit_tree(tree, opts = {})

[View source]

1425
1426
1427
1428
1429
1430
1431
1432
1433
# File 'lib/git/lib.rb', line 1425

def commit_tree(tree, opts = {})
  opts[:message] ||= "commit tree #{tree}"
  arr_opts = []
  arr_opts << tree
  arr_opts << '-p' << opts[:parent] if opts[:parent]
  Array(opts[:parents]).each { |p| arr_opts << '-p' << p } if opts[:parents]
  arr_opts << '-m' << opts[:message]
  command('commit-tree', *arr_opts)
end

#compare_version_to(*other_version) ⇒ Integer

Returns current_command_version <=> other_version

Examples:

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

Parameters:

  • other_version (Array<Object>)

    the other version to compare to

Returns:

  • (Integer)

    -1 if this version is less than other_version, 0 if equal, or 1 if greater than

[View source]

1512
1513
1514
# File 'lib/git/lib.rb', line 1512

def compare_version_to(*other_version)
  current_command_version <=> other_version
end

#config_get(name)

[View source]

958
959
960
# File 'lib/git/lib.rb', line 958

def config_get(name)
  command('config', '--get', name, chdir: @git_dir)
end

#config_list

[View source]

966
967
968
# File 'lib/git/lib.rb', line 966

def config_list
  parse_config_list command_lines('config', '--list', chdir: @git_dir)
end

#config_remote(name)

[View source]

948
949
950
951
952
953
954
955
956
# File 'lib/git/lib.rb', line 948

def config_remote(name)
  hsh = {}
  config_list.each do |key, value|
    if /remote.#{name}/.match(key)
      hsh[key.gsub("remote.#{name}.", '')] = value
    end
  end
  hsh
end

#config_set(name, value, options = {})

WRITE COMMANDS ##

[View source]

1002
1003
1004
1005
1006
1007
1008
# File 'lib/git/lib.rb', line 1002

def config_set(name, value, options = {})
  if options[:file].to_s.empty?
    command('config', name, value)
  else
    command('config', '--file', options[:file], name, value)
  end
end

#conflicts

:yields: file, your, their

[View source]

1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
# File 'lib/git/lib.rb', line 1256

def conflicts # :yields: file, your, their
  self.unmerged.each do |f|
    Tempfile.create("YOUR-#{File.basename(f)}") do |your|
      command('show', ":2:#{f}", out: your)
      your.close

      Tempfile.create("THEIR-#{File.basename(f)}") do |their|
        command('show', ":3:#{f}", out: their)
        their.close

        yield(f, your.path, their.path)
      end
    end
  end
end

#current_branch_stateHeadState

The current branch state which is the state of HEAD

Returns:

  • (HeadState)

    the state and name of the current branch

[View source]

745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
# File 'lib/git/lib.rb', line 745

def current_branch_state
  branch_name = command('branch', '--show-current')
  return HeadState.new(:detached, 'HEAD') if branch_name.empty?

  state =
    begin
      command('rev-parse', '--verify', '--quiet', branch_name)
      :active
    rescue Git::FailedError => e
      raise unless e.result.status.exitstatus == 1 && e.result.stderr.empty?

      :unborn
    end

  return HeadState.new(state, branch_name)
end

#current_command_version

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

[View source]

1493
1494
1495
1496
1497
1498
# File 'lib/git/lib.rb', line 1493

def current_command_version
  output = command('version')
  version = output[/\d+(\.\d+)+/]
  version_parts = version.split('.').collect { |i| i.to_i }
  version_parts.fill(0, version_parts.length...3)
end

#describe(commit_ish = nil, opts = {}) ⇒ String

Finds most recent tag that is reachable from a commit

Parameters:

  • commit_ish (String, nil) (defaults to: nil)

    target commit sha or object name

  • opts (Hash) (defaults to: {})

    the given options

Options Hash (opts):

  • :all (Boolean)
  • :tags (Boolean)
  • :contains (Boolean)
  • :debug (Boolean)
  • :long (Boolean)
  • :always (Boolean)
  • :exact_match (Boolean)
  • :dirty (true, String)
  • :abbrev (String)
  • :candidates (String)
  • :match (String)

Returns:

  • (String)

    the tag name

Raises:

  • (ArgumentError)

    if the commit_ish is a string starting with a hyphen

See Also:

[View source]

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/git/lib.rb', line 198

def describe(commit_ish = nil, opts = {})
  assert_args_are_not_options('commit-ish object', commit_ish)

  arr_opts = []

  arr_opts << '--all' if opts[:all]
  arr_opts << '--tags' if opts[:tags]
  arr_opts << '--contains' if opts[:contains]
  arr_opts << '--debug' if opts[:debug]
  arr_opts << '--long' if opts[:long]
  arr_opts << '--always' if opts[:always]
  arr_opts << '--exact-match' if opts[:exact_match] || opts[:"exact-match"]

  arr_opts << '--dirty' if opts[:dirty] == true
  arr_opts << "--dirty=#{opts[:dirty]}" if opts[:dirty].is_a?(String)

  arr_opts << "--abbrev=#{opts[:abbrev]}" if opts[:abbrev]
  arr_opts << "--candidates=#{opts[:candidates]}" if opts[:candidates]
  arr_opts << "--match=#{opts[:match]}" if opts[:match]

  arr_opts << commit_ish if commit_ish

  return command('describe', *arr_opts)
end

#diff_files

compares the index and the working directory

[View source]

866
867
868
# File 'lib/git/lib.rb', line 866

def diff_files
  diff_as_hash('diff-files')
end

#diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})

[View source]

816
817
818
819
820
821
822
823
824
825
# File 'lib/git/lib.rb', line 816

def diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})
  assert_args_are_not_options('commit or commit range', obj1, obj2)

  diff_opts = ['-p']
  diff_opts << obj1
  diff_opts << obj2 if obj2.is_a?(String)
  diff_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String

  command('diff', *diff_opts)
end

#diff_index(treeish)

compares the index and the repository

[View source]

871
872
873
# File 'lib/git/lib.rb', line 871

def diff_index(treeish)
  diff_as_hash('diff-index', treeish)
end

#diff_name_status(reference1 = nil, reference2 = nil, opts = {})

[View source]

849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
# File 'lib/git/lib.rb', line 849

def diff_name_status(reference1 = nil, reference2 = nil, opts = {})
  assert_args_are_not_options('commit or commit range', reference1, reference2)

  opts_arr = ['--name-status']
  opts_arr << reference1 if reference1
  opts_arr << reference2 if reference2

  opts_arr << '--' << opts[:path] if opts[:path]

  command_lines('diff', *opts_arr).inject({}) do |memo, line|
    status, path = line.split("\t")
    memo[path] = status
    memo
  end
end

#diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})

[View source]

827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
# File 'lib/git/lib.rb', line 827

def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
  assert_args_are_not_options('commit or commit range', obj1, obj2)

  diff_opts = ['--numstat']
  diff_opts << obj1
  diff_opts << obj2 if obj2.is_a?(String)
  diff_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String

  hsh = {:total => {:insertions => 0, :deletions => 0, :lines => 0, :files => 0}, :files => {}}

  command_lines('diff', *diff_opts).each do |file|
    (insertions, deletions, filename) = file.split("\t")
    hsh[:total][:insertions] += insertions.to_i
    hsh[:total][:deletions] += deletions.to_i
    hsh[:total][:lines] = (hsh[:total][:deletions] + hsh[:total][:insertions])
    hsh[:total][:files] += 1
    hsh[:files][filename] = {:insertions => insertions.to_i, :deletions => deletions.to_i}
  end

  hsh
end

#each_cat_file_header(data)

[View source]

478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/git/lib.rb', line 478

def each_cat_file_header(data)
  while (match = CAT_FILE_HEADER_LINE.match(data.shift))
    key = match[:key]
    value_lines = [match[:value]]

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

    yield key, value_lines.join("\n")
  end
end

#empty?Boolean

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

Returns:

  • (Boolean)
[View source]

1057
1058
1059
1060
1061
1062
1063
1064
# File 'lib/git/lib.rb', line 1057

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)

[View source]

1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
# File 'lib/git/lib.rb', line 1328

def fetch(remote, opts)
  arr_opts = []
  arr_opts << '--all' if opts[:all]
  arr_opts << '--tags' if opts[:t] || opts[:tags]
  arr_opts << '--prune' if opts[:p] || opts[:prune]
  arr_opts << '--prune-tags' if opts[:P] || opts[:'prune-tags']
  arr_opts << '--force' if opts[:f] || opts[:force]
  arr_opts << '--update-head-ok' if opts[:u] || opts[:'update-head-ok']
  arr_opts << '--unshallow' if opts[:unshallow]
  arr_opts << '--depth' << opts[:depth] if opts[:depth]
  arr_opts << '--' if remote || opts[:ref]
  arr_opts << remote if remote
  arr_opts << opts[:ref] if opts[:ref]

  command('fetch', *arr_opts, merge: true)
end

#full_log_commits(opts = {}) ⇒ Array<Hash>

Return the commits that are within the given revision range

Parameters:

  • opts (Hash) (defaults to: {})

    the given options

Options Hash (opts):

  • :count (Integer)

    the maximum number of commits to return (maps to max-count)

  • :all (Boolean)
  • :cherry (Boolean)
  • :since (String)
  • :until (String)
  • :grep (String)
  • :author (String)
  • :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.

  • :object (String)

    the revision range for the git log command

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

  • :path_limiter (Array<String>, String)

    only include commits that impact files from the specified paths

  • :skip (Integer)

Returns:

  • (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] 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

Raises:

  • (ArgumentError)

    if the revision range (specified with :between or :object) is a string starting with a hyphen

See Also:

[View source]

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/git/lib.rb', line 300

def full_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=raw'
  arr_opts << "--skip=#{opts[:skip]}" if opts[:skip]

  arr_opts += log_path_options(opts)

  full_log = command_lines('log', *arr_opts)

  process_commit_log_data(full_log)
end

#full_tree(sha)

[View source]

609
610
611
# File 'lib/git/lib.rb', line 609

def full_tree(sha)
  command_lines('ls-tree', '-r', sha)
end

#gc

[View source]

1409
1410
1411
# File 'lib/git/lib.rb', line 1409

def gc
  command('gc', '--prune', '--aggressive', '--auto')
end

#global_config_get(name)

[View source]

962
963
964
# File 'lib/git/lib.rb', line 962

def global_config_get(name)
  command('config', '--global', '--get', name)
end

#global_config_list

[View source]

970
971
972
# File 'lib/git/lib.rb', line 970

def global_config_list
  parse_config_list command_lines('config', '--global', '--list')
end

#global_config_set(name, value)

[View source]

1010
1011
1012
# File 'lib/git/lib.rb', line 1010

def global_config_set(name, value)
  command('config', '--global', name, value)
end

#grep(string, opts = {})

returns hash [tree-ish] = [[line_no, match], [line_no, match2]] [tree-ish] = [[line_no, match], [line_no, match2]]

[View source]

774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
# File 'lib/git/lib.rb', line 774

def grep(string, opts = {})
  opts[:object] ||= 'HEAD'

  grep_opts = ['-n']
  grep_opts << '-i' if opts[:ignore_case]
  grep_opts << '-v' if opts[:invert_match]
  grep_opts << '-E' if opts[:extended_regexp]
  grep_opts << '-e'
  grep_opts << string
  grep_opts << opts[:object] if opts[:object].is_a?(String)
  grep_opts.push('--', opts[:path_limiter]) if opts[:path_limiter].is_a?(String)
  grep_opts.push('--', *opts[:path_limiter]) if opts[:path_limiter].is_a?(Array)

  hsh = {}
  begin
    command_lines('grep', *grep_opts).each do |line|
      if m = /(.*?)\:(\d+)\:(.*)/.match(line)
        hsh[m[1]] ||= []
        hsh[m[1]] << [m[2].to_i, m[3]]
      end
    end
  rescue Git::FailedError => e
    raise unless e.result.status.exitstatus == 1 && e.result.stderr == ''
  end
  hsh
end

#ignored_files

[View source]

940
941
942
# File 'lib/git/lib.rb', line 940

def ignored_files
  command_lines('ls-files', '--others', '-i', '--exclude-standard').map { |f| unescape_quoted_path(f) }
end

#init(opts = {})

creates or reinitializes the repository

options: :bare :working_directory :initial_branch

[View source]

86
87
88
89
90
91
92
# File 'lib/git/lib.rb', line 86

def init(opts={})
  arr_opts = []
  arr_opts << '--bare' if opts[:bare]
  arr_opts << "--initial-branch=#{opts[:initial_branch]}" if opts[:initial_branch]

  command('init', *arr_opts)
end

#list_files(ref_dir)

[View source]

707
708
709
710
711
712
713
714
715
# File 'lib/git/lib.rb', line 707

def list_files(ref_dir)
  dir = File.join(@git_dir, 'refs', ref_dir)
  files = []
  begin
    files = Dir.glob('**/*', base: dir).select { |f| File.file?(File.join(dir, f)) }
  rescue
  end
  files
end

#log_commits(opts = {}) ⇒ Array<String>

Return the commits that are within the given revision range

Parameters:

  • opts (Hash) (defaults to: {})

    the given options

Options Hash (opts):

  • :count (Integer)

    the maximum number of commits to return (maps to max-count)

  • :all (Boolean)
  • :cherry (Boolean)
  • :since (String)
  • :until (String)
  • :grep (String)
  • :author (String)
  • :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.

  • :object (String)

    the revision range for the git log command

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

  • :path_limiter (Array<String>, String)

    only include commits that impact files from the specified paths

Returns:

  • (Array<String>)

    the log output

Raises:

  • (ArgumentError)

    if the resulting revision range is a string starting with a hyphen

See Also:

[View source]

250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/git/lib.rb', line 250

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) ⇒ Hash<String, Hash>

List all files that are in the index

Parameters:

  • location (String) (defaults to: nil)

    the location to list the files from

Returns:

  • (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
[View source]

887
888
889
890
891
892
893
894
895
896
897
898
# File 'lib/git/lib.rb', line 887

def ls_files(location=nil)
  location ||= '.'
  {}.tap do |files|
    command_lines('ls-files', '--stage', location).each do |line|
      (info, file) = line.split("\t")
      (mode, sha, stage) = info.split
      files[unescape_quoted_path(file)] = {
        :path => file, :mode_index => mode, :sha_index => sha, :stage => stage
      }
    end
  end
end

#ls_remote(location = nil, opts = {})

[View source]

923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
# File 'lib/git/lib.rb', line 923

def ls_remote(location=nil, opts={})
  arr_opts = []
  arr_opts << '--refs' if opts[:refs]
  arr_opts << (location || '.')

  Hash.new{ |h,k| h[k] = {} }.tap do |hsh|
    command_lines('ls-remote', *arr_opts).each do |line|
      (sha, info) = line.split("\t")
      (ref, type, name) = info.split('/', 3)
      type ||= 'head'
      type = 'branches' if type == 'heads'
      value = {:ref => ref, :sha => sha}
      hsh[type].update( name.nil? ? value : { name => value })
    end
  end
end

#ls_tree(sha, opts = {})

[View source]

588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
# File 'lib/git/lib.rb', line 588

def ls_tree(sha, opts = {})
  data = { 'blob' => {}, 'tree' => {}, 'commit' => {} }

  ls_tree_opts = []
  ls_tree_opts << '-r' if opts[:recursive]
  # path must be last arg
  ls_tree_opts << opts[:path] if opts[:path]

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

  data
end

#meets_required_version?Boolean

Returns:

  • (Boolean)
[View source]

1520
1521
1522
# File 'lib/git/lib.rb', line 1520

def meets_required_version?
  (self.current_command_version <=>  self.required_command_version) >= 0
end

#merge(branch, message = nil, opts = {})

[View source]

1224
1225
1226
1227
1228
1229
1230
1231
# File 'lib/git/lib.rb', line 1224

def merge(branch, message = nil, opts = {})
  arr_opts = []
  arr_opts << '--no-commit' if opts[:no_commit]
  arr_opts << '--no-ff' if opts[:no_ff]
  arr_opts << '-m' << message if message
  arr_opts += Array(branch)
  command('merge', *arr_opts)
end

#merge_base(*args)

[View source]

1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
# File 'lib/git/lib.rb', line 1233

def merge_base(*args)
  opts = args.last.is_a?(Hash) ? args.pop : {}

  arg_opts = []

  arg_opts << '--octopus' if opts[:octopus]
  arg_opts << '--independent' if opts[:independent]
  arg_opts << '--fork-point' if opts[:fork_point]
  arg_opts << '--all' if opts[:all]

  arg_opts += args

  command('merge-base', *arg_opts).lines.map(&:strip)
end

#mv(file1, file2)

[View source]

605
606
607
# File 'lib/git/lib.rb', line 605

def mv(file1, file2)
  command_lines('mv', '--', file1, file2)
end

#name_rev(commit_ish) ⇒ String? Also known as: namerev

Find the first symbolic name for given commit_ish

Parameters:

  • commit_ish (String)

    the commit_ish to find the symbolic name of

Returns:

  • (String, nil)

    the first symbolic name or nil if the commit_ish isn't found

Raises:

  • (ArgumentError)

    if the commit_ish is a string starting with a hyphen

[View source]

350
351
352
353
354
# File 'lib/git/lib.rb', line 350

def name_rev(commit_ish)
  assert_args_are_not_options('commit_ish', commit_ish)

  command('name-rev', commit_ish).split[1]
end

#parse_config(file)

[View source]

983
984
985
# File 'lib/git/lib.rb', line 983

def parse_config(file)
  parse_config_list command_lines('config', '--list', '--file', file)
end

#parse_config_list(lines)

[View source]

974
975
976
977
978
979
980
981
# File 'lib/git/lib.rb', line 974

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)

[View source]

457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/git/lib.rb', line 457

def process_commit_data(data, sha)
  hsh = {
    'sha'    => sha,
    'parent' => []
  }

  each_cat_file_header(data) do |key, value|
    if key == 'parent'
      hsh['parent'] << value
    else
      hsh[key] = value
    end
  end

  hsh['message'] = data.join("\n") + "\n"

  return hsh
end

#process_commit_log_data(data)

[View source]

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
# File 'lib/git/lib.rb', line 547

def process_commit_log_data(data)
  in_message = false

  hsh_array = []

  hsh = nil

  data.each do |line|
    line = line.chomp

    if line[0].nil?
      in_message = !in_message
      next
    end

    in_message = false if in_message && line[0..3] != "    "

    if in_message
      hsh['message'] << "#{line[4..-1]}\n"
      next
    end

    key, *value = line.split
    value = value.join(' ')

    case key
      when 'commit'
        hsh_array << hsh if hsh
        hsh = {'sha' => value, 'message' => +'', 'parent' => []}
      when 'parent'
        hsh['parent'] << value
      else
        hsh[key] = value
    end
  end

  hsh_array << hsh if hsh

  return hsh_array
end

#process_tag_data(data, name)

[View source]

535
536
537
538
539
540
541
542
543
544
545
# File 'lib/git/lib.rb', line 535

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"

  return hsh
end

#pull(remote = nil, branch = nil, opts = {})

Raises:

  • (ArgumentError)
[View source]

1382
1383
1384
1385
1386
1387
1388
1389
1390
# File 'lib/git/lib.rb', line 1382

def pull(remote = nil, branch = nil, opts = {})
  raise ArgumentError, "You must specify a remote if a branch is specified" if remote.nil? && !branch.nil?

  arr_opts = []
  arr_opts << '--allow-unrelated-histories' if opts[:allow_unrelated_histories]
  arr_opts << remote if remote
  arr_opts << branch if branch
  command('pull', *arr_opts)
end

#push(remote = nil, branch = nil, opts = nil)

Raises:

  • (ArgumentError)
[View source]

1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
# File 'lib/git/lib.rb', line 1345

def push(remote = nil, branch = nil, opts = nil)
  if opts.nil? && branch.instance_of?(Hash)
    opts = branch
    branch = nil
  end

  if opts.nil? && remote.instance_of?(Hash)
    opts = remote
    remote = nil
  end

  opts ||= {}

  # Small hack to keep backwards compatibility with the 'push(remote, branch, tags)' method signature.
  opts = {:tags => opts} if [true, false].include?(opts)

  raise ArgumentError, "You must specify a remote if a branch is specified" if remote.nil? && !branch.nil?

  arr_opts = []
  arr_opts << '--mirror'  if opts[:mirror]
  arr_opts << '--delete'  if opts[:delete]
  arr_opts << '--force'   if opts[:force] || opts[:f]
  arr_opts << '--all'     if opts[:all] && remote

  Array(opts[:push_option]).each { |o| arr_opts << '--push-option' << o } if opts[:push_option]
  arr_opts << remote if remote
  arr_opts_with_branch = arr_opts.dup
  arr_opts_with_branch << branch if branch

  if opts[:mirror]
      command('push', *arr_opts_with_branch)
  else
      command('push', *arr_opts_with_branch)
      command('push', '--tags', *arr_opts) if opts[:tags]
  end
end

#read_tree(treeish, opts = {})

reads a tree into the current index file

[View source]

1414
1415
1416
1417
1418
1419
# File 'lib/git/lib.rb', line 1414

def read_tree(treeish, opts = {})
  arr_opts = []
  arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
  arr_opts += [treeish]
  command('read-tree', *arr_opts)
end

#remote_add(name, url, opts = {})

[View source]

1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
# File 'lib/git/lib.rb', line 1272

def remote_add(name, url, opts = {})
  arr_opts = ['add']
  arr_opts << '-f' if opts[:with_fetch] || opts[:fetch]
  arr_opts << '-t' << opts[:track] if opts[:track]
  arr_opts << '--'
  arr_opts << name
  arr_opts << url

  command('remote', *arr_opts)
end

#remote_remove(name)

[View source]

1291
1292
1293
# File 'lib/git/lib.rb', line 1291

def remote_remove(name)
  command('remote', 'rm', name)
end

#remote_set_url(name, url)

[View source]

1283
1284
1285
1286
1287
1288
1289
# File 'lib/git/lib.rb', line 1283

def remote_set_url(name, url)
  arr_opts = ['set-url']
  arr_opts << name
  arr_opts << url

  command('remote', *arr_opts)
end

#remotes

[View source]

1295
1296
1297
# File 'lib/git/lib.rb', line 1295

def remotes
  command_lines('remote')
end

#repack

[View source]

1405
1406
1407
# File 'lib/git/lib.rb', line 1405

def repack
  command('repack', '-a', '-d')
end

#repository_default_branch(repository) ⇒ String

Returns the name of the default branch of the given repository

Parameters:

  • repository (URI, Pathname, String)

    The (possibly remote) repository to clone from

Returns:

  • (String)

    the name of the default branch

Raises:

[View source]

160
161
162
163
164
165
166
167
168
169
170
# File 'lib/git/lib.rb', line 160

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

[View source]

1516
1517
1518
# File 'lib/git/lib.rb', line 1516

def required_command_version
  [2, 28]
end

#reset(commit, opts = {})

[View source]

1108
1109
1110
1111
1112
1113
# File 'lib/git/lib.rb', line 1108

def reset(commit, opts = {})
  arr_opts = []
  arr_opts << '--hard' if opts[:hard]
  arr_opts << commit if commit
  command('reset', *arr_opts)
end

#return_base_opts_from_clone(clone_dir, opts)

[View source]

146
147
148
149
150
151
152
# File 'lib/git/lib.rb', line 146

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

#rev_parse(revision) ⇒ String Also known as: revparse

Verify and resolve a Git revision to its full SHA

Examples:

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

Parameters:

  • revision (String)

    the revision to resolve

Returns:

  • (String)

    the full commit hash

Raises:

  • (Git::FailedError)

    if the revision cannot be resolved

  • (ArgumentError)

    if the revision is a string starting with a hyphen

See Also:

[View source]

333
334
335
336
337
# File 'lib/git/lib.rb', line 333

def rev_parse(revision)
  assert_args_are_not_options('rev', revision)

  command('rev-parse', revision)
end

#revert(commitish, opts = {})

[View source]

1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
# File 'lib/git/lib.rb', line 1125

def revert(commitish, opts = {})
  # Forcing --no-edit as default since it's not an interactive session.
  opts = {:no_edit => true}.merge(opts)

  arr_opts = []
  arr_opts << '--no-edit' if opts[:no_edit]
  arr_opts << commitish

  command('revert', *arr_opts)
end

#rm(path = '.', opts = {})

[View source]

1043
1044
1045
1046
1047
1048
1049
1050
1051
# File 'lib/git/lib.rb', line 1043

def rm(path = '.', opts = {})
  arr_opts = ['-f']  # overrides the up-to-date check by default
  arr_opts << '-r' if opts[:recursive]
  arr_opts << '--cached' if opts[:cached]
  arr_opts << '--'
  arr_opts += Array(path)

  command('rm', *arr_opts)
end

#show(objectish = nil, path = nil) ⇒ String

Shows objects

Parameters:

  • objectish (String|NilClass) (defaults to: nil)

    the target object reference (nil == HEAD)

  • path (String|NilClass) (defaults to: nil)

    the path of the file to be shown

Returns:

  • (String)

    the object information

[View source]

992
993
994
995
996
997
998
# File 'lib/git/lib.rb', line 992

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)

[View source]

1169
1170
1171
1172
1173
1174
1175
# File 'lib/git/lib.rb', line 1169

def stash_apply(id = nil)
  if id
    command('stash', 'apply', id)
  else
    command('stash', 'apply')
  end
end

#stash_clear

[View source]

1177
1178
1179
# File 'lib/git/lib.rb', line 1177

def stash_clear
  command('stash', 'clear')
end

#stash_list

[View source]

1181
1182
1183
# File 'lib/git/lib.rb', line 1181

def stash_list
  command('stash', 'list')
end

#stash_save(message)

[View source]

1164
1165
1166
1167
# File 'lib/git/lib.rb', line 1164

def stash_save(message)
  output = command('stash', 'save', message)
  output =~ /HEAD is now at/
end

#stashes_all

[View source]

1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
# File 'lib/git/lib.rb', line 1148

def stashes_all
  arr = []
  filename = File.join(@git_dir, 'logs/refs/stash')
  if File.exist?(filename)
    File.open(filename) do |f|
      f.each_with_index do |line, i|
        _, msg = line.split("\t")
        # NOTE this logic may be removed/changed in 3.x
        m = msg.match(/^[^:]+:(.*)$/)
        arr << [i, (m ? m[1] : msg).strip]
      end
    end
  end
  arr
end

#tag(name, *opts)

[View source]

1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
# File 'lib/git/lib.rb', line 1303

def tag(name, *opts)
  target = opts[0].instance_of?(String) ? opts[0] : nil

  opts = opts.last.instance_of?(Hash) ? opts.last : {}

  if (opts[:a] || opts[:annotate]) && !(opts[:m] || opts[:message])
    raise  ArgumentError, 'Cannot create an annotated tag without a message.'
  end

  arr_opts = []

  arr_opts << '-f' if opts[:force] || opts[:f]
  arr_opts << '-a' if opts[:a] || opts[:annotate]
  arr_opts << '-s' if opts[:s] || opts[:sign]
  arr_opts << '-d' if opts[:d] || opts[:delete]
  arr_opts << name
  arr_opts << target if target

  if opts[:m] || opts[:message]
    arr_opts << '-m' << (opts[:m] || opts[:message])
  end

  command('tag', *arr_opts)
end

#tag_sha(tag_name)

[View source]

1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
# File 'lib/git/lib.rb', line 1392

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

[View source]

1299
1300
1301
# File 'lib/git/lib.rb', line 1299

def tags
  command_lines('tag')
end

#tree_depth(sha)

[View source]

613
614
615
# File 'lib/git/lib.rb', line 613

def tree_depth(sha)
  full_tree(sha).size
end

#unescape_quoted_path(path) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Unescape a path if it is quoted

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

Examples:

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

Parameters:

  • path (String)

    the path to unescape if quoted

Returns:

  • (String)

    the unescaped path if quoted otherwise the original path

[View source]

915
916
917
918
919
920
921
# File 'lib/git/lib.rb', line 915

def unescape_quoted_path(path)
  if path.start_with?('"') && path.end_with?('"')
    Git::EscapedPath.new(path[1..-2]).unescape
  else
    path
  end
end

#unexpected_branch_line_error(lines, line, index)

[View source]

662
663
664
665
666
667
668
669
670
671
672
# File 'lib/git/lib.rb', line 662

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

#unmerged

[View source]

1248
1249
1250
1251
1252
1253
1254
# File 'lib/git/lib.rb', line 1248

def unmerged
  unmerged = []
  command_lines('diff', "--cached").each do |line|
    unmerged << $1 if line =~ /^\* Unmerged path (.*)/
  end
  unmerged
end

#untracked_files

[View source]

944
945
946
# File 'lib/git/lib.rb', line 944

def untracked_files
  command_lines('ls-files', '--others', '--exclude-standard', chdir: @git_work_dir)
end

#update_ref(ref, commit)

[View source]

1435
1436
1437
# File 'lib/git/lib.rb', line 1435

def update_ref(ref, commit)
  command('update-ref', ref, commit)
end

#worktree_add(dir, commitish = nil)

[View source]

694
695
696
697
# File 'lib/git/lib.rb', line 694

def worktree_add(dir, commitish = nil)
  return command('worktree', 'add', dir, commitish) if !commitish.nil?
  command('worktree', 'add', dir)
end

#worktree_prune

[View source]

703
704
705
# File 'lib/git/lib.rb', line 703

def worktree_prune
  command('worktree', 'prune')
end

#worktree_remove(dir)

[View source]

699
700
701
# File 'lib/git/lib.rb', line 699

def worktree_remove(dir)
  command('worktree', 'remove', dir)
end

#worktrees_all

[View source]

674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
# File 'lib/git/lib.rb', line 674

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("\s")
    directory = s[1] if s[0] == 'worktree'
    arr << [directory, s[1]] if s[0] == 'HEAD'
  end
  arr
end

#write_tree

[View source]

1421
1422
1423
# File 'lib/git/lib.rb', line 1421

def write_tree
  command('write-tree')
end