git 1.0.4 → 1.0.5
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.
- data/README +4 -13
- data/lib/git.rb +6 -2
- data/lib/git/base.rb +37 -5
- data/lib/git/branch.rb +5 -0
- data/lib/git/branches.rb +12 -0
- data/lib/git/lib.rb +157 -25
- data/lib/git/lib.rb.orig +620 -0
- data/lib/git/object.rb +13 -5
- data/lib/git/stash.rb +26 -0
- data/lib/git/stashes.rb +49 -0
- data/tests/files/working.git/info/refs +10 -0
- data/tests/files/working.git/objects/info/packs +2 -0
- data/tests/files/working.git/objects/pack/pack-6e99d3a243c58205968336728d5637ce2a3b2aff.idx +0 -0
- data/tests/files/working.git/objects/pack/pack-6e99d3a243c58205968336728d5637ce2a3b2aff.pack +0 -0
- data/tests/files/working/dot_git/config +3 -0
- data/tests/test_helper.rb +11 -0
- data/tests/units/test_config.rb +3 -3
- data/tests/units/test_each_conflict.rb +49 -0
- data/tests/units/test_index_ops.rb +1 -1
- data/tests/units/test_lib.rb +9 -0
- data/tests/units/test_log.rb +2 -1
- data/tests/units/test_logger.rb +38 -0
- data/tests/units/test_object.rb +5 -0
- data/tests/units/test_stashes.rb +36 -0
- metadata +12 -2
data/README
CHANGED
@@ -10,14 +10,7 @@ http://jointheconversation.org/rubygit
|
|
10
10
|
|
11
11
|
Git public hosting of the project source code is at:
|
12
12
|
|
13
|
-
http://
|
14
|
-
|
15
|
-
= Roadmap
|
16
|
-
|
17
|
-
Right now I'm forking calls to the 'git' binary,
|
18
|
-
but eventually I'll replace that with either C bindings
|
19
|
-
to libgit or libgit-thin, or I'll write pure ruby
|
20
|
-
handlers for at least some of the Git stuff.
|
13
|
+
http://github/schacon/ruby-git
|
21
14
|
|
22
15
|
= Major Objects
|
23
16
|
|
@@ -45,8 +38,7 @@ Git::Remote - A reference to a remote repository that is tracked by this reposit
|
|
45
38
|
Git::Log - An Enumerable object that references all the Git::Object::Commit objects that encompass
|
46
39
|
your log query, which can be constructed through methods on the Git::Log object, like:
|
47
40
|
|
48
|
-
@git.log(20).object("
|
49
|
-
|
41
|
+
@git.log(20).object("some_file").since("2 weeks ago").between('v2.6', 'v2.7').each { |commit| [block] }
|
50
42
|
|
51
43
|
= Examples
|
52
44
|
|
@@ -59,8 +51,7 @@ First you have to remember to require rubygems if it's not. Then include the 'g
|
|
59
51
|
|
60
52
|
Here are the operations that need read permission only.
|
61
53
|
|
62
|
-
g = Git.open (working_dir
|
63
|
-
(git_dir, index_file)
|
54
|
+
g = Git.open (working_dir, :log => Logger.new(STDOUT))
|
64
55
|
|
65
56
|
g.index
|
66
57
|
g.index.readable?
|
@@ -244,4 +235,4 @@ Some examples of more low-level index and tree operations
|
|
244
235
|
# do file work
|
245
236
|
g.commit # commits to index
|
246
237
|
end
|
247
|
-
|
238
|
+
|
data/lib/git.rb
CHANGED
@@ -23,6 +23,10 @@ require 'git/diff'
|
|
23
23
|
require 'git/status'
|
24
24
|
require 'git/author'
|
25
25
|
|
26
|
+
require 'git/stashes'
|
27
|
+
require 'git/stash'
|
28
|
+
|
29
|
+
|
26
30
|
# Git/Ruby Library
|
27
31
|
#
|
28
32
|
# This provides bindings for working with git in complex
|
@@ -48,8 +52,8 @@ module Git
|
|
48
52
|
# it expects not to be able to use a working directory
|
49
53
|
# so you can't checkout stuff, commit things, etc.
|
50
54
|
# but you can do most read operations
|
51
|
-
def self.bare(git_dir)
|
52
|
-
Base.bare(git_dir)
|
55
|
+
def self.bare(git_dir, options = {})
|
56
|
+
Base.bare(git_dir, options)
|
53
57
|
end
|
54
58
|
|
55
59
|
# open an existing git working directory
|
data/lib/git/base.rb
CHANGED
@@ -7,10 +7,14 @@ module Git
|
|
7
7
|
@index = nil
|
8
8
|
|
9
9
|
@lib = nil
|
10
|
+
@logger = nil
|
10
11
|
|
11
12
|
# opens a bare Git Repository - no working directory options
|
12
|
-
def self.bare(git_dir)
|
13
|
-
|
13
|
+
def self.bare(git_dir, opts = {})
|
14
|
+
default = {:repository => git_dir}
|
15
|
+
git_options = default.merge(opts)
|
16
|
+
|
17
|
+
self.new(git_options)
|
14
18
|
end
|
15
19
|
|
16
20
|
# opens a new Git Project from a working directory
|
@@ -67,6 +71,10 @@ module Git
|
|
67
71
|
options[:repository] = File.join(working_dir, '.git') if !options[:repository]
|
68
72
|
options[:index] = File.join(working_dir, '.git', 'index') if !options[:index]
|
69
73
|
end
|
74
|
+
if options[:log]
|
75
|
+
@logger = options[:log]
|
76
|
+
@logger.info("Starting Git")
|
77
|
+
end
|
70
78
|
|
71
79
|
@working_directory = Git::WorkingDirectory.new(options[:working_directory]) if options[:working_directory]
|
72
80
|
@repository = Git::Repository.new(options[:repository]) if options[:repository]
|
@@ -122,7 +130,7 @@ module Git
|
|
122
130
|
def repo_size
|
123
131
|
size = 0
|
124
132
|
Dir.chdir(repo.path) do
|
125
|
-
(size, dot) = `du -
|
133
|
+
(size, dot) = `du -s`.chomp.split
|
126
134
|
end
|
127
135
|
size.to_i
|
128
136
|
end
|
@@ -199,7 +207,7 @@ module Git
|
|
199
207
|
# actual 'git' forked system calls. At some point I hope to replace the Git::Lib
|
200
208
|
# class with one that uses native methods or libgit C bindings
|
201
209
|
def lib
|
202
|
-
@lib ||= Git::Lib.new(self)
|
210
|
+
@lib ||= Git::Lib.new(self, @logger)
|
203
211
|
end
|
204
212
|
|
205
213
|
# will run a grep for 'string' on the HEAD of the git repository
|
@@ -269,6 +277,11 @@ module Git
|
|
269
277
|
self.lib.checkout(branch, opts)
|
270
278
|
end
|
271
279
|
|
280
|
+
# checks out an old version of a file
|
281
|
+
def checkout_file(version, file)
|
282
|
+
self.lib.checkout_file(version,file)
|
283
|
+
end
|
284
|
+
|
272
285
|
# fetches changes from a remote branch - this does not modify the working directory,
|
273
286
|
# it just gets the changes from the remote if there are any
|
274
287
|
def fetch(remote = 'origin')
|
@@ -291,6 +304,13 @@ module Git
|
|
291
304
|
self.lib.merge(branch, message)
|
292
305
|
end
|
293
306
|
|
307
|
+
# iterates over the files which are unmerged
|
308
|
+
#
|
309
|
+
# yields file, your_version, their_version
|
310
|
+
def each_conflict(&block)
|
311
|
+
self.lib.conflicts(&block)
|
312
|
+
end
|
313
|
+
|
294
314
|
# fetches a branch from a remote and merges it into the current working branch
|
295
315
|
def pull(remote = 'origin', branch = 'master', message = 'origin pull')
|
296
316
|
fetch(remote)
|
@@ -343,6 +363,10 @@ module Git
|
|
343
363
|
self.lib.repack
|
344
364
|
end
|
345
365
|
|
366
|
+
def gc
|
367
|
+
self.lib.gc
|
368
|
+
end
|
369
|
+
|
346
370
|
|
347
371
|
## LOWER LEVEL INDEX OPERATIONS ##
|
348
372
|
|
@@ -420,6 +444,14 @@ module Git
|
|
420
444
|
def revparse(objectish)
|
421
445
|
self.lib.revparse(objectish)
|
422
446
|
end
|
447
|
+
|
448
|
+
def ls_tree(objectish)
|
449
|
+
self.lib.ls_tree(objectish)
|
450
|
+
end
|
451
|
+
|
452
|
+
def cat_file(objectish)
|
453
|
+
self.lib.object_contents(objectish)
|
454
|
+
end
|
423
455
|
|
424
456
|
# returns the name of the branch the working directory is currently on
|
425
457
|
def current_branch
|
@@ -429,4 +461,4 @@ module Git
|
|
429
461
|
|
430
462
|
end
|
431
463
|
|
432
|
-
end
|
464
|
+
end
|
data/lib/git/branch.rb
CHANGED
@@ -5,6 +5,7 @@ module Git
|
|
5
5
|
|
6
6
|
@base = nil
|
7
7
|
@gcommit = nil
|
8
|
+
@stashes = nil
|
8
9
|
|
9
10
|
def initialize(base, name)
|
10
11
|
@remote = nil
|
@@ -25,6 +26,10 @@ module Git
|
|
25
26
|
@gcommit
|
26
27
|
end
|
27
28
|
|
29
|
+
def stashes
|
30
|
+
@stashes ||= Git::Stashes.new(@base)
|
31
|
+
end
|
32
|
+
|
28
33
|
def checkout
|
29
34
|
check_if_create
|
30
35
|
@base.checkout(@full)
|
data/lib/git/branches.rb
CHANGED
data/lib/git/lib.rb
CHANGED
@@ -11,8 +11,10 @@ module Git
|
|
11
11
|
@git_index_file = nil
|
12
12
|
@git_work_dir = nil
|
13
13
|
@path = nil
|
14
|
-
|
15
|
-
|
14
|
+
|
15
|
+
@logger = nil
|
16
|
+
|
17
|
+
def initialize(base = nil, logger = nil)
|
16
18
|
if base.is_a?(Git::Base)
|
17
19
|
@git_dir = base.repo.path
|
18
20
|
@git_index_file = base.index.path if base.index
|
@@ -22,6 +24,9 @@ module Git
|
|
22
24
|
@git_index_file = base[:index]
|
23
25
|
@git_work_dir = base[:working_directory]
|
24
26
|
end
|
27
|
+
if logger
|
28
|
+
@logger = logger
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
32
|
def init
|
@@ -85,6 +90,16 @@ module Git
|
|
85
90
|
if /\w{40}/.match(string) # passing in a sha - just no-op it
|
86
91
|
return string
|
87
92
|
end
|
93
|
+
|
94
|
+
head = File.join(@git_dir, 'refs', 'heads', string)
|
95
|
+
return File.read(head).chomp if File.file?(head)
|
96
|
+
|
97
|
+
head = File.join(@git_dir, 'refs', 'remotes', string)
|
98
|
+
return File.read(head).chomp if File.file?(head)
|
99
|
+
|
100
|
+
head = File.join(@git_dir, 'refs', 'tags', string)
|
101
|
+
return File.read(head).chomp if File.file?(head)
|
102
|
+
|
88
103
|
command('rev-parse', string)
|
89
104
|
end
|
90
105
|
|
@@ -109,7 +124,7 @@ module Git
|
|
109
124
|
|
110
125
|
def process_commit_data(data, sha = nil)
|
111
126
|
in_message = false
|
112
|
-
|
127
|
+
|
113
128
|
if sha
|
114
129
|
hsh = {'sha' => sha, 'message' => '', 'parent' => []}
|
115
130
|
else
|
@@ -117,6 +132,7 @@ module Git
|
|
117
132
|
end
|
118
133
|
|
119
134
|
data.each do |line|
|
135
|
+
line = line.chomp
|
120
136
|
if in_message && line != ''
|
121
137
|
hsh['message'] += line + "\n"
|
122
138
|
end
|
@@ -156,14 +172,32 @@ module Git
|
|
156
172
|
|
157
173
|
def ls_tree(sha)
|
158
174
|
data = {'blob' => {}, 'tree' => {}}
|
175
|
+
|
159
176
|
command_lines('ls-tree', sha.to_s).each do |line|
|
160
177
|
(info, filenm) = line.split("\t")
|
161
178
|
(mode, type, sha) = info.split
|
162
179
|
data[type][filenm] = {:mode => mode, :sha => sha}
|
163
180
|
end
|
181
|
+
|
164
182
|
data
|
165
183
|
end
|
166
184
|
|
185
|
+
def mv(file1, file2)
|
186
|
+
command_lines('mv', [file1, file2])
|
187
|
+
end
|
188
|
+
|
189
|
+
def full_tree(sha)
|
190
|
+
command_lines('ls-tree', ['-r', sha.to_s])
|
191
|
+
end
|
192
|
+
|
193
|
+
def tree_depth(sha)
|
194
|
+
full_tree(sha).size
|
195
|
+
end
|
196
|
+
|
197
|
+
def change_head_branch(branch_name)
|
198
|
+
command('symbolic-ref', ['HEAD', "refs/heads/#{branch_name}"])
|
199
|
+
end
|
200
|
+
|
167
201
|
def branches_all
|
168
202
|
arr = []
|
169
203
|
command_lines('branch', '-a').each do |b|
|
@@ -174,6 +208,13 @@ module Git
|
|
174
208
|
arr
|
175
209
|
end
|
176
210
|
|
211
|
+
def list_files(ref_dir)
|
212
|
+
dir = File.join(@git_dir, 'refs', ref_dir)
|
213
|
+
files = []
|
214
|
+
Dir.chdir(dir) { files = Dir.glob('**/*').select { |f| File.file?(f) } } rescue nil
|
215
|
+
files
|
216
|
+
end
|
217
|
+
|
177
218
|
def branch_current
|
178
219
|
branches_all.select { |b| b[1] }.first[0] rescue nil
|
179
220
|
end
|
@@ -267,22 +308,47 @@ module Git
|
|
267
308
|
|
268
309
|
def config_remote(name)
|
269
310
|
hsh = {}
|
270
|
-
|
271
|
-
(key
|
272
|
-
|
311
|
+
config_list.each do |key, value|
|
312
|
+
if /remote.#{name}/.match(key)
|
313
|
+
hsh[key.gsub("remote.#{name}.", '')] = value
|
314
|
+
end
|
273
315
|
end
|
274
316
|
hsh
|
275
317
|
end
|
276
318
|
|
277
319
|
def config_get(name)
|
278
|
-
|
320
|
+
c = config_list
|
321
|
+
c[name]
|
322
|
+
#command('config', ['--get', name])
|
279
323
|
end
|
280
324
|
|
281
325
|
def config_list
|
326
|
+
config = {}
|
327
|
+
config.merge!(parse_config('~/.gitconfig'))
|
328
|
+
config.merge!(parse_config(File.join(@git_dir, 'config')))
|
329
|
+
#hsh = {}
|
330
|
+
#command_lines('config', ['--list']).each do |line|
|
331
|
+
# (key, value) = line.split('=')
|
332
|
+
# hsh[key] = value
|
333
|
+
#end
|
334
|
+
#hsh
|
335
|
+
end
|
336
|
+
|
337
|
+
def parse_config(file)
|
282
338
|
hsh = {}
|
283
|
-
|
284
|
-
|
285
|
-
|
339
|
+
file = File.expand_path(file)
|
340
|
+
if File.file?(file)
|
341
|
+
current_section = nil
|
342
|
+
File.readlines(file).each do |line|
|
343
|
+
if m = /\[(\w+)\]/.match(line)
|
344
|
+
current_section = m[1]
|
345
|
+
elsif m = /\[(\w+?) "(.*?)"\]/.match(line)
|
346
|
+
current_section = "#{m[1]}.#{m[2]}"
|
347
|
+
elsif m = /(\w+?) = (.*)/.match(line)
|
348
|
+
key = "#{current_section}.#{m[1]}"
|
349
|
+
hsh[key] = m[2]
|
350
|
+
end
|
351
|
+
end
|
286
352
|
end
|
287
353
|
hsh
|
288
354
|
end
|
@@ -320,14 +386,44 @@ module Git
|
|
320
386
|
arr_opts << commit.to_s if commit
|
321
387
|
command('reset', arr_opts)
|
322
388
|
end
|
389
|
+
|
390
|
+
def stashes_all
|
391
|
+
arr = []
|
392
|
+
filename = File.join(@git_dir, 'logs/refs/stash')
|
393
|
+
if File.exist?(filename)
|
394
|
+
File.open(filename).each_with_index { |line, i|
|
395
|
+
m = line.match(/:(.*)$/)
|
396
|
+
arr << [i, m[1].strip]
|
397
|
+
}
|
398
|
+
end
|
399
|
+
arr
|
400
|
+
end
|
401
|
+
|
402
|
+
def stash_save(message)
|
403
|
+
output = command('stash save', [message])
|
404
|
+
return false unless output.match(/HEAD is now at/)
|
405
|
+
return true
|
406
|
+
end
|
323
407
|
|
324
|
-
|
408
|
+
def stash_apply(id)
|
409
|
+
command('stash apply', [id])
|
410
|
+
# Already uptodate! ---???? What then
|
411
|
+
end
|
412
|
+
|
413
|
+
def stash_clear
|
414
|
+
command('stash clear')
|
415
|
+
end
|
416
|
+
|
417
|
+
def stash_list
|
418
|
+
command('stash list')
|
419
|
+
end
|
420
|
+
|
325
421
|
def branch_new(branch)
|
326
422
|
command('branch', branch)
|
327
423
|
end
|
328
424
|
|
329
425
|
def branch_delete(branch)
|
330
|
-
command('branch', ['-
|
426
|
+
command('branch', ['-D', branch])
|
331
427
|
end
|
332
428
|
|
333
429
|
def checkout(branch, opts = {})
|
@@ -337,6 +433,13 @@ module Git
|
|
337
433
|
|
338
434
|
command('checkout', arr_opts)
|
339
435
|
end
|
436
|
+
|
437
|
+
def checkout_file(version, file)
|
438
|
+
arr_opts = []
|
439
|
+
arr_opts << version.to_s
|
440
|
+
arr_opts << file.to_s
|
441
|
+
command('checkout', arr_opts)
|
442
|
+
end
|
340
443
|
|
341
444
|
def merge(branch, message = nil)
|
342
445
|
arr_opts = []
|
@@ -344,7 +447,28 @@ module Git
|
|
344
447
|
arr_opts << branch.to_a.join(' ')
|
345
448
|
command('merge', arr_opts)
|
346
449
|
end
|
347
|
-
|
450
|
+
|
451
|
+
def unmerged
|
452
|
+
unmerged = []
|
453
|
+
command_lines('diff', ["--cached"]).each do |line|
|
454
|
+
unmerged << $1 if line =~ /^\* Unmerged path (.*)/
|
455
|
+
end
|
456
|
+
unmerged
|
457
|
+
end
|
458
|
+
|
459
|
+
def conflicts #yields :file, :your, :their
|
460
|
+
self.unmerged.each do |f|
|
461
|
+
your = Tempfile.new("YOUR-#{File.basename(f)}").path
|
462
|
+
arr_opts = [":2:#{f}", ">#{your}"]
|
463
|
+
command('show', arr_opts)
|
464
|
+
|
465
|
+
their = Tempfile.new("THEIR-#{File.basename(f)}").path
|
466
|
+
arr_opts = [":3:#{f}", ">#{their}"]
|
467
|
+
command('show', arr_opts)
|
468
|
+
yield(f, your, their)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
348
472
|
def remote_add(name, url, opts = {})
|
349
473
|
arr_opts = ['add']
|
350
474
|
arr_opts << '-f' if opts[:with_fetch]
|
@@ -382,6 +506,9 @@ module Git
|
|
382
506
|
end
|
383
507
|
|
384
508
|
def tag_sha(tag_name)
|
509
|
+
head = File.join(@git_dir, 'refs', 'tags', tag_name)
|
510
|
+
return File.read(head).chomp if File.exists?(head)
|
511
|
+
|
385
512
|
command('show-ref', ['--tags', '-s', tag_name])
|
386
513
|
end
|
387
514
|
|
@@ -389,6 +516,10 @@ module Git
|
|
389
516
|
command('repack', ['-a', '-d'])
|
390
517
|
end
|
391
518
|
|
519
|
+
def gc
|
520
|
+
command('gc', ['--prune', '--aggressive', '--auto'])
|
521
|
+
end
|
522
|
+
|
392
523
|
# reads a tree into the current index file
|
393
524
|
def read_tree(treeish, opts = {})
|
394
525
|
arr_opts = []
|
@@ -403,9 +534,9 @@ module Git
|
|
403
534
|
|
404
535
|
def commit_tree(tree, opts = {})
|
405
536
|
opts[:message] = "commit tree #{tree}" if !opts[:message]
|
406
|
-
t = Tempfile.new('commit-message')
|
407
|
-
|
408
|
-
|
537
|
+
t = Tempfile.new('commit-message')
|
538
|
+
t.write(opts[:message])
|
539
|
+
t.close
|
409
540
|
|
410
541
|
arr_opts = []
|
411
542
|
arr_opts << tree
|
@@ -461,11 +592,11 @@ module Git
|
|
461
592
|
|
462
593
|
private
|
463
594
|
|
464
|
-
def command_lines(cmd, opts =
|
595
|
+
def command_lines(cmd, opts = [], chdir = true)
|
465
596
|
command(cmd, opts, chdir).split("\n")
|
466
597
|
end
|
467
598
|
|
468
|
-
def command(cmd, opts =
|
599
|
+
def command(cmd, opts = [], chdir = true)
|
469
600
|
ENV['GIT_DIR'] = @git_dir if (@git_dir != ENV['GIT_DIR'])
|
470
601
|
ENV['GIT_INDEX_FILE'] = @git_index_file if (@git_index_file != ENV['GIT_INDEX_FILE'])
|
471
602
|
ENV['GIT_WORK_TREE'] = @git_work_dir if (@git_work_dir != ENV['GIT_WORK_TREE'])
|
@@ -476,15 +607,16 @@ module Git
|
|
476
607
|
|
477
608
|
out = nil
|
478
609
|
if chdir && (Dir.getwd != path)
|
479
|
-
Dir.chdir(path) { out =
|
610
|
+
Dir.chdir(path) { out = `#{git_cmd} 2>&1`.chomp }
|
480
611
|
else
|
481
|
-
out =
|
612
|
+
out = `#{git_cmd} 2>&1`.chomp
|
482
613
|
end
|
483
614
|
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
615
|
+
if @logger
|
616
|
+
@logger.info(git_cmd)
|
617
|
+
@logger.debug(out)
|
618
|
+
end
|
619
|
+
|
488
620
|
if $?.exitstatus > 0
|
489
621
|
if $?.exitstatus == 1 && out == ''
|
490
622
|
return ''
|
@@ -495,4 +627,4 @@ module Git
|
|
495
627
|
end
|
496
628
|
|
497
629
|
end
|
498
|
-
end
|
630
|
+
end
|