git 1.19.1 → 4.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.commitlintrc.yml +38 -0
- data/.github/copilot-instructions.md +2733 -0
- data/.github/pull_request_template.md +17 -0
- data/.github/workflows/continuous_integration.yml +92 -21
- data/.github/workflows/enforce_conventional_commits.yml +29 -0
- data/.github/workflows/experimental_continuous_integration.yml +59 -0
- data/.github/workflows/release.yml +53 -0
- data/.gitignore +5 -0
- data/.husky/commit-msg +1 -0
- data/.release-please-manifest.json +3 -0
- data/.rubocop.yml +55 -0
- data/.rubocop_todo.yml +12 -0
- data/.yardopts +4 -1
- data/AI_POLICY.md +24 -0
- data/CHANGELOG.md +501 -0
- data/CODE_OF_CONDUCT.md +25 -0
- data/CONTRIBUTING.md +323 -102
- data/GOVERNANCE.md +106 -0
- data/LICENSE +1 -1
- data/MAINTAINERS.md +17 -4
- data/README.md +575 -246
- data/Rakefile +13 -55
- data/git.gemspec +36 -30
- data/lib/git/args_builder.rb +111 -0
- data/lib/git/author.rb +9 -7
- data/lib/git/base.rb +602 -173
- data/lib/git/branch.rb +318 -38
- data/lib/git/branches.rb +21 -24
- data/lib/git/command_line.rb +330 -0
- data/lib/git/command_line_result.rb +9 -3
- data/lib/git/config.rb +10 -6
- data/lib/git/diff.rb +149 -81
- data/lib/git/diff_path_status.rb +46 -0
- data/lib/git/diff_stats.rb +59 -0
- data/lib/git/errors.rb +212 -0
- data/lib/git/escaped_path.rb +2 -2
- data/lib/git/fsck_object.rb +48 -0
- data/lib/git/fsck_result.rb +121 -0
- data/lib/git/index.rb +2 -1
- data/lib/git/lib.rb +1648 -643
- data/lib/git/log.rb +143 -106
- data/lib/git/object.rb +151 -125
- data/lib/git/path.rb +23 -16
- data/lib/git/remote.rb +5 -4
- data/lib/git/repository.rb +2 -2
- data/lib/git/stash.rb +11 -12
- data/lib/git/stashes.rb +16 -15
- data/lib/git/status.rb +104 -143
- data/lib/git/url.rb +3 -3
- data/lib/git/version.rb +3 -1
- data/lib/git/working_directory.rb +2 -0
- data/lib/git/worktree.rb +6 -5
- data/lib/git/worktrees.rb +6 -6
- data/lib/git.rb +131 -28
- data/package.json +10 -0
- data/redesign/1_architecture_existing.md +66 -0
- data/redesign/2_architecture_redesign.md +130 -0
- data/redesign/3_architecture_implementation.md +138 -0
- data/redesign/index.md +34 -0
- data/release-please-config.json +36 -0
- data/tasks/gem_tasks.rake +10 -0
- data/tasks/rubocop.rake +12 -0
- data/tasks/test.rake +13 -0
- data/tasks/test_gem.rake +12 -0
- data/tasks/yard.rake +23 -0
- metadata +114 -37
- data/.github/stale.yml +0 -25
- data/Dockerfile.changelog-rs +0 -12
- data/PULL_REQUEST_TEMPLATE.md +0 -9
- data/RELEASING.md +0 -70
- data/lib/git/base/factory.rb +0 -99
- data/lib/git/failed_error.rb +0 -53
- data/lib/git/git_execute_error.rb +0 -7
- data/lib/git/signaled_error.rb +0 -50
- /data/{ISSUE_TEMPLATE.md → .github/issue_template.md} +0 -0
data/lib/git/status.rb
CHANGED
|
@@ -1,108 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Git
|
|
4
|
+
# The Status class gets the status of a git repository. It identifies which
|
|
5
|
+
# files have been modified, added, or deleted, including untracked files.
|
|
6
|
+
# The Status object is an Enumerable of StatusFile objects.
|
|
2
7
|
#
|
|
3
|
-
#
|
|
8
|
+
# @api public
|
|
4
9
|
#
|
|
5
10
|
class Status
|
|
6
11
|
include Enumerable
|
|
7
12
|
|
|
13
|
+
# @param base [Git::Base] The base git object
|
|
8
14
|
def initialize(base)
|
|
9
15
|
@base = base
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
#
|
|
14
|
-
# Returns an Enumerable containing files that have changed from the
|
|
15
|
-
# git base directory
|
|
16
|
-
#
|
|
17
|
-
# @return [Enumerable]
|
|
18
|
-
def changed
|
|
19
|
-
@files.select { |_k, f| f.type == 'M' }
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
# Determines whether the given file has been changed.
|
|
24
|
-
# File path starts at git base directory
|
|
25
|
-
#
|
|
26
|
-
# @param file [String] The name of the file.
|
|
27
|
-
# @example Check if lib/git.rb has changed.
|
|
28
|
-
# changed?('lib/git.rb')
|
|
29
|
-
# @return [Boolean]
|
|
30
|
-
def changed?(file)
|
|
31
|
-
changed.member?(file)
|
|
16
|
+
# The factory returns a hash of file paths to StatusFile objects.
|
|
17
|
+
@files = StatusFileFactory.new(base).construct_files
|
|
32
18
|
end
|
|
33
19
|
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#
|
|
39
|
-
def
|
|
40
|
-
@files.select { |_k, f| f.type == 'A' }
|
|
41
|
-
end
|
|
20
|
+
# File status collections, memoized for performance.
|
|
21
|
+
def changed = @changed ||= select_files { |f| f.type == 'M' }
|
|
22
|
+
def added = @added ||= select_files { |f| f.type == 'A' }
|
|
23
|
+
def deleted = @deleted ||= select_files { |f| f.type == 'D' }
|
|
24
|
+
# This works with `true` or `nil`
|
|
25
|
+
def untracked = @untracked ||= select_files(&:untracked)
|
|
42
26
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# @example Check if lib/git.rb is added.
|
|
49
|
-
# added?('lib/git.rb')
|
|
50
|
-
# @return [Boolean]
|
|
51
|
-
def added?(file)
|
|
52
|
-
added.member?(file)
|
|
53
|
-
end
|
|
27
|
+
# Predicate methods to check the status of a specific file.
|
|
28
|
+
def changed?(file) = file_in_collection?(:changed, file)
|
|
29
|
+
def added?(file) = file_in_collection?(:added, file)
|
|
30
|
+
def deleted?(file) = file_in_collection?(:deleted, file)
|
|
31
|
+
def untracked?(file) = file_in_collection?(:untracked, file)
|
|
54
32
|
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
#
|
|
59
|
-
# @return [Enumerable]
|
|
60
|
-
def deleted
|
|
61
|
-
@files.select { |_k, f| f.type == 'D' }
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
# Determines whether the given file has been deleted from the repository
|
|
66
|
-
# File path starts at git base directory
|
|
67
|
-
#
|
|
68
|
-
# @param file [String] The name of the file.
|
|
69
|
-
# @example Check if lib/git.rb is deleted.
|
|
70
|
-
# deleted?('lib/git.rb')
|
|
71
|
-
# @return [Boolean]
|
|
72
|
-
def deleted?(file)
|
|
73
|
-
deleted.member?(file)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
#
|
|
77
|
-
# Returns an Enumerable containing files that are not tracked in git.
|
|
78
|
-
# File path starts at git base directory
|
|
79
|
-
#
|
|
80
|
-
# @return [Enumerable]
|
|
81
|
-
def untracked
|
|
82
|
-
@files.select { |_k, f| f.untracked }
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
#
|
|
86
|
-
# Determines whether the given file has is tracked by git.
|
|
87
|
-
# File path starts at git base directory
|
|
88
|
-
#
|
|
89
|
-
# @param file [String] The name of the file.
|
|
90
|
-
# @example Check if lib/git.rb is an untracked file.
|
|
91
|
-
# untracked?('lib/git.rb')
|
|
92
|
-
# @return [Boolean]
|
|
93
|
-
def untracked?(file)
|
|
94
|
-
untracked.member?(file)
|
|
95
|
-
end
|
|
33
|
+
# Access a status file by path, or iterate over all status files.
|
|
34
|
+
def [](file) = @files[file]
|
|
35
|
+
def each(&) = @files.values.each(&)
|
|
96
36
|
|
|
37
|
+
# Returns a formatted string representation of the status.
|
|
97
38
|
def pretty
|
|
98
|
-
|
|
99
|
-
each do |file|
|
|
100
|
-
out << pretty_file(file)
|
|
101
|
-
end
|
|
102
|
-
out << "\n"
|
|
103
|
-
out
|
|
39
|
+
map { |file| pretty_file(file) }.join << "\n"
|
|
104
40
|
end
|
|
105
41
|
|
|
42
|
+
private
|
|
43
|
+
|
|
106
44
|
def pretty_file(file)
|
|
107
45
|
<<~FILE
|
|
108
46
|
#{file.path}
|
|
@@ -114,84 +52,107 @@ module Git
|
|
|
114
52
|
FILE
|
|
115
53
|
end
|
|
116
54
|
|
|
117
|
-
|
|
55
|
+
def select_files(&block)
|
|
56
|
+
@files.select { |_path, file| block.call(file) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def file_in_collection?(collection_name, file_path)
|
|
60
|
+
collection = public_send(collection_name)
|
|
61
|
+
if ignore_case?
|
|
62
|
+
downcased_keys(collection_name).include?(file_path.downcase)
|
|
63
|
+
else
|
|
64
|
+
collection.key?(file_path)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
118
67
|
|
|
119
|
-
def
|
|
120
|
-
@
|
|
68
|
+
def downcased_keys(collection_name)
|
|
69
|
+
@_downcased_keys ||= {}
|
|
70
|
+
@_downcased_keys[collection_name] ||=
|
|
71
|
+
public_send(collection_name).keys.to_set(&:downcase)
|
|
121
72
|
end
|
|
122
73
|
|
|
123
|
-
def
|
|
124
|
-
@
|
|
74
|
+
def ignore_case?
|
|
75
|
+
return @_ignore_case if defined?(@_ignore_case)
|
|
76
|
+
|
|
77
|
+
@_ignore_case = (@base.config('core.ignoreCase') == 'true')
|
|
78
|
+
rescue Git::FailedError
|
|
79
|
+
@_ignore_case = false
|
|
125
80
|
end
|
|
126
81
|
|
|
127
|
-
#
|
|
82
|
+
# Represents a single file's status in the git repository. Each instance
|
|
83
|
+
# holds information about a file's state in the index and working tree.
|
|
128
84
|
class StatusFile
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
attr_accessor :sha_index, :sha_repo
|
|
85
|
+
attr_reader :path, :type, :stage, :mode_index, :mode_repo,
|
|
86
|
+
:sha_index, :sha_repo, :untracked
|
|
132
87
|
|
|
133
88
|
def initialize(base, hash)
|
|
134
|
-
@base
|
|
135
|
-
@path
|
|
136
|
-
@type
|
|
137
|
-
@stage
|
|
89
|
+
@base = base
|
|
90
|
+
@path = hash[:path]
|
|
91
|
+
@type = hash[:type]
|
|
92
|
+
@stage = hash[:stage]
|
|
138
93
|
@mode_index = hash[:mode_index]
|
|
139
|
-
@mode_repo
|
|
140
|
-
@sha_index
|
|
141
|
-
@sha_repo
|
|
142
|
-
@untracked
|
|
94
|
+
@mode_repo = hash[:mode_repo]
|
|
95
|
+
@sha_index = hash[:sha_index]
|
|
96
|
+
@sha_repo = hash[:sha_repo]
|
|
97
|
+
@untracked = hash[:untracked]
|
|
143
98
|
end
|
|
144
99
|
|
|
100
|
+
# Returns a Git::Object::Blob for either the index or repo version of the file.
|
|
145
101
|
def blob(type = :index)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
else
|
|
149
|
-
begin
|
|
150
|
-
@base.object(@sha_index)
|
|
151
|
-
rescue
|
|
152
|
-
@base.object(@sha_repo)
|
|
153
|
-
end
|
|
154
|
-
end
|
|
102
|
+
sha = type == :repo ? sha_repo : (sha_index || sha_repo)
|
|
103
|
+
@base.object(sha) if sha
|
|
155
104
|
end
|
|
156
105
|
end
|
|
157
106
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
107
|
+
# A factory class responsible for fetching git status data and building
|
|
108
|
+
# a hash of StatusFile objects.
|
|
109
|
+
# @api private
|
|
110
|
+
class StatusFileFactory
|
|
111
|
+
def initialize(base)
|
|
112
|
+
@base = base
|
|
113
|
+
@lib = base.lib
|
|
114
|
+
end
|
|
166
115
|
|
|
167
|
-
|
|
168
|
-
|
|
116
|
+
# Gathers all status data and builds a hash of file paths to
|
|
117
|
+
# StatusFile objects.
|
|
118
|
+
def construct_files
|
|
119
|
+
files_data = fetch_all_files_data
|
|
120
|
+
files_data.transform_values do |data|
|
|
121
|
+
StatusFile.new(@base, data)
|
|
122
|
+
end
|
|
169
123
|
end
|
|
170
|
-
end
|
|
171
124
|
|
|
172
|
-
|
|
173
|
-
ignore = @base.lib.ignored_files
|
|
125
|
+
private
|
|
174
126
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
127
|
+
# Fetches and merges status information from multiple git commands.
|
|
128
|
+
def fetch_all_files_data
|
|
129
|
+
files = @lib.ls_files # Start with files tracked in the index.
|
|
130
|
+
merge_untracked_files(files)
|
|
131
|
+
merge_modified_files(files)
|
|
132
|
+
merge_head_diffs(files)
|
|
133
|
+
files
|
|
134
|
+
end
|
|
179
135
|
|
|
180
|
-
|
|
136
|
+
def merge_untracked_files(files)
|
|
137
|
+
@lib.untracked_files.each do |file|
|
|
138
|
+
files[file] = { path: file, untracked: true }
|
|
139
|
+
end
|
|
181
140
|
end
|
|
182
|
-
end
|
|
183
141
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
142
|
+
def merge_modified_files(files)
|
|
143
|
+
# Merge changes between the index and the working directory.
|
|
144
|
+
@lib.diff_files.each do |path, data|
|
|
145
|
+
(files[path] ||= {}).merge!(data)
|
|
146
|
+
end
|
|
188
147
|
end
|
|
189
|
-
end
|
|
190
148
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
149
|
+
def merge_head_diffs(files)
|
|
150
|
+
return if @lib.empty?
|
|
151
|
+
|
|
152
|
+
# Merge changes between HEAD and the index.
|
|
153
|
+
@lib.diff_index('HEAD').each do |path, data|
|
|
154
|
+
(files[path] ||= {}).merge!(data)
|
|
155
|
+
end
|
|
195
156
|
end
|
|
196
157
|
end
|
|
197
158
|
end
|
data/lib/git/url.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Git
|
|
|
23
23
|
:(?!/) # : serparator is required, but must not be followed by /
|
|
24
24
|
(?<path>.*?) # path is required
|
|
25
25
|
$
|
|
26
|
-
}x
|
|
26
|
+
}x
|
|
27
27
|
|
|
28
28
|
# Parse a Git URL and return an Addressable::URI object
|
|
29
29
|
#
|
|
@@ -118,9 +118,9 @@ module Git
|
|
|
118
118
|
#
|
|
119
119
|
def to_s
|
|
120
120
|
if user
|
|
121
|
-
"#{user}@#{host}:#{path[1
|
|
121
|
+
"#{user}@#{host}:#{path[1..]}"
|
|
122
122
|
else
|
|
123
|
-
"#{host}:#{path[1
|
|
123
|
+
"#{host}:#{path[1..]}"
|
|
124
124
|
end
|
|
125
125
|
end
|
|
126
126
|
end
|
data/lib/git/version.rb
CHANGED
data/lib/git/worktree.rb
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'git/path'
|
|
2
4
|
|
|
3
5
|
module Git
|
|
4
|
-
|
|
5
|
-
class Worktree
|
|
6
|
-
|
|
7
|
-
attr_accessor :full, :dir, :gcommit
|
|
6
|
+
# A worktree in a Git repository
|
|
7
|
+
class Worktree
|
|
8
|
+
attr_accessor :full, :dir
|
|
8
9
|
|
|
9
10
|
def initialize(base, dir, gcommit = nil)
|
|
10
11
|
@full = dir
|
|
11
|
-
@full +=
|
|
12
|
+
@full += " #{gcommit}" unless gcommit.nil?
|
|
12
13
|
@base = base
|
|
13
14
|
@dir = dir
|
|
14
15
|
@gcommit = gcommit
|
data/lib/git/worktrees.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Git
|
|
2
4
|
# object that holds all the available worktrees
|
|
3
5
|
class Worktrees
|
|
4
|
-
|
|
5
6
|
include Enumerable
|
|
6
7
|
|
|
7
8
|
def initialize(base)
|
|
@@ -21,20 +22,19 @@ module Git
|
|
|
21
22
|
@worktrees.size
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
def each(&
|
|
25
|
-
@worktrees.values.each(&
|
|
25
|
+
def each(&)
|
|
26
|
+
@worktrees.values.each(&)
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def [](worktree_name)
|
|
29
|
-
@worktrees.values.
|
|
30
|
+
@worktrees.values.each_with_object(@worktrees) do |worktree, worktrees|
|
|
30
31
|
worktrees[worktree.full] ||= worktree
|
|
31
|
-
worktrees
|
|
32
32
|
end[worktree_name.to_s]
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def to_s
|
|
36
36
|
out = ''
|
|
37
|
-
@worktrees.
|
|
37
|
+
@worktrees.each_value do |b|
|
|
38
38
|
out << b.to_s << "\n"
|
|
39
39
|
end
|
|
40
40
|
out
|
data/lib/git.rb
CHANGED
|
@@ -1,19 +1,44 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/deprecation'
|
|
4
|
+
|
|
5
|
+
# Define Git::Deprecation before requiring the rest of the library to ensure that
|
|
6
|
+
# any deprecation warnings emitted during the loading of the library are properly
|
|
7
|
+
# configured according to the GIT_DEPRECATION_BEHAVIOR environment variable.
|
|
8
|
+
#
|
|
9
|
+
module Git
|
|
10
|
+
# The deprecation instance used to emit deprecation warnings for the Git gem
|
|
11
|
+
#
|
|
12
|
+
# @api public
|
|
13
|
+
Deprecation = ActiveSupport::Deprecation.new('5.0.0', 'Git')
|
|
14
|
+
|
|
15
|
+
if (behavior = ENV.fetch('GIT_DEPRECATION_BEHAVIOR', nil))
|
|
16
|
+
behavior = behavior.strip
|
|
17
|
+
allowed_behaviors = ActiveSupport::Deprecation::DEFAULT_BEHAVIORS.keys.map(&:to_s)
|
|
18
|
+
|
|
19
|
+
unless allowed_behaviors.include?(behavior)
|
|
20
|
+
raise ArgumentError,
|
|
21
|
+
"Invalid GIT_DEPRECATION_BEHAVIOR=#{behavior.inspect}; " \
|
|
22
|
+
"expected one of: #{allowed_behaviors.join(', ')}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
Deprecation.behavior = behavior.to_sym
|
|
26
|
+
end
|
|
27
|
+
end
|
|
5
28
|
|
|
6
29
|
require 'git/author'
|
|
7
30
|
require 'git/base'
|
|
8
31
|
require 'git/branch'
|
|
9
32
|
require 'git/branches'
|
|
10
33
|
require 'git/command_line_result'
|
|
34
|
+
require 'git/command_line'
|
|
11
35
|
require 'git/config'
|
|
12
36
|
require 'git/diff'
|
|
13
37
|
require 'git/encoding_utils'
|
|
38
|
+
require 'git/errors'
|
|
14
39
|
require 'git/escaped_path'
|
|
15
|
-
require 'git/
|
|
16
|
-
require 'git/
|
|
40
|
+
require 'git/fsck_object'
|
|
41
|
+
require 'git/fsck_result'
|
|
17
42
|
require 'git/index'
|
|
18
43
|
require 'git/lib'
|
|
19
44
|
require 'git/log'
|
|
@@ -21,7 +46,6 @@ require 'git/object'
|
|
|
21
46
|
require 'git/path'
|
|
22
47
|
require 'git/remote'
|
|
23
48
|
require 'git/repository'
|
|
24
|
-
require 'git/signaled_error'
|
|
25
49
|
require 'git/status'
|
|
26
50
|
require 'git/stash'
|
|
27
51
|
require 'git/stashes'
|
|
@@ -38,17 +62,33 @@ require 'git/worktrees'
|
|
|
38
62
|
#
|
|
39
63
|
# @author Scott Chacon (mailto:schacon@gmail.com)
|
|
40
64
|
#
|
|
41
|
-
module Git
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
|
|
65
|
+
module Git # rubocop:disable Style/OneClassPerFile
|
|
66
|
+
# Internal alias for Git::Lib, used by the gem itself after the public constant
|
|
67
|
+
# is deprecated. Code outside the gem should not reference this constant.
|
|
68
|
+
# @api private
|
|
69
|
+
LibImpl = remove_const(:Lib)
|
|
70
|
+
|
|
71
|
+
# @api private
|
|
72
|
+
def self.const_missing(name)
|
|
73
|
+
return super unless name == :Lib
|
|
74
|
+
|
|
75
|
+
Git::Deprecation.warn(
|
|
76
|
+
'Git::Lib is deprecated and will be removed in version 5.x. ' \
|
|
77
|
+
'Use the #lib accessor on the object returned by Git.init, Git.open, or Git.clone instead.'
|
|
78
|
+
)
|
|
79
|
+
const_set(:Lib, LibImpl)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# g.config('user.name', 'Scott Chacon') # sets value
|
|
83
|
+
# g.config('user.email', 'email@email.com') # sets value
|
|
84
|
+
# g.config('user.name') # returns 'Scott Chacon'
|
|
85
|
+
# g.config # returns whole config hash
|
|
46
86
|
def config(name = nil, value = nil)
|
|
47
|
-
lib =
|
|
48
|
-
if
|
|
87
|
+
lib = LibImpl.new
|
|
88
|
+
if name && value
|
|
49
89
|
# set value
|
|
50
90
|
lib.config_set(name, value)
|
|
51
|
-
elsif
|
|
91
|
+
elsif name
|
|
52
92
|
# return value
|
|
53
93
|
lib.config_get(name)
|
|
54
94
|
else
|
|
@@ -62,7 +102,7 @@ module Git
|
|
|
62
102
|
end
|
|
63
103
|
|
|
64
104
|
def self.config
|
|
65
|
-
|
|
105
|
+
Base.config
|
|
66
106
|
end
|
|
67
107
|
|
|
68
108
|
def global_config(name = nil, value = nil)
|
|
@@ -90,6 +130,12 @@ module Git
|
|
|
90
130
|
# @param [Hash] options The options for this command (see list of valid
|
|
91
131
|
# options below)
|
|
92
132
|
#
|
|
133
|
+
# @option options [String, nil] :git_ssh An optional custom SSH command
|
|
134
|
+
#
|
|
135
|
+
# - If not specified, uses the global config (Git.configure { |c| c.git_ssh = ... }).
|
|
136
|
+
# - If nil, disables SSH for this instance.
|
|
137
|
+
# - If a non-empty string, uses that value for this instance.
|
|
138
|
+
#
|
|
93
139
|
# @option options [Logger] :log A logger to use for Git operations. Git commands
|
|
94
140
|
# are logged at the `:info` level. Additional logging is done at the `:debug`
|
|
95
141
|
# level.
|
|
@@ -142,6 +188,20 @@ module Git
|
|
|
142
188
|
# @option options [String] :filter Request that the server send a partial
|
|
143
189
|
# clone according to the given filter
|
|
144
190
|
#
|
|
191
|
+
# @option options [Boolean, nil] :single_branch Control whether the clone
|
|
192
|
+
# limits fetch refspecs to a single branch.
|
|
193
|
+
# - If nil (default), no flag is passed and the Git default is used.
|
|
194
|
+
# - If true, `--single-branch` is passed to limit the refspec to the
|
|
195
|
+
# checkout branch.
|
|
196
|
+
# - If false, `--no-single-branch` is passed to broaden the refspec (useful
|
|
197
|
+
# for shallow clones that should include all branches).
|
|
198
|
+
#
|
|
199
|
+
# @option options [String, nil] :git_ssh An optional custom SSH command
|
|
200
|
+
#
|
|
201
|
+
# - If not specified, uses the global config (Git.configure { |c| c.git_ssh = ... }).
|
|
202
|
+
# - If nil, disables SSH for this instance.
|
|
203
|
+
# - If a non-empty string, uses that value for this instance.
|
|
204
|
+
#
|
|
145
205
|
# @option options [Logger] :log A logger to use for Git operations. Git
|
|
146
206
|
# commands are logged at the `:info` level. Additional logging is done
|
|
147
207
|
# at the `:debug` level.
|
|
@@ -184,11 +244,18 @@ module Git
|
|
|
184
244
|
# config: ['user.name=John Doe', 'user.email=john@doe.com']
|
|
185
245
|
# )
|
|
186
246
|
#
|
|
247
|
+
# @example Clone using a specific SSH key
|
|
248
|
+
# git = Git.clone(
|
|
249
|
+
# 'git@github.com:ruby-git/ruby-git.git',
|
|
250
|
+
# 'local-dir',
|
|
251
|
+
# git_ssh: 'ssh -i /path/to/private_key'
|
|
252
|
+
# )
|
|
253
|
+
#
|
|
187
254
|
# @return [Git::Base] an object that can execute git commands in the context
|
|
188
255
|
# of the cloned local working copy or cloned repository.
|
|
189
256
|
#
|
|
190
257
|
def self.clone(repository_url, directory = nil, options = {})
|
|
191
|
-
clone_to_options = options.
|
|
258
|
+
clone_to_options = options.slice(:bare, :mirror)
|
|
192
259
|
directory ||= Git::URL.clone_to(repository_url, **clone_to_options)
|
|
193
260
|
Base.clone(repository_url, directory, options)
|
|
194
261
|
end
|
|
@@ -213,7 +280,8 @@ module Git
|
|
|
213
280
|
# @example with the logging option
|
|
214
281
|
# logger = Logger.new(STDOUT, level: Logger::INFO)
|
|
215
282
|
# Git.default_branch('.', log: logger) # => 'master'
|
|
216
|
-
# I, [2022-04-13T16:01:33.221596 #18415] INFO -- : git '-c' 'core.quotePath=true'
|
|
283
|
+
# I, [2022-04-13T16:01:33.221596 #18415] INFO -- : git '-c' 'core.quotePath=true'
|
|
284
|
+
# '-c' 'color.ui=false' ls-remote '--symref' '--' '.' 'HEAD' 2>&1
|
|
217
285
|
#
|
|
218
286
|
# @param repository [URI, Pathname, String] The (possibly remote) repository to get the default branch name for
|
|
219
287
|
#
|
|
@@ -240,25 +308,37 @@ module Git
|
|
|
240
308
|
# See +clone+ for options. Does not obey the <tt>:remote</tt> option,
|
|
241
309
|
# since the .git info will be deleted anyway; always uses the default
|
|
242
310
|
# remote, 'origin.'
|
|
311
|
+
#
|
|
312
|
+
# <tt>options[:branch]</tt> is the short name of the ref: a branch name such as
|
|
313
|
+
# 'main' or a tag name such as 'v1.0.0'. A full ref path such as
|
|
314
|
+
# 'refs/tags/v1.0.0' or a commit SHA is not accepted.
|
|
315
|
+
#
|
|
316
|
+
# Removing +.git+ is not atomic. If it fails, the exported files are complete and
|
|
317
|
+
# usable, but the directory keeps whatever part of +.git+ could not be deleted.
|
|
318
|
+
# Nothing is cleaned up, because the exported files are the deliverable and the
|
|
319
|
+
# leftover has to be removed by hand once the cause of the failure is fixed.
|
|
320
|
+
#
|
|
321
|
+
# @raise [SystemCallError] if the +.git+ directory cannot be removed. The exported
|
|
322
|
+
# files are left in place, and the directory keeps whatever part of +.git+ could
|
|
323
|
+
# not be deleted.
|
|
243
324
|
def self.export(repository, name, options = {})
|
|
244
325
|
options.delete(:remote)
|
|
245
|
-
repo = clone(repository, name, {:
|
|
246
|
-
repo.checkout("origin/#{options[:branch]}") if options[:branch]
|
|
326
|
+
repo = clone(repository, name, { depth: 1 }.merge(options))
|
|
247
327
|
FileUtils.rm_r File.join(repo.dir.to_s, '.git')
|
|
248
328
|
end
|
|
249
329
|
|
|
250
330
|
# Same as g.config, but forces it to be at the global level
|
|
251
331
|
#
|
|
252
|
-
#g.config('user.name', 'Scott Chacon') # sets value
|
|
253
|
-
#g.config('user.email', 'email@email.com') # sets value
|
|
254
|
-
#g.config('user.name') # returns 'Scott Chacon'
|
|
255
|
-
#g.config # returns whole config hash
|
|
332
|
+
# g.config('user.name', 'Scott Chacon') # sets value
|
|
333
|
+
# g.config('user.email', 'email@email.com') # sets value
|
|
334
|
+
# g.config('user.name') # returns 'Scott Chacon'
|
|
335
|
+
# g.config # returns whole config hash
|
|
256
336
|
def self.global_config(name = nil, value = nil)
|
|
257
|
-
lib =
|
|
258
|
-
if
|
|
337
|
+
lib = LibImpl.new(nil, nil)
|
|
338
|
+
if name && value
|
|
259
339
|
# set value
|
|
260
340
|
lib.global_config_set(name, value)
|
|
261
|
-
elsif
|
|
341
|
+
elsif name
|
|
262
342
|
# return value
|
|
263
343
|
lib.global_config_get(name)
|
|
264
344
|
else
|
|
@@ -296,6 +376,12 @@ module Git
|
|
|
296
376
|
# and converted to an absolute path using
|
|
297
377
|
# [File.expand_path](https://www.rubydoc.info/stdlib/core/File.expand_path).
|
|
298
378
|
#
|
|
379
|
+
# @option options [String, nil] :git_ssh An optional custom SSH command
|
|
380
|
+
#
|
|
381
|
+
# - If not specified, uses the global config (Git.configure { |c| c.git_ssh = ... }).
|
|
382
|
+
# - If nil, disables SSH for this instance.
|
|
383
|
+
# - If a non-empty string, uses that value for this instance.
|
|
384
|
+
#
|
|
299
385
|
# @option options [Logger] :log A logger to use for Git operations. Git
|
|
300
386
|
# commands are logged at the `:info` level. Additional logging is done
|
|
301
387
|
# at the `:debug` level.
|
|
@@ -330,7 +416,7 @@ module Git
|
|
|
330
416
|
# @param [String|NilClass] location the target repository location or nil for '.'
|
|
331
417
|
# @return [{String=>Hash}] the available references of the target repo.
|
|
332
418
|
def self.ls_remote(location = nil, options = {})
|
|
333
|
-
|
|
419
|
+
LibImpl.new.ls_remote(location, options)
|
|
334
420
|
end
|
|
335
421
|
|
|
336
422
|
# Open a an existing Git working directory
|
|
@@ -370,6 +456,12 @@ module Git
|
|
|
370
456
|
# @option options [Pathname] :index used to specify a non-standard path to an
|
|
371
457
|
# index file. The default is `"#{working_dir}/.git/index"`
|
|
372
458
|
#
|
|
459
|
+
# @option options [String, nil] :git_ssh An optional custom SSH command
|
|
460
|
+
#
|
|
461
|
+
# - If not specified, uses the global config (Git.configure { |c| c.git_ssh = ... }).
|
|
462
|
+
# - If nil, disables SSH for this instance.
|
|
463
|
+
# - If a non-empty string, uses that value for this instance.
|
|
464
|
+
#
|
|
373
465
|
# @option options [Logger] :log A logger to use for Git operations. Git
|
|
374
466
|
# commands are logged at the `:info` level. Additional logging is done
|
|
375
467
|
# at the `:debug` level.
|
|
@@ -380,4 +472,15 @@ module Git
|
|
|
380
472
|
def self.open(working_dir, options = {})
|
|
381
473
|
Base.open(working_dir, options)
|
|
382
474
|
end
|
|
475
|
+
|
|
476
|
+
# Return the version of the git binary
|
|
477
|
+
#
|
|
478
|
+
# @example
|
|
479
|
+
# Git.binary_version # => [2, 46, 0]
|
|
480
|
+
#
|
|
481
|
+
# @return [Array<Integer>] the version of the git binary
|
|
482
|
+
#
|
|
483
|
+
def self.binary_version(binary_path = Git::Base.config.binary_path)
|
|
484
|
+
Base.binary_version(binary_path)
|
|
485
|
+
end
|
|
383
486
|
end
|