git 1.19.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/RELEASING.md CHANGED
@@ -7,64 +7,79 @@
7
7
 
8
8
  Releasing a new version of the `git` gem requires these steps:
9
9
 
10
- - [How to release a new git.gem](#how-to-release-a-new-gitgem)
11
- - [Install Prerequisites](#install-prerequisites)
12
- - [Prepare the Release](#prepare-the-release)
13
- - [Review and Merge the Release](#review-and-merge-the-release)
14
- - [Build and Release the Gem](#build-and-release-the-gem)
15
-
16
- These instructions use an example where:
17
-
18
- - The default branch is `master`
19
- - The current release version is `1.5.0`
20
- - You want to create a new *minor* release, `1.6.0`
10
+ * [Install Prerequisites](#install-prerequisites)
11
+ * [Determine the SemVer release type](#determine-the-semver-release-type)
12
+ * [Create the release](#create-the-release)
13
+ * [Review the CHANGELOG and release PR](#review-the-changelog-and-release-pr)
14
+ * [Manually merge the release PR](#manually-merge-the-release-pr)
15
+ * [Publish the git gem to RubyGems.org](#publish-the-git-gem-to-rubygemsorg)
21
16
 
22
17
  ## Install Prerequisites
23
18
 
24
19
  The following tools need to be installed in order to create the release:
25
20
 
26
- - [git](https://git-scm.com) is used to interact with the local and remote repositories
27
- - [gh](https://cli.github.com) is used to create the release and PR in GitHub
28
- - [Docker](https://www.docker.com) is used to run the script to create the release notes
21
+ * [create_githhub_release](https://github.com/main-branch/create_github_release) is used to create the release
22
+ * [git](https://git-scm.com) is used by `create-github-release` to interact with the local and remote repositories
23
+ * [gh](https://cli.github.com) is used by `create-github-release` to create the release and PR in GitHub
29
24
 
30
- On a Mac, these tools can be installed using [brew](https://brew.sh):
25
+ On a Mac, these tools can be installed using [gem](https://guides.rubygems.org/rubygems-basics/) and [brew](https://brew.sh):
31
26
 
32
27
  ```shell
28
+ $ gem install create_github_release
29
+ ...
33
30
  $ brew install git
34
31
  ...
35
32
  $ brew install gh
36
33
  ...
37
- $ brew install --cask docker
38
- ...
39
34
  $
40
35
  ```
41
36
 
42
- ## Prepare the Release
37
+ ## Determine the SemVer release type
43
38
 
44
- Bump the version, create release notes, tag the release and create a GitHub release and PR which can be used to review the release.
39
+ Determine the SemVer version increment that should be applied for the new release:
45
40
 
46
- Steps:
41
+ * `major`: when the release includes incompatible API or functional changes.
42
+ * `minor`: when the release adds functionality in a backward-compatible manner
43
+ * `patch`: when the release includes small user-facing changes that are
44
+ backward-compatible and do not introduce new functionality.
47
45
 
48
- - Check out the code with `git clone https://github.com/ruby-git/ruby-git ruby-git-v1.6.0 && cd ruby-git-v1.6.0`
49
- - Install development dependencies using bundle `bundle install`
50
- - Based upon the nature of the changes, decide on the type of release: `major`, `minor`, or `patch` (in this example we will use `minor`)
51
- - Run the release script `bundle exec create-github-release minor`
46
+ ## Create the release
52
47
 
53
- ## Review and Merge the Release
48
+ Create the release using the `create-github-release` command. If the release type
49
+ is `major`, the command is:
54
50
 
55
- Have the release PR approved and merge the changes into the `master` branch.
51
+ ```shell
52
+ create-github-release major
53
+ ```
56
54
 
57
- **IMPORTANT** DO NOT merge to the `master` branch using the GitHub UI. Instead use the instructions below.
55
+ Follow the directions given by the `create-github-release` command to finish the
56
+ release. Where the instructions given by the command differ than the instructions
57
+ below, follow the instructions given by the command.
58
58
 
59
- Steps:
59
+ ## Review the CHANGELOG and release PR
60
60
 
61
- - Get the release PR reviewed and approved in GitHub
62
- - Merge the changes with the command `git checkout master && git merge --ff-only v1.6.0 && git push`
61
+ The `create-github-release` command will output a link to the CHANGELOG and the PR
62
+ it created for the release. Review the CHANGELOG and have someone review and approve
63
+ the release PR.
63
64
 
64
- ## Build and Release the Gem
65
+ ## Manually merge the release PR
65
66
 
66
- Build the gem and publish it to [rubygems.org](https://rubygems.org/gems/git)
67
+ It is important to manually merge the PR so a separate merge commit can be avoided.
68
+ Use the commands output by the `create-github-release` which will looks like this
69
+ if you are creating a 2.0.0 release:
67
70
 
68
- Steps:
71
+ ```shell
72
+ git checkout master
73
+ git merge --ff-only release-v2.0.0
74
+ git push
75
+ ```
76
+
77
+ This will automatically close the release PR.
78
+
79
+ ## Publish the git gem to RubyGems.org
69
80
 
70
- - Build and release the gem using rake `bundle exec rake release`
81
+ Finally, publish the git gem to RubyGems.org using the following command:
82
+
83
+ ```shell
84
+ rake release:rubygem_push
85
+ ```
data/git.gemspec CHANGED
@@ -24,22 +24,22 @@ Gem::Specification.new do |s|
24
24
  s.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{s.name}/#{s.version}"
25
25
 
26
26
  s.require_paths = ['lib']
27
- s.required_ruby_version = '>= 2.3'
28
- s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to?(:required_rubygems_version=)
29
- s.requirements = ['git 1.6.0.0, or greater']
27
+ s.required_ruby_version = '>= 3.0.0'
28
+ s.requirements = ['git 2.28.0 or greater']
30
29
 
30
+ s.add_runtime_dependency 'activesupport', '>= 5.0'
31
31
  s.add_runtime_dependency 'addressable', '~> 2.8'
32
+ s.add_runtime_dependency 'process_executer', '~> 1.1'
32
33
  s.add_runtime_dependency 'rchardet', '~> 1.8'
33
34
 
34
- s.add_development_dependency 'bump', '~> 0.10'
35
- s.add_development_dependency 'create_github_release', '~> 0.2'
35
+ s.add_development_dependency 'create_github_release', '~> 1.4'
36
36
  s.add_development_dependency 'minitar', '~> 0.9'
37
37
  s.add_development_dependency 'mocha', '~> 2.1'
38
- s.add_development_dependency 'rake', '~> 13.0'
39
- s.add_development_dependency 'test-unit', '~> 3.3'
38
+ s.add_development_dependency 'rake', '~> 13.1'
39
+ s.add_development_dependency 'test-unit', '~> 3.6'
40
40
 
41
41
  unless RUBY_PLATFORM == 'java'
42
- s.add_development_dependency 'redcarpet', '~> 3.5'
42
+ s.add_development_dependency 'redcarpet', '~> 3.6'
43
43
  s.add_development_dependency 'yard', '~> 0.9', '>= 0.9.28'
44
44
  s.add_development_dependency 'yardstick', '~> 0.9'
45
45
  end
data/lib/git/base.rb CHANGED
@@ -409,14 +409,27 @@ module Git
409
409
  self.lib.conflicts(&block)
410
410
  end
411
411
 
412
- # pulls the given branch from the given remote into the current branch
413
- #
414
- # @git.pull # pulls from origin/master
415
- # @git.pull('upstream') # pulls from upstream/master
416
- # @git.pull('upstream', 'develope') # pulls from upstream/develop
417
- #
418
- def pull(remote = nil, branch = nil)
419
- self.lib.pull(remote, branch)
412
+ # Pulls the given branch from the given remote into the current branch
413
+ #
414
+ # @param remote [String] the remote repository to pull from
415
+ # @param branch [String] the branch to pull from
416
+ # @param opts [Hash] options to pass to the pull command
417
+ #
418
+ # @option opts [Boolean] :allow_unrelated_histories (false) Merges histories of two projects that started their
419
+ # lives independently
420
+ # @example pulls from origin/master
421
+ # @git.pull
422
+ # @example pulls from upstream/master
423
+ # @git.pull('upstream')
424
+ # @example pulls from upstream/develop
425
+ # @git.pull('upstream', 'develop')
426
+ #
427
+ # @return [Void]
428
+ #
429
+ # @raise [Git::FailedError] if the pull fails
430
+ # @raise [ArgumentError] if a branch is given without a remote
431
+ def pull(remote = nil, branch = nil, opts = {})
432
+ self.lib.pull(remote, branch, opts)
420
433
  end
421
434
 
422
435
  # returns an array of Git:Remote objects
@@ -0,0 +1,377 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git/base'
4
+ require 'git/command_line_result'
5
+ require 'git/errors'
6
+ require 'stringio'
7
+
8
+ module Git
9
+ # Runs a git command and returns the result
10
+ #
11
+ # @api public
12
+ #
13
+ class CommandLine
14
+ # Create a Git::CommandLine object
15
+ #
16
+ # @example
17
+ # env = { 'GIT_DIR' => '/path/to/git/dir' }
18
+ # binary_path = '/usr/bin/git'
19
+ # global_opts = %w[--git-dir /path/to/git/dir]
20
+ # logger = Logger.new(STDOUT)
21
+ # cli = CommandLine.new(env, binary_path, global_opts, logger)
22
+ # cli.run('version') #=> #<Git::CommandLineResult:0x00007f9b0c0b0e00
23
+ #
24
+ # @param env [Hash<String, String>] environment variables to set
25
+ # @param global_opts [Array<String>] global options to pass to git
26
+ # @param logger [Logger] the logger to use
27
+ #
28
+ def initialize(env, binary_path, global_opts, logger)
29
+ @env = env
30
+ @binary_path = binary_path
31
+ @global_opts = global_opts
32
+ @logger = logger
33
+ end
34
+
35
+ # @attribute [r] env
36
+ #
37
+ # Variables to set (or unset) in the git command's environment
38
+ #
39
+ # @example
40
+ # env = { 'GIT_DIR' => '/path/to/git/dir' }
41
+ # command_line = Git::CommandLine.new(env, '/usr/bin/git', [], Logger.new(STDOUT))
42
+ # command_line.env #=> { 'GIT_DIR' => '/path/to/git/dir' }
43
+ #
44
+ # @return [Hash<String, String>]
45
+ #
46
+ # @see https://ruby-doc.org/3.2.1/Process.html#method-c-spawn Process.spawn
47
+ # for details on how to set environment variables using the `env` parameter
48
+ #
49
+ attr_reader :env
50
+
51
+ # @attribute [r] binary_path
52
+ #
53
+ # The path to the command line binary to run
54
+ #
55
+ # @example
56
+ # binary_path = '/usr/bin/git'
57
+ # command_line = Git::CommandLine.new({}, binary_path, ['version'], Logger.new(STDOUT))
58
+ # command_line.binary_path #=> '/usr/bin/git'
59
+ #
60
+ # @return [String]
61
+ #
62
+ attr_reader :binary_path
63
+
64
+ # @attribute [r] global_opts
65
+ #
66
+ # The global options to pass to git
67
+ #
68
+ # These are options that are passed to git before the command name and
69
+ # arguments. For example, in `git --git-dir /path/to/git/dir version`, the
70
+ # global options are %w[--git-dir /path/to/git/dir].
71
+ #
72
+ # @example
73
+ # env = {}
74
+ # global_opts = %w[--git-dir /path/to/git/dir]
75
+ # logger = Logger.new(nil)
76
+ # cli = CommandLine.new(env, '/usr/bin/git', global_opts, logger)
77
+ # cli.global_opts #=> %w[--git-dir /path/to/git/dir]
78
+ #
79
+ # @return [Array<String>]
80
+ #
81
+ attr_reader :global_opts
82
+
83
+ # @attribute [r] logger
84
+ #
85
+ # The logger to use for logging git commands and results
86
+ #
87
+ # @example
88
+ # env = {}
89
+ # global_opts = %w[]
90
+ # logger = Logger.new(STDOUT)
91
+ # cli = CommandLine.new(env, '/usr/bin/git', global_opts, logger)
92
+ # cli.logger == logger #=> true
93
+ #
94
+ # @return [Logger]
95
+ #
96
+ attr_reader :logger
97
+
98
+ # Execute a git command, wait for it to finish, and return the result
99
+ #
100
+ # NORMALIZATION
101
+ #
102
+ # The command output is returned as a Unicde string containing the binary output
103
+ # from the command. If the binary output is not valid UTF-8, the output will
104
+ # cause problems because the encoding will be invalid.
105
+ #
106
+ # Normalization is a process that trys to convert the binary output to a valid
107
+ # UTF-8 string. It uses the `rchardet` gem to detect the encoding of the binary
108
+ # output and then converts it to UTF-8.
109
+ #
110
+ # Normalization is not enabled by default. Pass `normalize: true` to Git::CommandLine#run
111
+ # to enable it. Normalization will only be performed on stdout and only if the `out:`` option
112
+ # is nil or is a StringIO object. If the out: option is set to a file or other IO object,
113
+ # the normalize option will be ignored.
114
+ #
115
+ # @example Run a command and return the output
116
+ # cli.run('version') #=> "git version 2.39.1\n"
117
+ #
118
+ # @example The args array should be splatted into the parameter list
119
+ # args = %w[log -n 1 --oneline]
120
+ # cli.run(*args) #=> "f5baa11 beginning of Ruby/Git project\n"
121
+ #
122
+ # @example Run a command and return the chomped output
123
+ # cli.run('version', chomp: true) #=> "git version 2.39.1"
124
+ #
125
+ # @example Run a command and without normalizing the output
126
+ # cli.run('version', normalize: false) #=> "git version 2.39.1\n"
127
+ #
128
+ # @example Capture stdout in a temporary file
129
+ # require 'tempfile'
130
+ # tempfile = Tempfile.create('git') do |file|
131
+ # cli.run('version', out: file)
132
+ # file.rewind
133
+ # file.read #=> "git version 2.39.1\n"
134
+ # end
135
+ #
136
+ # @example Capture stderr in a StringIO object
137
+ # require 'stringio'
138
+ # stderr = StringIO.new
139
+ # begin
140
+ # cli.run('log', 'nonexistent-branch', err: stderr)
141
+ # rescue Git::FailedError => e
142
+ # stderr.string #=> "unknown revision or path not in the working tree.\n"
143
+ # end
144
+ #
145
+ # @param args [Array<String>] the command line arguements to pass to git
146
+ #
147
+ # This array should be splatted into the parameter list.
148
+ #
149
+ # @param out [#write, nil] the object to write stdout to or nil to ignore stdout
150
+ #
151
+ # If this is a 'StringIO' object, then `stdout_writer.string` will be returned.
152
+ #
153
+ # In general, only specify a `stdout_writer` object when you want to redirect
154
+ # stdout to a file or some other object that responds to `#write`. The default
155
+ # behavior will return the output of the command.
156
+ #
157
+ # @param err [#write] the object to write stderr to or nil to ignore stderr
158
+ #
159
+ # If this is a 'StringIO' object and `merged_output` is `true`, then
160
+ # `stderr_writer.string` will be merged into the output returned by this method.
161
+ #
162
+ # @param normalize [Boolean] whether to normalize the output to a valid encoding
163
+ #
164
+ # @param chomp [Boolean] whether to chomp the output
165
+ #
166
+ # @param merge [Boolean] whether to merge stdout and stderr in the string returned
167
+ #
168
+ # @param chdir [String] the directory to run the command in
169
+ #
170
+ # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete
171
+ #
172
+ # If timeout is zero, the timeout will not be enforced.
173
+ #
174
+ # If the command times out, it is killed via a `SIGKILL` signal and `Git::TimeoutError` is raised.
175
+ #
176
+ # If the command does not respond to SIGKILL, it will hang this method.
177
+ #
178
+ # @return [Git::CommandLineResult] the output of the command
179
+ #
180
+ # This result of running the command.
181
+ #
182
+ # @raise [ArgumentError] if `args` is not an array of strings
183
+ #
184
+ # @raise [Git::SignaledError] if the command was terminated because of an uncaught signal
185
+ #
186
+ # @raise [Git::FailedError] if the command returned a non-zero exitstatus
187
+ #
188
+ # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
189
+ #
190
+ # @raise [Git::TimeoutError] if the command times out
191
+ #
192
+ def run(*args, out:, err:, normalize:, chomp:, merge:, chdir: nil, timeout: nil)
193
+ git_cmd = build_git_cmd(args)
194
+ out ||= StringIO.new
195
+ err ||= (merge ? out : StringIO.new)
196
+ status = execute(git_cmd, out, err, chdir: (chdir || :not_set), timeout: timeout)
197
+
198
+ process_result(git_cmd, status, out, err, normalize, chomp, timeout)
199
+ end
200
+
201
+ private
202
+
203
+ # Build the git command line from the available sources to send to `Process.spawn`
204
+ # @return [Array<String>]
205
+ # @api private
206
+ #
207
+ def build_git_cmd(args)
208
+ raise ArgumentError.new('The args array can not contain an array') if args.any? { |a| a.is_a?(Array) }
209
+
210
+ [binary_path, *global_opts, *args].map { |e| e.to_s }
211
+ end
212
+
213
+ # Determine the output to return in the `CommandLineResult`
214
+ #
215
+ # If the writer can return the output by calling `#string` (such as a StringIO),
216
+ # then return the result of normalizing the encoding and chomping the output
217
+ # as requested.
218
+ #
219
+ # If the writer does not support `#string`, then return nil. The output is
220
+ # assumed to be collected by the writer itself such as when the writer
221
+ # is a file instead of a StringIO.
222
+ #
223
+ # @param writer [#string] the writer to post-process
224
+ #
225
+ # @return [String, nil]
226
+ #
227
+ # @api private
228
+ #
229
+ def post_process(writer, normalize, chomp)
230
+ if writer.respond_to?(:string)
231
+ output = writer.string.dup
232
+ output = output.lines.map { |l| Git::EncodingUtils.normalize_encoding(l) }.join if normalize
233
+ output.chomp! if chomp
234
+ output
235
+ else
236
+ nil
237
+ end
238
+ end
239
+
240
+ # Post-process all writers and return an array of the results
241
+ #
242
+ # @param writers [Array<#write>] the writers to post-process
243
+ # @param normalize [Boolean] whether to normalize the output of each writer
244
+ # @param chomp [Boolean] whether to chomp the output of each writer
245
+ #
246
+ # @return [Array<String, nil>] the output of each writer that supports `#string`
247
+ #
248
+ # @api private
249
+ #
250
+ def post_process_all(writers, normalize, chomp)
251
+ Array.new.tap do |result|
252
+ writers.each { |writer| result << post_process(writer, normalize, chomp) }
253
+ end
254
+ end
255
+
256
+ # Raise an error when there was exception while collecting the subprocess output
257
+ #
258
+ # @param git_cmd [Array<String>] the git command that was executed
259
+ # @param pipe_name [Symbol] the name of the pipe that raised the exception
260
+ # @param pipe [ProcessExecuter::MonitoredPipe] the pipe that raised the exception
261
+ #
262
+ # @raise [Git::ProcessIOError]
263
+ #
264
+ # @return [void] this method always raises an error
265
+ #
266
+ # @api private
267
+ #
268
+ def raise_pipe_error(git_cmd, pipe_name, pipe)
269
+ raise Git::ProcessIOError.new("Pipe Exception for #{git_cmd}: #{pipe_name}"), cause: pipe.exception
270
+ end
271
+
272
+ # Execute the git command and collect the output
273
+ #
274
+ # @param cmd [Array<String>] the git command to execute
275
+ # @param chdir [String] the directory to run the command in
276
+ # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete
277
+ #
278
+ # If timeout is zero of nil, the command will not time out. If the command
279
+ # times out, it is killed via a SIGKILL signal and `Git::TimeoutError` is raised.
280
+ #
281
+ # If the command does not respond to SIGKILL, it will hang this method.
282
+ #
283
+ # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
284
+ # @raise [Git::TimeoutError] if the command times out
285
+ #
286
+ # @return [ProcessExecuter::Status] the status of the completed subprocess
287
+ #
288
+ # @api private
289
+ #
290
+ def spawn(cmd, out_writers, err_writers, chdir:, timeout:)
291
+ out_pipe = ProcessExecuter::MonitoredPipe.new(*out_writers, chunk_size: 10_000)
292
+ err_pipe = ProcessExecuter::MonitoredPipe.new(*err_writers, chunk_size: 10_000)
293
+ ProcessExecuter.spawn(env, *cmd, out: out_pipe, err: err_pipe, chdir: chdir, timeout: timeout)
294
+ ensure
295
+ out_pipe.close
296
+ err_pipe.close
297
+ raise_pipe_error(cmd, :stdout, out_pipe) if out_pipe.exception
298
+ raise_pipe_error(cmd, :stderr, err_pipe) if err_pipe.exception
299
+ end
300
+
301
+ # The writers that will be used to collect stdout and stderr
302
+ #
303
+ # Additional writers could be added here if you wanted to tee output
304
+ # or send output to the terminal.
305
+ #
306
+ # @param out [#write] the object to write stdout to
307
+ # @param err [#write] the object to write stderr to
308
+ #
309
+ # @return [Array<Array<#write>, Array<#write>>] the writers for stdout and stderr
310
+ #
311
+ # @api private
312
+ #
313
+ def writers(out, err)
314
+ out_writers = [out]
315
+ err_writers = [err]
316
+ [out_writers, err_writers]
317
+ end
318
+
319
+ # Process the result of the command and return a Git::CommandLineResult
320
+ #
321
+ # Post process output, log the command and result, and raise an error if the
322
+ # command failed.
323
+ #
324
+ # @param git_cmd [Array<String>] the git command that was executed
325
+ # @param status [Process::Status] the status of the completed subprocess
326
+ # @param out [#write] the object that stdout was written to
327
+ # @param err [#write] the object that stderr was written to
328
+ # @param normalize [Boolean] whether to normalize the output of each writer
329
+ # @param chomp [Boolean] whether to chomp the output of each writer
330
+ # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete
331
+ #
332
+ # @return [Git::CommandLineResult] the result of the command to return to the caller
333
+ #
334
+ # @raise [Git::FailedError] if the command failed
335
+ # @raise [Git::SignaledError] if the command was signaled
336
+ # @raise [Git::TimeoutError] if the command times out
337
+ # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
338
+ #
339
+ # @api private
340
+ #
341
+ def process_result(git_cmd, status, out, err, normalize, chomp, timeout)
342
+ out_str, err_str = post_process_all([out, err], normalize, chomp)
343
+ logger.info { "#{git_cmd} exited with status #{status}" }
344
+ logger.debug { "stdout:\n#{out_str.inspect}\nstderr:\n#{err_str.inspect}" }
345
+ Git::CommandLineResult.new(git_cmd, status, out_str, err_str).tap do |result|
346
+ raise Git::TimeoutError.new(result, timeout) if status.timeout?
347
+ raise Git::SignaledError.new(result) if status.signaled?
348
+ raise Git::FailedError.new(result) unless status.success?
349
+ end
350
+ end
351
+
352
+ # Execute the git command and write the command output to out and err
353
+ #
354
+ # @param git_cmd [Array<String>] the git command to execute
355
+ # @param out [#write] the object to write stdout to
356
+ # @param err [#write] the object to write stderr to
357
+ # @param chdir [String] the directory to run the command in
358
+ # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete
359
+ #
360
+ # If timeout is zero of nil, the command will not time out. If the command
361
+ # times out, it is killed via a SIGKILL signal and `Git::TimeoutError` is raised.
362
+ #
363
+ # If the command does not respond to SIGKILL, it will hang this method.
364
+ #
365
+ # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
366
+ # @raise [Git::TimeoutError] if the command times out
367
+ #
368
+ # @return [Git::CommandLineResult] the result of the command to return to the caller
369
+ #
370
+ # @api private
371
+ #
372
+ def execute(git_cmd, out, err, chdir:, timeout:)
373
+ out_writers, err_writers = writers(out, err)
374
+ spawn(git_cmd, out_writers, err_writers, chdir: chdir, timeout: timeout)
375
+ end
376
+ end
377
+ end
data/lib/git/config.rb CHANGED
@@ -2,11 +2,12 @@ module Git
2
2
 
3
3
  class Config
4
4
 
5
- attr_writer :binary_path, :git_ssh
5
+ attr_writer :binary_path, :git_ssh, :timeout
6
6
 
7
7
  def initialize
8
8
  @binary_path = nil
9
9
  @git_ssh = nil
10
+ @timeout = nil
10
11
  end
11
12
 
12
13
  def binary_path
@@ -17,6 +18,9 @@ module Git
17
18
  @git_ssh || ENV['GIT_SSH']
18
19
  end
19
20
 
21
+ def timeout
22
+ @timeout || (ENV['GIT_TIMEOUT'] && ENV['GIT_TIMEOUT'].to_i)
23
+ end
20
24
  end
21
25
 
22
26
  end