spikegrobstein-git 1.2.7

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.
data/lib/git/author.rb ADDED
@@ -0,0 +1,14 @@
1
+ module Git
2
+ class Author
3
+ attr_accessor :name, :email, :date
4
+
5
+ def initialize(author_string)
6
+ if m = /(.*?) <(.*?)> (\d+) (.*)/.match(author_string)
7
+ @name = m[1]
8
+ @email = m[2]
9
+ @date = Time.at(m[3].to_i)
10
+ end
11
+ end
12
+
13
+ end
14
+ end
data/lib/git/base.rb ADDED
@@ -0,0 +1,560 @@
1
+ module Git
2
+
3
+ class Base
4
+
5
+ # opens a bare Git Repository - no working directory options
6
+ def self.bare(git_dir, opts = {})
7
+ self.new({:repository => git_dir}.merge(opts))
8
+ end
9
+
10
+ # opens a new Git Project from a working directory
11
+ # you can specify non-standard git_dir and index file in the options
12
+ def self.open(working_dir, opts={})
13
+ self.new({:working_directory => working_dir}.merge(opts))
14
+ end
15
+
16
+ # initializes a git repository
17
+ #
18
+ # options:
19
+ # :bare
20
+ # :index
21
+ # :repository
22
+ #
23
+ def self.init(working_dir, opts = {})
24
+ opts[:working_directory] = working_dir if !opts[:working_directory]
25
+ opts[:repository] = File.join(opts[:working_directory], '.git') if !opts[:repository]
26
+
27
+ FileUtils.mkdir_p(opts[:working_directory]) if opts[:working_directory] && !File.directory?(opts[:working_directory])
28
+
29
+ init_opts = {
30
+ :bare => opts[:bare]
31
+ }
32
+
33
+ opts.delete(:working_directory) if opts[:bare]
34
+
35
+ Git::Lib.new(opts).init(init_opts)
36
+
37
+ self.new(opts)
38
+ end
39
+
40
+ # clones a git repository locally
41
+ #
42
+ # repository - http://repo.or.cz/w/sinatra.git
43
+ # name - sinatra
44
+ #
45
+ # options:
46
+ # :repository
47
+ #
48
+ # :bare
49
+ # or
50
+ # :working_directory
51
+ # :index_file
52
+ #
53
+ def self.clone(repository, name, opts = {})
54
+ # run git-clone
55
+ self.new(Git::Lib.new.clone(repository, name, opts))
56
+ end
57
+
58
+ def initialize(options = {})
59
+ if working_dir = options[:working_directory]
60
+ options[:repository] ||= File.join(working_dir, '.git')
61
+ options[:index] ||= File.join(working_dir, '.git', 'index')
62
+ end
63
+ if options[:log]
64
+ @logger = options[:log]
65
+ @logger.info("Starting Git")
66
+ else
67
+ @logger = nil
68
+ end
69
+
70
+ @working_directory = options[:working_directory] ? Git::WorkingDirectory.new(options[:working_directory]) : nil
71
+ @repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil
72
+ @index = options[:index] ? Git::Index.new(options[:index], false) : nil
73
+ end
74
+
75
+
76
+ # returns a reference to the working directory
77
+ # @git.dir.path
78
+ # @git.dir.writeable?
79
+ def dir
80
+ @working_directory
81
+ end
82
+
83
+ # returns reference to the git repository directory
84
+ # @git.dir.path
85
+ def repo
86
+ @repository
87
+ end
88
+
89
+ # returns reference to the git index file
90
+ def index
91
+ @index
92
+ end
93
+
94
+
95
+ def set_working(work_dir, check = true)
96
+ @lib = nil
97
+ @working_directory = Git::WorkingDirectory.new(work_dir.to_s, check)
98
+ end
99
+
100
+ def set_index(index_file, check = true)
101
+ @lib = nil
102
+ @index = Git::Index.new(index_file.to_s, check)
103
+ end
104
+
105
+ # changes current working directory for a block
106
+ # to the git working directory
107
+ #
108
+ # example
109
+ # @git.chdir do
110
+ # # write files
111
+ # @git.add
112
+ # @git.commit('message')
113
+ # end
114
+ def chdir # :yields: the Git::Path
115
+ Dir.chdir(dir.path) do
116
+ yield dir.path
117
+ end
118
+ end
119
+
120
+ # returns the repository size in bytes
121
+ def repo_size
122
+ Dir.chdir(repo.path) do
123
+ return `du -s`.chomp.split.first.to_i
124
+ end
125
+ end
126
+
127
+ #g.config('user.name', 'Scott Chacon') # sets value
128
+ #g.config('user.email', 'email@email.com') # sets value
129
+ #g.config('user.name') # returns 'Scott Chacon'
130
+ #g.config # returns whole config hash
131
+ def config(name = nil, value = nil)
132
+ if(name && value)
133
+ # set value
134
+ lib.config_set(name, value)
135
+ elsif (name)
136
+ # return value
137
+ lib.config_get(name)
138
+ else
139
+ # return hash
140
+ lib.config_list
141
+ end
142
+ end
143
+
144
+ # factory methods
145
+
146
+ # returns a Git::Object of the appropriate type
147
+ # you can also call @git.gtree('tree'), but that's
148
+ # just for readability. If you call @git.gtree('HEAD') it will
149
+ # still return a Git::Object::Commit object.
150
+ #
151
+ # @git.object calls a factory method that will run a rev-parse
152
+ # on the objectish and determine the type of the object and return
153
+ # an appropriate object for that type
154
+ def object(objectish)
155
+ Git::Object.new(self, objectish)
156
+ end
157
+
158
+ def gtree(objectish)
159
+ Git::Object.new(self, objectish, 'tree')
160
+ end
161
+
162
+ def gcommit(objectish)
163
+ Git::Object.new(self, objectish, 'commit')
164
+ end
165
+
166
+ def gblob(objectish)
167
+ Git::Object.new(self, objectish, 'blob')
168
+ end
169
+
170
+ # returns a Git::Log object with count commits
171
+ def log(count = 30)
172
+ Git::Log.new(self, count)
173
+ end
174
+
175
+ # returns a Git::Status object
176
+ def status
177
+ Git::Status.new(self)
178
+ end
179
+
180
+ # returns a Git::Branches object of all the Git::Branch objects for this repo
181
+ def branches
182
+ Git::Branches.new(self)
183
+ end
184
+
185
+ # returns a Git::Branch object for branch_name
186
+ def branch(branch_name = 'master')
187
+ Git::Branch.new(self, branch_name)
188
+ end
189
+
190
+ # returns +true+ if the branch exists locally
191
+ def is_local_branch?(branch)
192
+ branch_names = self.branches.local.map {|b| b.name}
193
+ branch_names.include?(branch)
194
+ end
195
+
196
+ # returns +true+ if the branch exists remotely
197
+ def is_remote_branch?(branch)
198
+ branch_names = self.branches.local.map {|b| b.name}
199
+ branch_names.include?(branch)
200
+ end
201
+
202
+ # returns +true+ if the branch exists
203
+ def is_branch?(branch)
204
+ branch_names = self.branches.map {|b| b.name}
205
+ branch_names.include?(branch)
206
+ end
207
+
208
+ # returns a Git::Remote object
209
+ def remote(remote_name = 'origin')
210
+ Git::Remote.new(self, remote_name)
211
+ end
212
+
213
+ # this is a convenience method for accessing the class that wraps all the
214
+ # actual 'git' forked system calls. At some point I hope to replace the Git::Lib
215
+ # class with one that uses native methods or libgit C bindings
216
+ def lib
217
+ @lib ||= Git::Lib.new(self, @logger)
218
+ end
219
+
220
+ # will run a grep for 'string' on the HEAD of the git repository
221
+ #
222
+ # to be more surgical in your grep, you can call grep() off a specific
223
+ # git object. for example:
224
+ #
225
+ # @git.object("v2.3").grep('TODO')
226
+ #
227
+ # in any case, it returns a hash of arrays of the type:
228
+ # hsh[tree-ish] = [[line_no, match], [line_no, match2]]
229
+ # hsh[tree-ish] = [[line_no, match], [line_no, match2]]
230
+ #
231
+ # so you might use it like this:
232
+ #
233
+ # @git.grep("TODO").each do |sha, arr|
234
+ # puts "in blob #{sha}:"
235
+ # arr.each do |match|
236
+ # puts "\t line #{match[0]}: '#{match[1]}'"
237
+ # end
238
+ # end
239
+ def grep(string, path_limiter = nil, opts = {})
240
+ self.object('HEAD').grep(string, path_limiter, opts)
241
+ end
242
+
243
+ # returns a Git::Diff object
244
+ def diff(objectish = 'HEAD', obj2 = nil)
245
+ Git::Diff.new(self, objectish, obj2)
246
+ end
247
+
248
+ # updates the repository index using the workig dorectory content
249
+ #
250
+ # @git.add('path/to/file')
251
+ # @git.add(['path/to/file1','path/to/file2'])
252
+ # @git.add(:all => true)
253
+ #
254
+ # options:
255
+ # :all => true
256
+ #
257
+ # @param [String,Array] paths files paths to be added (optional, default='.')
258
+ # @param [Hash] options
259
+ def add(*args)
260
+ if args[0].instance_of?(String) || args[0].instance_of?(Array)
261
+ self.lib.add(args[0],args[1]||{})
262
+ else
263
+ self.lib.add('.', args[0]||{})
264
+ end
265
+ end
266
+
267
+ # removes file(s) from the git repository
268
+ def remove(path = '.', opts = {})
269
+ self.lib.remove(path, opts)
270
+ end
271
+
272
+ # resets the working directory to the provided commitish
273
+ def reset(commitish = nil, opts = {})
274
+ self.lib.reset(commitish, opts)
275
+ end
276
+
277
+ # resets the working directory to the commitish with '--hard'
278
+ def reset_hard(commitish = nil, opts = {})
279
+ opts = {:hard => true}.merge(opts)
280
+ self.lib.reset(commitish, opts)
281
+ end
282
+
283
+ # cleans the working directory
284
+ #
285
+ # options:
286
+ # :force
287
+ # :d
288
+ #
289
+ def clean(opts = {})
290
+ self.lib.clean(opts)
291
+ end
292
+
293
+ # reverts the working directory to the provided commitish.
294
+ # Accepts a range, such as comittish..HEAD
295
+ #
296
+ # options:
297
+ # :no_edit
298
+ #
299
+ def revert(commitish = nil, opts = {})
300
+ self.lib.revert(commitish, opts)
301
+ end
302
+
303
+ # commits all pending changes in the index file to the git repository
304
+ #
305
+ # options:
306
+ # :all
307
+ # :allow_empty
308
+ # :amend
309
+ # :author
310
+ #
311
+ def commit(message, opts = {})
312
+ self.lib.commit(message, opts)
313
+ end
314
+
315
+ # commits all pending changes in the index file to the git repository,
316
+ # but automatically adds all modified files without having to explicitly
317
+ # calling @git.add() on them.
318
+ def commit_all(message, opts = {})
319
+ opts = {:add_all => true}.merge(opts)
320
+ self.lib.commit(message, opts)
321
+ end
322
+
323
+ # checks out a branch as the new git working directory
324
+ def checkout(branch = 'master', opts = {})
325
+ self.lib.checkout(branch, opts)
326
+ end
327
+
328
+ # checks out an old version of a file
329
+ def checkout_file(version, file)
330
+ self.lib.checkout_file(version,file)
331
+ end
332
+
333
+ # fetches changes from a remote branch - this does not modify the working directory,
334
+ # it just gets the changes from the remote if there are any
335
+ def fetch(remote = 'origin', opts={})
336
+ self.lib.fetch(remote, opts)
337
+ end
338
+
339
+ # pushes changes to a remote repository - easiest if this is a cloned repository,
340
+ # otherwise you may have to run something like this first to setup the push parameters:
341
+ #
342
+ # @git.config('remote.remote-name.push', 'refs/heads/master:refs/heads/master')
343
+ #
344
+ def push(remote = 'origin', branch = 'master', opts = {})
345
+ # Small hack to keep backwards compatibility with the 'push(remote, branch, tags)' method signature.
346
+ opts = {:tags => opts} if [true, false].include?(opts)
347
+
348
+ self.lib.push(remote, branch, opts)
349
+ end
350
+
351
+ # merges one or more branches into the current working branch
352
+ #
353
+ # you can specify more than one branch to merge by passing an array of branches
354
+ def merge(branch, message = 'merge')
355
+ self.lib.merge(branch, message)
356
+ end
357
+
358
+ # iterates over the files which are unmerged
359
+ def each_conflict(&block) # :yields: file, your_version, their_version
360
+ self.lib.conflicts(&block)
361
+ end
362
+
363
+ # pulls the given branch from the given remote into the current branch
364
+ #
365
+ # @git.pull # pulls from origin/master
366
+ # @git.pull('upstream') # pulls from upstream/master
367
+ # @git.pull('upstream', 'develope') # pulls from upstream/develop
368
+ #
369
+ def pull(remote='origin', branch='master')
370
+ self.lib.pull(remote, branch)
371
+ end
372
+
373
+ # returns an array of Git:Remote objects
374
+ def remotes
375
+ self.lib.remotes.map { |r| Git::Remote.new(self, r) }
376
+ end
377
+
378
+ # adds a new remote to this repository
379
+ # url can be a git url or a Git::Base object if it's a local reference
380
+ #
381
+ # @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git')
382
+ # @git.fetch('scotts_git')
383
+ # @git.merge('scotts_git/master')
384
+ #
385
+ # Options:
386
+ # :fetch => true
387
+ # :track => <branch_name>
388
+ def add_remote(name, url, opts = {})
389
+ url = url.repo.path if url.is_a?(Git::Base)
390
+ self.lib.remote_add(name, url, opts)
391
+ Git::Remote.new(self, name)
392
+ end
393
+
394
+ # removes a remote from this repository
395
+ #
396
+ # @git.remove_remote('scott_git')
397
+ def remove_remote(name)
398
+ self.lib.remote_remove(name)
399
+ end
400
+
401
+ # returns an array of all Git::Tag objects for this repository
402
+ def tags
403
+ self.lib.tags.map { |r| tag(r) }
404
+ end
405
+
406
+ # returns a Git::Tag object
407
+ def tag(tag_name)
408
+ Git::Object.new(self, tag_name, 'tag', true)
409
+ end
410
+
411
+ # Creates a new git tag (Git::Tag)
412
+ # Usage:
413
+ # repo.add_tag('tag_name', object_reference)
414
+ # repo.add_tag('tag_name', object_reference, {:options => 'here'})
415
+ # repo.add_tag('tag_name', {:options => 'here'})
416
+ #
417
+ # Options:
418
+ # :a | :annotate -> true
419
+ # :d -> true
420
+ # :f -> true
421
+ # :m | :message -> String
422
+ # :s -> true
423
+ #
424
+ def add_tag(name, *opts)
425
+ self.lib.tag(name, *opts)
426
+ tag(name)
427
+ end
428
+
429
+ # deletes a tag
430
+ def delete_tag(name)
431
+ self.lib.tag(name, {:d => true})
432
+ end
433
+
434
+ # creates an archive file of the given tree-ish
435
+ def archive(treeish, file = nil, opts = {})
436
+ self.object(treeish).archive(file, opts)
437
+ end
438
+
439
+ # repacks the repository
440
+ def repack
441
+ self.lib.repack
442
+ end
443
+
444
+ def gc
445
+ self.lib.gc
446
+ end
447
+
448
+ def apply(file)
449
+ if File.exists?(file)
450
+ self.lib.apply(file)
451
+ end
452
+ end
453
+
454
+ def apply_mail(file)
455
+ self.lib.apply_mail(file) if File.exists?(file)
456
+ end
457
+
458
+ ## LOWER LEVEL INDEX OPERATIONS ##
459
+
460
+ def with_index(new_index) # :yields: new_index
461
+ old_index = @index
462
+ set_index(new_index, false)
463
+ return_value = yield @index
464
+ set_index(old_index)
465
+ return_value
466
+ end
467
+
468
+ def with_temp_index &blk
469
+ # Workaround for JRUBY, since they handle the TempFile path different.
470
+ # MUST be improved to be safer and OS independent.
471
+ if RUBY_PLATFORM == 'java'
472
+ temp_path = "/tmp/temp-index-#{(0...15).map{ ('a'..'z').to_a[rand(26)] }.join}"
473
+ else
474
+ tempfile = Tempfile.new('temp-index')
475
+ temp_path = tempfile.path
476
+ tempfile.close
477
+ tempfile.unlink
478
+ end
479
+
480
+ with_index(temp_path, &blk)
481
+ end
482
+
483
+ def checkout_index(opts = {})
484
+ self.lib.checkout_index(opts)
485
+ end
486
+
487
+ def read_tree(treeish, opts = {})
488
+ self.lib.read_tree(treeish, opts)
489
+ end
490
+
491
+ def write_tree
492
+ self.lib.write_tree
493
+ end
494
+
495
+ def commit_tree(tree = nil, opts = {})
496
+ Git::Object::Commit.new(self, self.lib.commit_tree(tree, opts))
497
+ end
498
+
499
+ def write_and_commit_tree(opts = {})
500
+ tree = write_tree
501
+ commit_tree(tree, opts)
502
+ end
503
+
504
+ def update_ref(branch, commit)
505
+ branch(branch).update_ref(commit)
506
+ end
507
+
508
+
509
+ def ls_files(location=nil)
510
+ self.lib.ls_files(location)
511
+ end
512
+
513
+ def with_working(work_dir) # :yields: the Git::WorkingDirectory
514
+ return_value = false
515
+ old_working = @working_directory
516
+ set_working(work_dir)
517
+ Dir.chdir work_dir do
518
+ return_value = yield @working_directory
519
+ end
520
+ set_working(old_working)
521
+ return_value
522
+ end
523
+
524
+ def with_temp_working &blk
525
+ tempfile = Tempfile.new("temp-workdir")
526
+ temp_dir = tempfile.path
527
+ tempfile.close
528
+ tempfile.unlink
529
+ Dir.mkdir(temp_dir, 0700)
530
+ with_working(temp_dir, &blk)
531
+ end
532
+
533
+
534
+ # runs git rev-parse to convert the objectish to a full sha
535
+ #
536
+ # @git.revparse("HEAD^^")
537
+ # @git.revparse('v2.4^{tree}')
538
+ # @git.revparse('v2.4:/doc/index.html')
539
+ #
540
+ def revparse(objectish)
541
+ self.lib.revparse(objectish)
542
+ end
543
+
544
+ def ls_tree(objectish)
545
+ self.lib.ls_tree(objectish)
546
+ end
547
+
548
+ def cat_file(objectish)
549
+ self.lib.object_contents(objectish)
550
+ end
551
+
552
+ # returns the name of the branch the working directory is currently on
553
+ def current_branch
554
+ self.lib.branch_current
555
+ end
556
+
557
+
558
+ end
559
+
560
+ end