git 1.4.0 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of git might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/{CHANGELOG → CHANGELOG.md} +41 -10
- data/CONTRIBUTING.md +149 -0
- data/MAINTAINERS.md +14 -0
- data/README.md +260 -212
- data/lib/git.rb +186 -46
- data/lib/git/base.rb +192 -147
- data/lib/git/base/factory.rb +47 -21
- data/lib/git/branch.rb +5 -1
- data/lib/git/config.rb +1 -1
- data/lib/git/diff.rb +7 -10
- data/lib/git/lib.rb +259 -77
- data/lib/git/log.rb +8 -1
- data/lib/git/stashes.rb +11 -0
- data/lib/git/status.rb +1 -1
- data/lib/git/version.rb +1 -1
- metadata +91 -36
- data/VERSION +0 -2
data/lib/git.rb
CHANGED
@@ -19,30 +19,24 @@ require 'git/repository'
|
|
19
19
|
require 'git/status'
|
20
20
|
require 'git/stash'
|
21
21
|
require 'git/stashes'
|
22
|
+
require 'git/version'
|
22
23
|
require 'git/working_directory'
|
24
|
+
require 'git/worktree'
|
25
|
+
require 'git/worktrees'
|
23
26
|
|
24
27
|
lib = Git::Lib.new(nil, nil)
|
25
28
|
unless lib.meets_required_version?
|
26
29
|
$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."
|
27
30
|
end
|
28
31
|
|
29
|
-
# Git
|
30
|
-
#
|
31
|
-
# This provides bindings for working with git in complex
|
32
|
-
# interactions, including branching and merging, object
|
33
|
-
# inspection and manipulation, history, patch generation
|
34
|
-
# and more. You should be able to do most fundamental git
|
35
|
-
# operations with this library.
|
36
|
-
#
|
37
|
-
# This module provides the basic functions to open a git
|
32
|
+
# The Git module provides the basic functions to open a git
|
38
33
|
# reference to work with. You can open a working directory,
|
39
34
|
# open a bare repository, initialize a new repo or clone an
|
40
35
|
# existing remote repository.
|
41
36
|
#
|
42
|
-
#
|
43
|
-
#
|
37
|
+
# @author Scott Chacon (mailto:schacon@gmail.com)
|
38
|
+
#
|
44
39
|
module Git
|
45
|
-
|
46
40
|
#g.config('user.name', 'Scott Chacon') # sets value
|
47
41
|
#g.config('user.email', 'email@email.com') # sets value
|
48
42
|
#g.config('user.name') # returns 'Scott Chacon'
|
@@ -73,25 +67,93 @@ module Git
|
|
73
67
|
self.class.global_config(name, value)
|
74
68
|
end
|
75
69
|
|
76
|
-
#
|
70
|
+
# Open a bare repository
|
71
|
+
#
|
72
|
+
# Opens a bare repository located in the `git_dir` directory.
|
73
|
+
# Since there is no working copy, you can not checkout or commit
|
74
|
+
# but you can do most read operations.
|
75
|
+
#
|
76
|
+
# @see https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefbarerepositoryabarerepository
|
77
|
+
# What is a bare repository?
|
78
|
+
#
|
79
|
+
# @example Open a bare repository and retrieve the first commit SHA
|
80
|
+
# repository = Git.bare('ruby-git.git')
|
81
|
+
# puts repository.log[0].sha #=> "64c6fa011d3287bab9158049c85f3e85718854a0"
|
82
|
+
#
|
83
|
+
# @param [Pathname] git_dir The path to the bare repository directory
|
84
|
+
# containing an initialized Git repository. If a relative path is given, it
|
85
|
+
# is converted to an absolute path using
|
86
|
+
# [File.expand_path](https://www.rubydoc.info/stdlib/core/File.expand_path).
|
87
|
+
#
|
88
|
+
# @param [Hash] options The options for this command (see list of valid
|
89
|
+
# options below)
|
90
|
+
#
|
91
|
+
# @option options [Logger] :log A logger to use for Git operations. Git commands
|
92
|
+
# are logged at the `:info` level. Additional logging is done at the `:debug`
|
93
|
+
# level.
|
94
|
+
#
|
95
|
+
# @return [Git::Base] an object that can execute git commands in the context
|
96
|
+
# of the bare repository.
|
77
97
|
#
|
78
|
-
# this takes the path to a bare git repo
|
79
|
-
# it expects not to be able to use a working directory
|
80
|
-
# so you can't checkout stuff, commit things, etc.
|
81
|
-
# but you can do most read operations
|
82
98
|
def self.bare(git_dir, options = {})
|
83
99
|
Base.bare(git_dir, options)
|
84
100
|
end
|
85
|
-
|
86
|
-
#
|
101
|
+
|
102
|
+
# Clone a repository into an empty or newly created directory
|
87
103
|
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
104
|
+
# @see https://git-scm.com/docs/git-clone git clone
|
105
|
+
# @see https://git-scm.com/docs/git-clone#_git_urls_a_id_urls_a GIT URLs
|
106
|
+
#
|
107
|
+
# @param [URI, Pathname] repository The (possibly remote) repository to clone
|
108
|
+
# from. See [GIT URLS](https://git-scm.com/docs/git-clone#_git_urls_a_id_urls_a)
|
109
|
+
# for more information.
|
110
|
+
#
|
111
|
+
# @param [Pathname] name The directory to clone into.
|
112
|
+
#
|
113
|
+
# @param [Hash] options The options for this command (see list of valid
|
114
|
+
# options below)
|
92
115
|
#
|
93
|
-
#
|
94
|
-
#
|
116
|
+
# @option options [Boolean] :bare Make a bare Git repository. See
|
117
|
+
# [what is a bare repository?](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefbarerepositoryabarerepository).
|
118
|
+
#
|
119
|
+
# @option options [String] :branch The name of a branch or tag to checkout
|
120
|
+
# instead of the default branch.
|
121
|
+
#
|
122
|
+
# @option options [Integer] :depth Create a shallow clone with a history
|
123
|
+
# truncated to the specified number of commits.
|
124
|
+
#
|
125
|
+
# @option options [Logger] :log A logger to use for Git operations. Git
|
126
|
+
# commands are logged at the `:info` level. Additional logging is done
|
127
|
+
# at the `:debug` level.
|
128
|
+
#
|
129
|
+
# @option options [Boolean] :mirror Set up a mirror of the source repository.
|
130
|
+
#
|
131
|
+
# @option options [String] :origin Use the value instead `origin` to track
|
132
|
+
# the upstream repository.
|
133
|
+
#
|
134
|
+
# @option options [Pathname] :path The directory to clone into. May be used
|
135
|
+
# as an alternative to the `directory` parameter. If specified, the
|
136
|
+
# `path` option is used instead of the `directory` parameter.
|
137
|
+
#
|
138
|
+
# @option options [Boolean] :recursive After the clone is created, initialize
|
139
|
+
# all submodules within, using their default settings.
|
140
|
+
#
|
141
|
+
# @example Clone into the default directory `ruby-git`
|
142
|
+
# git = Git.clone('https://github.com/ruby-git/ruby-git.git')
|
143
|
+
#
|
144
|
+
# @example Clone and then checkout the `development` branch
|
145
|
+
# git = Git.clone('https://github.com/ruby-git/ruby-git.git', branch: 'development')
|
146
|
+
#
|
147
|
+
# @example Clone into a different directory `my-ruby-git`
|
148
|
+
# git = Git.clone('https://github.com/ruby-git/ruby-git.git', 'my-ruby-git')
|
149
|
+
# # or:
|
150
|
+
# git = Git.clone('https://github.com/ruby-git/ruby-git.git', path: 'my-ruby-git')
|
151
|
+
#
|
152
|
+
# @example Create a bare repository in the directory `ruby-git.git`
|
153
|
+
# git = Git.clone('https://github.com/ruby-git/ruby-git.git', bare: true)
|
154
|
+
#
|
155
|
+
# @return [Git::Base] an object that can execute git commands in the context
|
156
|
+
# of the cloned local working copy or cloned repository.
|
95
157
|
#
|
96
158
|
def self.clone(repository, name, options = {})
|
97
159
|
Base.clone(repository, name, options)
|
@@ -110,7 +172,7 @@ module Git
|
|
110
172
|
repo.checkout("origin/#{options[:branch]}") if options[:branch]
|
111
173
|
Dir.chdir(repo.dir.to_s) { FileUtils.rm_r '.git' }
|
112
174
|
end
|
113
|
-
|
175
|
+
|
114
176
|
# Same as g.config, but forces it to be at the global level
|
115
177
|
#
|
116
178
|
#g.config('user.name', 'Scott Chacon') # sets value
|
@@ -131,36 +193,114 @@ module Git
|
|
131
193
|
end
|
132
194
|
end
|
133
195
|
|
134
|
-
#
|
196
|
+
# Create an empty Git repository or reinitialize an existing Git repository
|
135
197
|
#
|
136
|
-
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
|
140
|
-
|
198
|
+
# @param [Pathname] directory If the `:bare` option is NOT given or is not
|
199
|
+
# `true`, the repository will be created in `"#{directory}/.git"`.
|
200
|
+
# Otherwise, the repository is created in `"#{directory}"`.
|
201
|
+
#
|
202
|
+
# All directories along the path to `directory` are created if they do not exist.
|
203
|
+
#
|
204
|
+
# A relative path is referenced from the current working directory of the process
|
205
|
+
# and converted to an absolute path using
|
206
|
+
# [File.expand_path](https://www.rubydoc.info/stdlib/core/File.expand_path).
|
207
|
+
#
|
208
|
+
# @param [Hash] options The options for this command (see list of valid
|
209
|
+
# options below)
|
210
|
+
#
|
211
|
+
# @option options [Boolean] :bare Instead of creating a repository at
|
212
|
+
# `"#{directory}/.git"`, create a bare repository at `"#{directory}"`.
|
213
|
+
# See [what is a bare repository?](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefbarerepositoryabarerepository).
|
214
|
+
#
|
215
|
+
# @option options [Pathname] :repository the path to put the newly initialized
|
216
|
+
# Git repository. The default for non-bare repository is `"#{directory}/.git"`.
|
217
|
+
#
|
218
|
+
# A relative path is referenced from the current working directory of the process
|
219
|
+
# and converted to an absolute path using
|
220
|
+
# [File.expand_path](https://www.rubydoc.info/stdlib/core/File.expand_path).
|
221
|
+
#
|
222
|
+
# @option options [Logger] :log A logger to use for Git operations. Git
|
223
|
+
# commands are logged at the `:info` level. Additional logging is done
|
224
|
+
# at the `:debug` level.
|
225
|
+
#
|
226
|
+
# @return [Git::Base] an object that can execute git commands in the context
|
227
|
+
# of the newly initialized repository
|
228
|
+
#
|
229
|
+
# @example Initialize a repository in the current directory
|
230
|
+
# git = Git.init
|
231
|
+
#
|
232
|
+
# @example Initialize a repository in some other directory
|
233
|
+
# git = Git.init '~/code/ruby-git'
|
234
|
+
#
|
235
|
+
# @example Initialize a bare repository
|
236
|
+
# git = Git.init '~/code/ruby-git.git', bare: true
|
237
|
+
#
|
238
|
+
# @example Initialize a repository in a non-default location (outside of the working copy)
|
239
|
+
# git = Git.init '~/code/ruby-git', repository: '~/code/ruby-git.git'
|
240
|
+
#
|
241
|
+
# @see https://git-scm.com/docs/git-init git init
|
242
|
+
#
|
243
|
+
def self.init(directory = '.', options = {})
|
244
|
+
Base.init(directory, options)
|
141
245
|
end
|
142
|
-
|
143
|
-
# returns a Hash containing information about the references
|
246
|
+
|
247
|
+
# returns a Hash containing information about the references
|
144
248
|
# of the target repository
|
145
249
|
#
|
250
|
+
# options
|
251
|
+
# :refs
|
252
|
+
#
|
146
253
|
# @param [String|NilClass] location the target repository location or nil for '.'
|
147
254
|
# @return [{String=>Hash}] the available references of the target repo.
|
148
|
-
def self.ls_remote(location=nil)
|
149
|
-
Git::Lib.new.ls_remote(location)
|
255
|
+
def self.ls_remote(location = nil, options = {})
|
256
|
+
Git::Lib.new.ls_remote(location, options)
|
150
257
|
end
|
151
258
|
|
152
|
-
#
|
153
|
-
#
|
154
|
-
#
|
155
|
-
# a git reference, referring to
|
156
|
-
#
|
157
|
-
#
|
259
|
+
# Open a an existing Git working directory
|
260
|
+
#
|
261
|
+
# Git.open will most likely be the most common way to create
|
262
|
+
# a git reference, referring to an existing working directory.
|
263
|
+
#
|
264
|
+
# If not provided in the options, the library will assume
|
265
|
+
# the repository and index are in the default places (`.git/`, `.git/index`).
|
266
|
+
#
|
267
|
+
# @example Open the Git working directory in the current directory
|
268
|
+
# git = Git.open
|
269
|
+
#
|
270
|
+
# @example Open a Git working directory in some other directory
|
271
|
+
# git = Git.open('~/Projects/ruby-git')
|
272
|
+
#
|
273
|
+
# @example Use a logger to see what is going on
|
274
|
+
# logger = Logger.new(STDOUT)
|
275
|
+
# git = Git.open('~/Projects/ruby-git', log: logger)
|
276
|
+
#
|
277
|
+
# @example Open a working copy whose repository is in a non-standard directory
|
278
|
+
# git = Git.open('~/Projects/ruby-git', repository: '~/Project/ruby-git.git')
|
279
|
+
#
|
280
|
+
# @param [Pathname] working_dir the path to the working directory to use
|
281
|
+
# for git commands.
|
282
|
+
#
|
283
|
+
# A relative path is referenced from the current working directory of the process
|
284
|
+
# and converted to an absolute path using
|
285
|
+
# [File.expand_path](https://www.rubydoc.info/stdlib/core/File.expand_path).
|
286
|
+
#
|
287
|
+
# @param [Hash] options The options for this command (see list of valid
|
288
|
+
# options below)
|
289
|
+
#
|
290
|
+
# @option options [Pathname] :repository used to specify a non-standard path to
|
291
|
+
# the repository directory. The default is `"#{working_dir}/.git"`.
|
292
|
+
#
|
293
|
+
# @option options [Pathname] :index used to specify a non-standard path to an
|
294
|
+
# index file. The default is `"#{working_dir}/.git/index"`
|
295
|
+
#
|
296
|
+
# @option options [Logger] :log A logger to use for Git operations. Git
|
297
|
+
# commands are logged at the `:info` level. Additional logging is done
|
298
|
+
# at the `:debug` level.
|
299
|
+
#
|
300
|
+
# @return [Git::Base] an object that can execute git commands in the context
|
301
|
+
# of the opened working copy
|
158
302
|
#
|
159
|
-
# options
|
160
|
-
# :repository => '/path/to/alt_git_dir'
|
161
|
-
# :index => '/path/to/alt_index_file'
|
162
303
|
def self.open(working_dir, options = {})
|
163
304
|
Base.open(working_dir, options)
|
164
305
|
end
|
165
|
-
|
166
306
|
end
|
data/lib/git/base.rb
CHANGED
@@ -1,34 +1,25 @@
|
|
1
1
|
require 'git/base/factory'
|
2
2
|
|
3
3
|
module Git
|
4
|
-
|
4
|
+
# Git::Base is the main public interface for interacting with Git commands.
|
5
|
+
#
|
6
|
+
# Instead of creating a Git::Base directly, obtain a Git::Base instance by
|
7
|
+
# calling one of the follow {Git} class methods: {Git.open}, {Git.init},
|
8
|
+
# {Git.clone}, or {Git.bare}.
|
9
|
+
#
|
5
10
|
class Base
|
6
|
-
|
7
11
|
include Git::Base::Factory
|
8
12
|
|
9
|
-
#
|
10
|
-
def self.bare(git_dir,
|
11
|
-
self.new({:repository => git_dir}.merge(
|
13
|
+
# (see Git.bare)
|
14
|
+
def self.bare(git_dir, options = {})
|
15
|
+
self.new({:repository => git_dir}.merge(options))
|
12
16
|
end
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
# name - sinatra
|
18
|
-
#
|
19
|
-
# options:
|
20
|
-
# :repository
|
21
|
-
#
|
22
|
-
# :bare
|
23
|
-
# or
|
24
|
-
# :working_directory
|
25
|
-
# :index_file
|
26
|
-
#
|
27
|
-
def self.clone(repository, name, opts = {})
|
28
|
-
# run git-clone
|
29
|
-
self.new(Git::Lib.new.clone(repository, name, opts))
|
17
|
+
|
18
|
+
# (see Git.clone)
|
19
|
+
def self.clone(repository, name, options = {})
|
20
|
+
self.new(Git::Lib.new(nil, options[:log]).clone(repository, name, options))
|
30
21
|
end
|
31
|
-
|
22
|
+
|
32
23
|
# Returns (and initialize if needed) a Git::Config instance
|
33
24
|
#
|
34
25
|
# @return [Git::Config] the current config instance.
|
@@ -36,49 +27,86 @@ module Git
|
|
36
27
|
return @@config ||= Config.new
|
37
28
|
end
|
38
29
|
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
FileUtils.mkdir_p(opts[:working_directory]) if opts[:working_directory] && !File.directory?(opts[:working_directory])
|
51
|
-
|
52
|
-
init_opts = {
|
53
|
-
:bare => opts[:bare]
|
54
|
-
}
|
55
|
-
|
56
|
-
opts.delete(:working_directory) if opts[:bare]
|
57
|
-
|
30
|
+
# (see Git.init)
|
31
|
+
def self.init(directory, options = {})
|
32
|
+
options[:working_directory] ||= directory
|
33
|
+
options[:repository] ||= File.join(options[:working_directory], '.git')
|
34
|
+
|
35
|
+
FileUtils.mkdir_p(options[:working_directory]) if options[:working_directory] && !File.directory?(options[:working_directory])
|
36
|
+
|
37
|
+
init_options = { :bare => options[:bare] }
|
38
|
+
|
39
|
+
options.delete(:working_directory) if options[:bare]
|
40
|
+
|
58
41
|
# Submodules have a .git *file* not a .git folder.
|
59
42
|
# This file's contents point to the location of
|
60
43
|
# where the git refs are held (In the parent repo)
|
61
|
-
if File.file?('.git')
|
44
|
+
if options[:working_directory] && File.file?(File.join(options[:working_directory], '.git'))
|
62
45
|
git_file = File.open('.git').read[8..-1].strip
|
63
|
-
|
64
|
-
|
46
|
+
options[:repository] = git_file
|
47
|
+
options[:index] = git_file + '/index'
|
65
48
|
end
|
66
49
|
|
67
|
-
Git::Lib
|
68
|
-
|
69
|
-
|
50
|
+
# TODO: this dance seems awkward: this creates a Git::Lib so we can call
|
51
|
+
# init so we can create a new Git::Base which in turn (ultimately)
|
52
|
+
# creates another/different Git::Lib.
|
53
|
+
#
|
54
|
+
# TODO: maybe refactor so this Git::Bare.init does this:
|
55
|
+
# self.new(opts).init(init_opts) and move all/some of this code into
|
56
|
+
# Git::Bare#init. This way the init method can be called on any
|
57
|
+
# repository you have a Git::Base instance for. This would not
|
58
|
+
# change the existing interface (other than adding to it).
|
59
|
+
#
|
60
|
+
Git::Lib.new(options).init(init_options)
|
61
|
+
|
62
|
+
self.new(options)
|
70
63
|
end
|
71
|
-
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
64
|
+
|
65
|
+
# (see Git.open)
|
66
|
+
def self.open(working_dir, options={})
|
67
|
+
# TODO: move this to Git.open?
|
68
|
+
|
69
|
+
options[:working_directory] ||= working_dir
|
70
|
+
options[:repository] ||= File.join(options[:working_directory], '.git')
|
71
|
+
|
72
|
+
# Submodules have a .git *file* not a .git folder.
|
73
|
+
# This file's contents point to the location of
|
74
|
+
# where the git refs are held (In the parent repo)
|
75
|
+
if options[:working_directory] && File.file?(File.join(options[:working_directory], '.git'))
|
76
|
+
git_file = File.open('.git').read[8..-1].strip
|
77
|
+
options[:repository] = git_file
|
78
|
+
options[:index] = git_file + '/index'
|
79
|
+
end
|
80
|
+
|
81
|
+
self.new(options)
|
76
82
|
end
|
77
|
-
|
83
|
+
|
84
|
+
# Create an object that executes Git commands in the context of a working
|
85
|
+
# copy or a bare repository.
|
86
|
+
#
|
87
|
+
# @param [Hash] options The options for this command (see list of valid
|
88
|
+
# options below)
|
89
|
+
#
|
90
|
+
# @option options [Pathname] :working_dir the path to the root of the working
|
91
|
+
# directory. Should be `nil` if executing commands on a bare repository.
|
92
|
+
#
|
93
|
+
# @option options [Pathname] :repository used to specify a non-standard path to
|
94
|
+
# the repository directory. The default is `"#{working_dir}/.git"`.
|
95
|
+
#
|
96
|
+
# @option options [Pathname] :index used to specify a non-standard path to an
|
97
|
+
# index file. The default is `"#{working_dir}/.git/index"`
|
98
|
+
#
|
99
|
+
# @option options [Logger] :log A logger to use for Git operations. Git
|
100
|
+
# commands are logged at the `:info` level. Additional logging is done
|
101
|
+
# at the `:debug` level.
|
102
|
+
#
|
103
|
+
# @return [Git::Base] an object that can execute git commands in the context
|
104
|
+
# of the opened working copy or bare repository
|
105
|
+
#
|
78
106
|
def initialize(options = {})
|
79
107
|
if working_dir = options[:working_directory]
|
80
108
|
options[:repository] ||= File.join(working_dir, '.git')
|
81
|
-
options[:index] ||= File.join(
|
109
|
+
options[:index] ||= File.join(options[:repository], 'index')
|
82
110
|
end
|
83
111
|
if options[:log]
|
84
112
|
@logger = options[:log]
|
@@ -86,17 +114,17 @@ module Git
|
|
86
114
|
else
|
87
115
|
@logger = nil
|
88
116
|
end
|
89
|
-
|
117
|
+
|
90
118
|
@working_directory = options[:working_directory] ? Git::WorkingDirectory.new(options[:working_directory]) : nil
|
91
|
-
@repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil
|
119
|
+
@repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil
|
92
120
|
@index = options[:index] ? Git::Index.new(options[:index], false) : nil
|
93
121
|
end
|
94
|
-
|
122
|
+
|
95
123
|
# changes current working directory for a block
|
96
124
|
# to the git working directory
|
97
125
|
#
|
98
126
|
# example
|
99
|
-
# @git.chdir do
|
127
|
+
# @git.chdir do
|
100
128
|
# # write files
|
101
129
|
# @git.add
|
102
130
|
# @git.commit('message')
|
@@ -106,7 +134,7 @@ module Git
|
|
106
134
|
yield dir.path
|
107
135
|
end
|
108
136
|
end
|
109
|
-
|
137
|
+
|
110
138
|
#g.config('user.name', 'Scott Chacon') # sets value
|
111
139
|
#g.config('user.email', 'email@email.com') # sets value
|
112
140
|
#g.config('user.name') # returns 'Scott Chacon'
|
@@ -123,14 +151,14 @@ module Git
|
|
123
151
|
lib.config_list
|
124
152
|
end
|
125
153
|
end
|
126
|
-
|
154
|
+
|
127
155
|
# returns a reference to the working directory
|
128
156
|
# @git.dir.path
|
129
157
|
# @git.dir.writeable?
|
130
158
|
def dir
|
131
159
|
@working_directory
|
132
160
|
end
|
133
|
-
|
161
|
+
|
134
162
|
# returns reference to the git index file
|
135
163
|
def index
|
136
164
|
@index
|
@@ -141,24 +169,28 @@ module Git
|
|
141
169
|
def repo
|
142
170
|
@repository
|
143
171
|
end
|
144
|
-
|
172
|
+
|
145
173
|
# returns the repository size in bytes
|
146
174
|
def repo_size
|
147
|
-
Dir.
|
148
|
-
|
149
|
-
end
|
175
|
+
Dir.glob(File.join(repo.path, '**', '*'), File::FNM_DOTMATCH).reject do |f|
|
176
|
+
f.include?('..')
|
177
|
+
end.map do |f|
|
178
|
+
File.expand_path(f)
|
179
|
+
end.uniq.map do |f|
|
180
|
+
File.stat(f).size.to_i
|
181
|
+
end.reduce(:+)
|
150
182
|
end
|
151
|
-
|
183
|
+
|
152
184
|
def set_index(index_file, check = true)
|
153
185
|
@lib = nil
|
154
186
|
@index = Git::Index.new(index_file.to_s, check)
|
155
187
|
end
|
156
|
-
|
188
|
+
|
157
189
|
def set_working(work_dir, check = true)
|
158
190
|
@lib = nil
|
159
191
|
@working_directory = Git::WorkingDirectory.new(work_dir.to_s, check)
|
160
192
|
end
|
161
|
-
|
193
|
+
|
162
194
|
# returns +true+ if the branch exists locally
|
163
195
|
def is_local_branch?(branch)
|
164
196
|
branch_names = self.branches.local.map {|b| b.name}
|
@@ -177,53 +209,60 @@ module Git
|
|
177
209
|
branch_names.include?(branch)
|
178
210
|
end
|
179
211
|
|
180
|
-
# this is a convenience method for accessing the class that wraps all the
|
212
|
+
# this is a convenience method for accessing the class that wraps all the
|
181
213
|
# actual 'git' forked system calls. At some point I hope to replace the Git::Lib
|
182
214
|
# class with one that uses native methods or libgit C bindings
|
183
215
|
def lib
|
184
216
|
@lib ||= Git::Lib.new(self, @logger)
|
185
217
|
end
|
186
|
-
|
187
|
-
#
|
188
|
-
#
|
189
|
-
# to be more surgical in your grep, you can call grep() off a specific
|
190
|
-
# git object. for example:
|
191
|
-
#
|
192
|
-
# @git.object("v2.3").grep('TODO')
|
193
|
-
#
|
194
|
-
# in any case, it returns a hash of arrays of the type:
|
195
|
-
# hsh[tree-ish] = [[line_no, match], [line_no, match2]]
|
196
|
-
# hsh[tree-ish] = [[line_no, match], [line_no, match2]]
|
218
|
+
|
219
|
+
# Run a grep for 'string' on the HEAD of the git repository
|
197
220
|
#
|
198
|
-
#
|
221
|
+
# @example Limit grep's scope by calling grep() from a specific object:
|
222
|
+
# git.object("v2.3").grep('TODO')
|
199
223
|
#
|
200
|
-
#
|
224
|
+
# @example Using grep results:
|
225
|
+
# git.grep("TODO").each do |sha, arr|
|
201
226
|
# puts "in blob #{sha}:"
|
202
|
-
# arr.each do |
|
203
|
-
# puts "\t line #{
|
227
|
+
# arr.each do |line_no, match_string|
|
228
|
+
# puts "\t line #{line_no}: '#{match_string}'"
|
204
229
|
# end
|
205
230
|
# end
|
231
|
+
#
|
232
|
+
# @return [Hash<String, Array>] a hash of arrays
|
233
|
+
# ```Ruby
|
234
|
+
# {
|
235
|
+
# 'tree-ish1' => [[line_no1, match_string1], ...],
|
236
|
+
# 'tree-ish2' => [[line_no1, match_string1], ...],
|
237
|
+
# ...
|
238
|
+
# }
|
239
|
+
# ```
|
240
|
+
#
|
206
241
|
def grep(string, path_limiter = nil, opts = {})
|
207
242
|
self.object('HEAD').grep(string, path_limiter, opts)
|
208
243
|
end
|
209
|
-
|
244
|
+
|
210
245
|
# updates the repository index using the working directory content
|
211
246
|
#
|
212
|
-
#
|
213
|
-
#
|
214
|
-
#
|
247
|
+
# @example
|
248
|
+
# git.add
|
249
|
+
# git.add('path/to/file')
|
250
|
+
# git.add(['path/to/file1','path/to/file2'])
|
251
|
+
# git.add(:all => true)
|
215
252
|
#
|
216
253
|
# options:
|
217
254
|
# :all => true
|
218
255
|
#
|
219
256
|
# @param [String,Array] paths files paths to be added (optional, default='.')
|
220
257
|
# @param [Hash] options
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
258
|
+
# @option options [boolean] :all
|
259
|
+
# Update the index not only where the working tree has a file matching
|
260
|
+
# <pathspec> but also where the index already has an entry.
|
261
|
+
# See [the --all option to git-add](https://git-scm.com/docs/git-add#Documentation/git-add.txt--A)
|
262
|
+
# for more details.
|
263
|
+
#
|
264
|
+
def add(paths = '.', **options)
|
265
|
+
self.lib.add(paths, options)
|
227
266
|
end
|
228
267
|
|
229
268
|
# removes file(s) from the git repository
|
@@ -282,7 +321,7 @@ module Git
|
|
282
321
|
end
|
283
322
|
|
284
323
|
# commits all pending changes in the index file to the git repository
|
285
|
-
#
|
324
|
+
#
|
286
325
|
# options:
|
287
326
|
# :all
|
288
327
|
# :allow_empty
|
@@ -292,10 +331,10 @@ module Git
|
|
292
331
|
def commit(message, opts = {})
|
293
332
|
self.lib.commit(message, opts)
|
294
333
|
end
|
295
|
-
|
334
|
+
|
296
335
|
# commits all pending changes in the index file to the git repository,
|
297
336
|
# but automatically adds all modified files without having to explicitly
|
298
|
-
# calling @git.add() on them.
|
337
|
+
# calling @git.add() on them.
|
299
338
|
def commit_all(message, opts = {})
|
300
339
|
opts = {:add_all => true}.merge(opts)
|
301
340
|
self.lib.commit(message, opts)
|
@@ -305,7 +344,7 @@ module Git
|
|
305
344
|
def checkout(branch = 'master', opts = {})
|
306
345
|
self.lib.checkout(branch, opts)
|
307
346
|
end
|
308
|
-
|
347
|
+
|
309
348
|
# checks out an old version of a file
|
310
349
|
def checkout_file(version, file)
|
311
350
|
self.lib.checkout_file(version,file)
|
@@ -328,12 +367,12 @@ module Git
|
|
328
367
|
|
329
368
|
self.lib.push(remote, branch, opts)
|
330
369
|
end
|
331
|
-
|
370
|
+
|
332
371
|
# merges one or more branches into the current working branch
|
333
372
|
#
|
334
373
|
# you can specify more than one branch to merge by passing an array of branches
|
335
|
-
def merge(branch, message = 'merge')
|
336
|
-
self.lib.merge(branch, message)
|
374
|
+
def merge(branch, message = 'merge', opts = {})
|
375
|
+
self.lib.merge(branch, message, opts)
|
337
376
|
end
|
338
377
|
|
339
378
|
# iterates over the files which are unmerged
|
@@ -350,7 +389,7 @@ module Git
|
|
350
389
|
def pull(remote='origin', branch='master')
|
351
390
|
self.lib.pull(remote, branch)
|
352
391
|
end
|
353
|
-
|
392
|
+
|
354
393
|
# returns an array of Git:Remote objects
|
355
394
|
def remotes
|
356
395
|
self.lib.remotes.map { |r| Git::Remote.new(self, r) }
|
@@ -358,7 +397,7 @@ module Git
|
|
358
397
|
|
359
398
|
# adds a new remote to this repository
|
360
399
|
# url can be a git url or a Git::Base object if it's a local reference
|
361
|
-
#
|
400
|
+
#
|
362
401
|
# @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git')
|
363
402
|
# @git.fetch('scotts_git')
|
364
403
|
# @git.merge('scotts_git/master')
|
@@ -396,48 +435,53 @@ module Git
|
|
396
435
|
end
|
397
436
|
|
398
437
|
# Creates a new git tag (Git::Tag)
|
399
|
-
# Usage:
|
400
|
-
# repo.add_tag('tag_name', object_reference)
|
401
|
-
# repo.add_tag('tag_name', object_reference, {:options => 'here'})
|
402
|
-
# repo.add_tag('tag_name', {:options => 'here'})
|
403
438
|
#
|
404
|
-
#
|
405
|
-
#
|
406
|
-
# :
|
407
|
-
# :
|
408
|
-
#
|
409
|
-
#
|
410
|
-
#
|
411
|
-
|
412
|
-
|
439
|
+
# @example
|
440
|
+
# repo.add_tag('tag_name', object_reference)
|
441
|
+
# repo.add_tag('tag_name', object_reference, {:options => 'here'})
|
442
|
+
# repo.add_tag('tag_name', {:options => 'here'})
|
443
|
+
#
|
444
|
+
# @param [String] name The name of the tag to add
|
445
|
+
# @param [Hash] options Opstions to pass to `git tag`.
|
446
|
+
# See [git-tag](https://git-scm.com/docs/git-tag) for more details.
|
447
|
+
# @option options [boolean] :annotate Make an unsigned, annotated tag object
|
448
|
+
# @option options [boolean] :a An alias for the `:annotate` option
|
449
|
+
# @option options [boolean] :d Delete existing tag with the given names.
|
450
|
+
# @option options [boolean] :f Replace an existing tag with the given name (instead of failing)
|
451
|
+
# @option options [String] :message Use the given tag message
|
452
|
+
# @option options [String] :m An alias for the `:message` option
|
453
|
+
# @option options [boolean] :s Make a GPG-signed tag.
|
454
|
+
#
|
455
|
+
def add_tag(name, *options)
|
456
|
+
self.lib.tag(name, *options)
|
413
457
|
self.tag(name)
|
414
458
|
end
|
415
|
-
|
416
|
-
# deletes a tag
|
417
|
-
def delete_tag(name)
|
459
|
+
|
460
|
+
# deletes a tag
|
461
|
+
def delete_tag(name)
|
418
462
|
self.lib.tag(name, {:d => true})
|
419
463
|
end
|
420
|
-
|
464
|
+
|
421
465
|
# creates an archive file of the given tree-ish
|
422
466
|
def archive(treeish, file = nil, opts = {})
|
423
467
|
self.object(treeish).archive(file, opts)
|
424
468
|
end
|
425
|
-
|
469
|
+
|
426
470
|
# repacks the repository
|
427
471
|
def repack
|
428
472
|
self.lib.repack
|
429
473
|
end
|
430
|
-
|
474
|
+
|
431
475
|
def gc
|
432
476
|
self.lib.gc
|
433
477
|
end
|
434
|
-
|
478
|
+
|
435
479
|
def apply(file)
|
436
480
|
if File.exist?(file)
|
437
481
|
self.lib.apply(file)
|
438
482
|
end
|
439
483
|
end
|
440
|
-
|
484
|
+
|
441
485
|
def apply_mail(file)
|
442
486
|
self.lib.apply_mail(file) if File.exist?(file)
|
443
487
|
end
|
@@ -450,9 +494,9 @@ module Git
|
|
450
494
|
def show(objectish=nil, path=nil)
|
451
495
|
self.lib.show(objectish, path)
|
452
496
|
end
|
453
|
-
|
497
|
+
|
454
498
|
## LOWER LEVEL INDEX OPERATIONS ##
|
455
|
-
|
499
|
+
|
456
500
|
def with_index(new_index) # :yields: new_index
|
457
501
|
old_index = @index
|
458
502
|
set_index(new_index, false)
|
@@ -460,10 +504,10 @@ module Git
|
|
460
504
|
set_index(old_index)
|
461
505
|
return_value
|
462
506
|
end
|
463
|
-
|
507
|
+
|
464
508
|
def with_temp_index &blk
|
465
509
|
# Workaround for JRUBY, since they handle the TempFile path different.
|
466
|
-
# MUST be improved to be safer and OS independent.
|
510
|
+
# MUST be improved to be safer and OS independent.
|
467
511
|
if RUBY_PLATFORM == 'java'
|
468
512
|
temp_path = "/tmp/temp-index-#{(0...15).map{ ('a'..'z').to_a[rand(26)] }.join}"
|
469
513
|
else
|
@@ -475,29 +519,29 @@ module Git
|
|
475
519
|
|
476
520
|
with_index(temp_path, &blk)
|
477
521
|
end
|
478
|
-
|
522
|
+
|
479
523
|
def checkout_index(opts = {})
|
480
524
|
self.lib.checkout_index(opts)
|
481
525
|
end
|
482
|
-
|
526
|
+
|
483
527
|
def read_tree(treeish, opts = {})
|
484
528
|
self.lib.read_tree(treeish, opts)
|
485
529
|
end
|
486
|
-
|
530
|
+
|
487
531
|
def write_tree
|
488
532
|
self.lib.write_tree
|
489
533
|
end
|
490
|
-
|
534
|
+
|
491
535
|
def write_and_commit_tree(opts = {})
|
492
536
|
tree = write_tree
|
493
537
|
commit_tree(tree, opts)
|
494
538
|
end
|
495
|
-
|
539
|
+
|
496
540
|
def update_ref(branch, commit)
|
497
541
|
branch(branch).update_ref(commit)
|
498
542
|
end
|
499
|
-
|
500
|
-
|
543
|
+
|
544
|
+
|
501
545
|
def ls_files(location=nil)
|
502
546
|
self.lib.ls_files(location)
|
503
547
|
end
|
@@ -505,14 +549,14 @@ module Git
|
|
505
549
|
def with_working(work_dir) # :yields: the Git::WorkingDirectory
|
506
550
|
return_value = false
|
507
551
|
old_working = @working_directory
|
508
|
-
set_working(work_dir)
|
552
|
+
set_working(work_dir)
|
509
553
|
Dir.chdir work_dir do
|
510
554
|
return_value = yield @working_directory
|
511
555
|
end
|
512
556
|
set_working(old_working)
|
513
557
|
return_value
|
514
558
|
end
|
515
|
-
|
559
|
+
|
516
560
|
def with_temp_working &blk
|
517
561
|
tempfile = Tempfile.new("temp-workdir")
|
518
562
|
temp_dir = tempfile.path
|
@@ -521,22 +565,23 @@ module Git
|
|
521
565
|
Dir.mkdir(temp_dir, 0700)
|
522
566
|
with_working(temp_dir, &blk)
|
523
567
|
end
|
524
|
-
|
525
|
-
|
568
|
+
|
569
|
+
|
526
570
|
# runs git rev-parse to convert the objectish to a full sha
|
527
571
|
#
|
528
|
-
#
|
529
|
-
#
|
530
|
-
#
|
572
|
+
# @example
|
573
|
+
# git.revparse("HEAD^^")
|
574
|
+
# git.revparse('v2.4^{tree}')
|
575
|
+
# git.revparse('v2.4:/doc/index.html')
|
531
576
|
#
|
532
577
|
def revparse(objectish)
|
533
578
|
self.lib.revparse(objectish)
|
534
579
|
end
|
535
|
-
|
580
|
+
|
536
581
|
def ls_tree(objectish)
|
537
582
|
self.lib.ls_tree(objectish)
|
538
583
|
end
|
539
|
-
|
584
|
+
|
540
585
|
def cat_file(objectish)
|
541
586
|
self.lib.object_contents(objectish)
|
542
587
|
end
|
@@ -545,7 +590,7 @@ module Git
|
|
545
590
|
def current_branch
|
546
591
|
self.lib.branch_current
|
547
592
|
end
|
548
|
-
|
593
|
+
|
549
594
|
end
|
550
|
-
|
595
|
+
|
551
596
|
end
|