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 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://repo.or.cz/w/rubygit.git
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("HEAD^").since("2 weeks ago").between('v2.6', 'v2.7').each { |commit| [block] }
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
@@ -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
- self.new :repository => git_dir
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 -d0`.chomp.split
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
@@ -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)
@@ -41,5 +41,17 @@ module Git
41
41
  @branches[symbol.to_s]
42
42
  end
43
43
 
44
+ def to_s
45
+ out = ''
46
+ @branches.each do |k, b|
47
+ if b.current
48
+ out += "* " + b.to_s + "\n"
49
+ else
50
+ out += " " + b.to_s + "\n"
51
+ end
52
+ end
53
+ out
54
+ end
55
+
44
56
  end
45
57
  end
@@ -11,8 +11,10 @@ module Git
11
11
  @git_index_file = nil
12
12
  @git_work_dir = nil
13
13
  @path = nil
14
-
15
- def initialize(base = nil)
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
- command_lines('config', ['--get-regexp', "remote.#{name}"]).each do |line|
271
- (key, value) = line.split
272
- hsh[key.gsub("remote.#{name}.", '')] = value
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
- command('config', ['--get', name])
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
- command_lines('config', ['--list']).each do |line|
284
- (key, value) = line.split('=')
285
- hsh[key] = value
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', ['-d', 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') do |t|
407
- t.write(opts[:message])
408
- end
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 = {}, chdir = true)
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 = {}, chdir = true)
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 = `git #{cmd} #{opts} 2>&1`.chomp }
610
+ Dir.chdir(path) { out = `#{git_cmd} 2>&1`.chomp }
480
611
  else
481
- out = `git #{cmd} #{opts} 2>&1`.chomp
612
+ out = `#{git_cmd} 2>&1`.chomp
482
613
  end
483
614
 
484
- #puts git_cmd
485
- #puts out
486
- #puts
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