schacon-grit 0.9.4 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/API.txt +101 -0
- data/History.txt +42 -2
- data/LICENSE +22 -0
- data/README.md +210 -0
- data/VERSION.yml +4 -0
- data/lib/grit.rb +17 -5
- data/lib/grit/blame.rb +61 -0
- data/lib/grit/blob.rb +11 -2
- data/lib/grit/commit.rb +44 -31
- data/lib/grit/commit_stats.rb +26 -2
- data/lib/grit/diff.rb +8 -8
- data/lib/grit/git-ruby.rb +87 -6
- data/lib/grit/git-ruby/git_object.rb +29 -6
- data/lib/grit/git-ruby/internal/{mmap.rb → file_window.rb} +2 -2
- data/lib/grit/git-ruby/internal/loose.rb +6 -6
- data/lib/grit/git-ruby/internal/pack.rb +22 -20
- data/lib/grit/git-ruby/object.rb +8 -2
- data/lib/grit/git-ruby/repository.rb +33 -24
- data/lib/grit/git.rb +189 -11
- data/lib/grit/index.rb +15 -14
- data/lib/grit/merge.rb +45 -0
- data/lib/grit/ref.rb +8 -29
- data/lib/grit/repo.rb +144 -21
- data/lib/grit/ruby1.9.rb +7 -0
- data/lib/grit/submodule.rb +5 -1
- data/lib/grit/tag.rb +22 -66
- data/lib/grit/tree.rb +20 -1
- metadata +32 -47
- data/Manifest.txt +0 -71
- data/README.txt +0 -213
- data/Rakefile +0 -29
- data/grit.gemspec +0 -62
- data/lib/grit/head.rb +0 -83
- data/test/test_actor.rb +0 -35
- data/test/test_blob.rb +0 -79
- data/test/test_commit.rb +0 -190
- data/test/test_config.rb +0 -58
- data/test/test_diff.rb +0 -18
- data/test/test_git.rb +0 -64
- data/test/test_grit.rb +0 -32
- data/test/test_head.rb +0 -47
- data/test/test_real.rb +0 -19
- data/test/test_reality.rb +0 -17
- data/test/test_remote.rb +0 -14
- data/test/test_repo.rb +0 -285
- data/test/test_tag.rb +0 -25
- data/test/test_tree.rb +0 -96
data/lib/grit/index.rb
CHANGED
@@ -29,12 +29,20 @@ module Grit
|
|
29
29
|
current[filename] = data
|
30
30
|
end
|
31
31
|
|
32
|
+
# Sets the current tree
|
33
|
+
# +tree+ the branch/tag/sha... to use - a string
|
34
|
+
#
|
35
|
+
# Returns index (self)
|
32
36
|
def read_tree(tree)
|
33
37
|
self.current_tree = self.repo.tree(tree)
|
34
38
|
end
|
35
39
|
|
36
40
|
# Commit the contents of the index
|
37
|
-
# +message+ is the commit message
|
41
|
+
# +message+ is the commit message [nil]
|
42
|
+
# +parents+ is one or more commits to attach this commit to to form a new head [nil]
|
43
|
+
# +actor+ is the details of the user making the commit [nil]
|
44
|
+
# +last_tree+ is a tree to compare with - to avoid making empty commits [nil]
|
45
|
+
# +head+ is the branch to write this head to [master]
|
38
46
|
#
|
39
47
|
# Returns a String of the SHA1 of the commit
|
40
48
|
def commit(message, parents = nil, actor = nil, last_tree = nil, head = 'master')
|
@@ -62,16 +70,9 @@ module Grit
|
|
62
70
|
contents << ''
|
63
71
|
contents << message
|
64
72
|
|
65
|
-
commit_sha1 = self.repo.git.
|
66
|
-
|
67
|
-
# self.repo.git.update_ref({}, 'HEAD', commit_sha1)
|
68
|
-
ref_heads = File.join(self.repo.path, 'refs', 'heads')
|
69
|
-
FileUtils.mkdir_p(ref_heads)
|
70
|
-
File.open(File.join(ref_heads, head), 'w') do |f|
|
71
|
-
f.write(commit_sha1)
|
72
|
-
end if commit_sha1
|
73
|
+
commit_sha1 = self.repo.git.put_raw_object(contents.join("\n"), 'commit')
|
73
74
|
|
74
|
-
commit_sha1
|
75
|
+
self.repo.update_ref(head, commit_sha1)
|
75
76
|
end
|
76
77
|
|
77
78
|
# Recursively write a tree to the index
|
@@ -92,12 +93,12 @@ module Grit
|
|
92
93
|
# overwrite with new tree contents
|
93
94
|
tree.each do |k, v|
|
94
95
|
case v
|
95
|
-
when String
|
96
|
+
when String
|
96
97
|
sha = write_blob(v)
|
97
98
|
sha = [sha].pack("H*")
|
98
99
|
str = "%s %s\0%s" % ['100644', k, sha]
|
99
100
|
tree_contents[k] = str
|
100
|
-
when Hash
|
101
|
+
when Hash
|
101
102
|
ctree = now_tree/k if now_tree
|
102
103
|
sha = write_tree(v, ctree)
|
103
104
|
sha = [sha].pack("H*")
|
@@ -106,7 +107,7 @@ module Grit
|
|
106
107
|
end
|
107
108
|
end
|
108
109
|
tr = tree_contents.sort.map { |k, v| v }.join('')
|
109
|
-
self.repo.git.
|
110
|
+
self.repo.git.put_raw_object(tr, 'tree')
|
110
111
|
end
|
111
112
|
|
112
113
|
# Write the blob to the index
|
@@ -114,7 +115,7 @@ module Grit
|
|
114
115
|
#
|
115
116
|
# Returns the SHA1 String of the blob
|
116
117
|
def write_blob(data)
|
117
|
-
self.repo.git.
|
118
|
+
self.repo.git.put_raw_object(data, 'blob')
|
118
119
|
end
|
119
120
|
end # Index
|
120
121
|
|
data/lib/grit/merge.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Merge
|
4
|
+
|
5
|
+
STATUS_BOTH = 'both'
|
6
|
+
STATUS_OURS = 'ours'
|
7
|
+
STATUS_THEIRS = 'theirs'
|
8
|
+
|
9
|
+
attr_reader :conflicts, :text, :sections
|
10
|
+
|
11
|
+
def initialize(str)
|
12
|
+
status = STATUS_BOTH
|
13
|
+
|
14
|
+
section = 1
|
15
|
+
@conflicts = 0
|
16
|
+
@text = {}
|
17
|
+
|
18
|
+
lines = str.split("\n")
|
19
|
+
lines.each do |line|
|
20
|
+
if /^<<<<<<< (.*?)/.match(line)
|
21
|
+
status = STATUS_OURS
|
22
|
+
@conflicts += 1
|
23
|
+
section += 1
|
24
|
+
elsif line == '======='
|
25
|
+
status = STATUS_THEIRS
|
26
|
+
elsif /^>>>>>>> (.*?)/.match(line)
|
27
|
+
status = STATUS_BOTH
|
28
|
+
section += 1
|
29
|
+
else
|
30
|
+
@text[section] ||= {}
|
31
|
+
@text[section][status] ||= []
|
32
|
+
@text[section][status] << line
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@text = @text.values
|
36
|
+
@sections = @text.size
|
37
|
+
end
|
38
|
+
|
39
|
+
# Pretty object inspection
|
40
|
+
def inspect
|
41
|
+
%Q{#<Grit::Merge}
|
42
|
+
end
|
43
|
+
end # Merge
|
44
|
+
|
45
|
+
end # Grit
|
data/lib/grit/ref.rb
CHANGED
@@ -9,32 +9,13 @@ module Grit
|
|
9
9
|
# +options+ is a Hash of options
|
10
10
|
#
|
11
11
|
# Returns Grit::Ref[] (baked)
|
12
|
-
def find_all(repo, options = {})
|
13
|
-
refs =
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
if m = /^(\w{40}) (.*?)$/.match(line)
|
19
|
-
next if !Regexp.new('^' + prefix).match(m[2])
|
20
|
-
name = m[2].sub("#{prefix}/", '')
|
21
|
-
commit = Commit.create(repo, :id => m[1])
|
22
|
-
refs << self.new(name, commit)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
files = Dir.glob(prefix + '/**/*')
|
28
|
-
files.each do |ref|
|
29
|
-
next if !File.file?(ref)
|
30
|
-
id = File.read(ref).chomp
|
31
|
-
name = ref.sub("#{prefix}/", '')
|
32
|
-
commit = Commit.create(repo, :id => id)
|
33
|
-
refs << self.new(name, commit)
|
34
|
-
end
|
12
|
+
def find_all(repo, options = {})
|
13
|
+
refs = repo.git.refs(options, prefix)
|
14
|
+
refs.split("\n").map do |ref|
|
15
|
+
name, id = *ref.split(' ')
|
16
|
+
commit = Commit.create(repo, :id => id)
|
17
|
+
self.new(name, commit)
|
35
18
|
end
|
36
|
-
|
37
|
-
refs
|
38
19
|
end
|
39
20
|
|
40
21
|
protected
|
@@ -80,7 +61,7 @@ module Grit
|
|
80
61
|
#
|
81
62
|
# Returns Grit::Head (baked)
|
82
63
|
def self.current(repo, options = {})
|
83
|
-
head =
|
64
|
+
head = repo.git.fs_read('HEAD').chomp
|
84
65
|
if /ref: refs\/heads\/(.*)/.match(head)
|
85
66
|
self.new($1, repo.git.rev_parse(options, 'HEAD'))
|
86
67
|
end
|
@@ -88,8 +69,6 @@ module Grit
|
|
88
69
|
|
89
70
|
end # Head
|
90
71
|
|
91
|
-
class Tag < Ref ; end
|
92
|
-
|
93
72
|
class Remote < Ref; end
|
94
|
-
|
73
|
+
|
95
74
|
end # Grit
|
data/lib/grit/repo.rb
CHANGED
@@ -13,6 +13,7 @@ module Grit
|
|
13
13
|
|
14
14
|
# Create a new Repo instance
|
15
15
|
# +path+ is the path to either the root git directory or the bare git repo
|
16
|
+
# +options+ :is_bare force to load a bare repo
|
16
17
|
#
|
17
18
|
# Examples
|
18
19
|
# g = Repo.new("/Users/tom/dev/grit")
|
@@ -37,7 +38,8 @@ module Grit
|
|
37
38
|
|
38
39
|
self.git = Git.new(self.path)
|
39
40
|
end
|
40
|
-
|
41
|
+
|
42
|
+
# Does nothing yet...
|
41
43
|
def self.init(path)
|
42
44
|
# !! TODO !!
|
43
45
|
# create directory
|
@@ -49,8 +51,13 @@ module Grit
|
|
49
51
|
#
|
50
52
|
# Returns String
|
51
53
|
def description
|
52
|
-
|
54
|
+
self.git.fs_read('description').chomp
|
55
|
+
end
|
56
|
+
|
57
|
+
def blame(file, commit = nil)
|
58
|
+
Blame.new(self, file, commit)
|
53
59
|
end
|
60
|
+
|
54
61
|
|
55
62
|
# An array of Head objects representing the branch heads in
|
56
63
|
# this repo
|
@@ -62,10 +69,14 @@ module Grit
|
|
62
69
|
|
63
70
|
alias_method :branches, :heads
|
64
71
|
|
65
|
-
def
|
72
|
+
def get_head(head_name)
|
66
73
|
heads.find { |h| h.name == head_name }
|
67
74
|
end
|
68
75
|
|
76
|
+
def is_head?(head_name)
|
77
|
+
get_head(head_name)
|
78
|
+
end
|
79
|
+
|
69
80
|
# Object reprsenting the current repo head.
|
70
81
|
#
|
71
82
|
# Returns Grit::Head (baked)
|
@@ -93,7 +104,7 @@ module Grit
|
|
93
104
|
self.git.add({}, *files.flatten)
|
94
105
|
end
|
95
106
|
|
96
|
-
#
|
107
|
+
# Remove files from the index
|
97
108
|
def remove(*files)
|
98
109
|
self.git.rm({}, *files.flatten)
|
99
110
|
end
|
@@ -128,6 +139,34 @@ module Grit
|
|
128
139
|
def remotes
|
129
140
|
Remote.find_all(self)
|
130
141
|
end
|
142
|
+
|
143
|
+
def remote_list
|
144
|
+
self.git.list_remotes
|
145
|
+
end
|
146
|
+
|
147
|
+
def remote_add(name, url)
|
148
|
+
self.git.remote({}, 'add', name, url)
|
149
|
+
end
|
150
|
+
|
151
|
+
def remote_fetch(name)
|
152
|
+
self.git.fetch({}, name)
|
153
|
+
end
|
154
|
+
|
155
|
+
# takes an array of remote names and last pushed dates
|
156
|
+
# fetches from all of the remotes where the local fetch
|
157
|
+
# date is earlier than the passed date, then records the
|
158
|
+
# last fetched date
|
159
|
+
#
|
160
|
+
# { 'origin' => date,
|
161
|
+
# 'peter => date,
|
162
|
+
# }
|
163
|
+
def remotes_fetch_needed(remotes)
|
164
|
+
remotes.each do |remote, date|
|
165
|
+
# TODO: check against date
|
166
|
+
self.remote_fetch(remote)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
131
170
|
|
132
171
|
# An array of Ref objects representing the refs in
|
133
172
|
# this repo
|
@@ -198,6 +237,53 @@ module Grit
|
|
198
237
|
Commit.find_all(self, id, options).first
|
199
238
|
end
|
200
239
|
|
240
|
+
# Returns a list of commits that is in +other_repo+ but not in self
|
241
|
+
#
|
242
|
+
# Returns Grit::Commit[]
|
243
|
+
def commit_deltas_from(other_repo, ref = "master", other_ref = "master")
|
244
|
+
# TODO: we should be able to figure out the branch point, rather than
|
245
|
+
# rev-list'ing the whole thing
|
246
|
+
repo_refs = self.git.rev_list({}, ref).strip.split("\n")
|
247
|
+
other_repo_refs = other_repo.git.rev_list({}, other_ref).strip.split("\n")
|
248
|
+
|
249
|
+
(other_repo_refs - repo_refs).map do |ref|
|
250
|
+
Commit.find_all(other_repo, ref, {:max_count => 1}).first
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def objects(refs)
|
255
|
+
Grit.no_quote = true
|
256
|
+
obj = self.git.rev_list({:objects => true}, refs).split("\n").map { |a| a[0, 40] }
|
257
|
+
Grit.no_quote = false
|
258
|
+
obj
|
259
|
+
end
|
260
|
+
|
261
|
+
def objects_between(ref1, ref2 = nil)
|
262
|
+
if ref2
|
263
|
+
refs = "#{ref2}..#{ref1}"
|
264
|
+
else
|
265
|
+
refs = ref1
|
266
|
+
end
|
267
|
+
self.objects(refs)
|
268
|
+
end
|
269
|
+
|
270
|
+
def diff_objects(commit_sha, parents = true)
|
271
|
+
revs = []
|
272
|
+
Grit.no_quote = true
|
273
|
+
if parents
|
274
|
+
# PARENTS:
|
275
|
+
cmd = "-r -t -m #{commit_sha}"
|
276
|
+
revs = self.git.diff_tree({}, cmd).strip.split("\n").map{ |a| r = a.split(' '); r[3] if r[1] != '160000' }
|
277
|
+
else
|
278
|
+
# NO PARENTS:
|
279
|
+
cmd = "-r -t #{commit_sha}"
|
280
|
+
revs = self.git.method_missing('ls-tree', {}, "-r -t #{commit_sha}").split("\n").map{ |a| a.split("\t").first.split(' ')[2] }
|
281
|
+
end
|
282
|
+
revs << self.commit(commit_sha).tree.id
|
283
|
+
Grit.no_quote = false
|
284
|
+
return revs.uniq.compact
|
285
|
+
end
|
286
|
+
|
201
287
|
# The Tree object for the given treeish reference
|
202
288
|
# +treeish+ is the reference (default 'master')
|
203
289
|
# +paths+ is an optional Array of directory paths to restrict the tree (deafult [])
|
@@ -255,20 +341,31 @@ module Grit
|
|
255
341
|
# Returns Grit::Repo (the newly created repo)
|
256
342
|
def self.init_bare(path, git_options = {}, repo_options = {})
|
257
343
|
git = Git.new(path)
|
344
|
+
git.fs_mkdir('..')
|
258
345
|
git.init(git_options)
|
259
346
|
self.new(path, repo_options)
|
260
347
|
end
|
348
|
+
|
349
|
+
def self.init_bare_or_open(path, git_options = {}, repo_options = {})
|
350
|
+
git = Git.new(path)
|
351
|
+
if !git.exist?
|
352
|
+
git.fs_mkdir(path)
|
353
|
+
git.init(git_options)
|
354
|
+
end
|
355
|
+
self.new(path, repo_options)
|
356
|
+
end
|
261
357
|
|
262
358
|
# Fork a bare git repository from this repo
|
263
359
|
# +path+ is the full path of the new repo (traditionally ends with /<name>.git)
|
264
|
-
# +options+ is any additional options to the git clone command
|
360
|
+
# +options+ is any additional options to the git clone command (:bare and :shared are true by default)
|
265
361
|
#
|
266
362
|
# Returns Grit::Repo (the newly forked repo)
|
267
363
|
def fork_bare(path, options = {})
|
268
364
|
default_options = {:bare => true, :shared => true}
|
269
365
|
real_options = default_options.merge(options)
|
366
|
+
Git.new(path).fs_mkdir('..')
|
270
367
|
self.git.clone(real_options, self.path, path)
|
271
|
-
|
368
|
+
self.new(path)
|
272
369
|
end
|
273
370
|
|
274
371
|
# Archive the given treeish
|
@@ -310,23 +407,30 @@ module Grit
|
|
310
407
|
def archive_tar_gz(treeish = 'master', prefix = nil)
|
311
408
|
options = {}
|
312
409
|
options[:prefix] = prefix if prefix
|
313
|
-
self.git.archive(options, treeish, "| gzip")
|
410
|
+
self.git.archive(options, treeish, "| gzip -n")
|
314
411
|
end
|
315
412
|
|
316
|
-
#
|
317
|
-
|
413
|
+
# Write an archive directly to a file
|
414
|
+
# +treeish+ is the treeish name/id (default 'master')
|
415
|
+
# +prefix+ is the optional prefix (default nil)
|
416
|
+
# +filename+ is the name of the file (default 'archive.tar.gz')
|
417
|
+
# +format+ is the optional format (default nil)
|
418
|
+
# +pipe+ is the command to run the output through (default 'gzip')
|
419
|
+
#
|
420
|
+
# Returns nothing
|
421
|
+
def archive_to_file(treeish = 'master', prefix = nil, filename = 'archive.tar.gz', format = nil, pipe = "gzip")
|
318
422
|
options = {}
|
319
423
|
options[:prefix] = prefix if prefix
|
320
|
-
|
424
|
+
options[:format] = format if format
|
425
|
+
self.git.archive(options, treeish, "| #{pipe} > #{filename}")
|
321
426
|
end
|
322
427
|
|
323
|
-
|
324
428
|
# Enable git-daemon serving of this repository by writing the
|
325
429
|
# git-daemon-export-ok file to its git directory
|
326
430
|
#
|
327
431
|
# Returns nothing
|
328
432
|
def enable_daemon_serve
|
329
|
-
|
433
|
+
self.git.fs_write(DAEMON_EXPORT_FILE, '')
|
330
434
|
end
|
331
435
|
|
332
436
|
# Disable git-daemon serving of this repository by ensuring there is no
|
@@ -334,17 +438,20 @@ module Grit
|
|
334
438
|
#
|
335
439
|
# Returns nothing
|
336
440
|
def disable_daemon_serve
|
337
|
-
|
441
|
+
self.git.fs_delete(DAEMON_EXPORT_FILE)
|
442
|
+
end
|
443
|
+
|
444
|
+
def gc_auto
|
445
|
+
self.git.gc({:auto => true})
|
338
446
|
end
|
339
447
|
|
340
448
|
# The list of alternates for this repo
|
341
449
|
#
|
342
450
|
# Returns Array[String] (pathnames of alternates)
|
343
451
|
def alternates
|
344
|
-
alternates_path =
|
345
|
-
|
346
|
-
|
347
|
-
File.read(alternates_path).strip.split("\n")
|
452
|
+
alternates_path = "objects/info/alternates"
|
453
|
+
if self.git.fs_exist?(alternates_path)
|
454
|
+
self.git.fs_read(alternates_path).strip.split("\n")
|
348
455
|
else
|
349
456
|
[]
|
350
457
|
end
|
@@ -362,11 +469,9 @@ module Grit
|
|
362
469
|
end
|
363
470
|
|
364
471
|
if alts.empty?
|
365
|
-
|
472
|
+
self.git.fs_write('objects/info/alternates', '')
|
366
473
|
else
|
367
|
-
|
368
|
-
f.write alts.join("\n")
|
369
|
-
end
|
474
|
+
self.git.fs_write('objects/info/alternates', alts.join("\n"))
|
370
475
|
end
|
371
476
|
end
|
372
477
|
|
@@ -378,6 +483,24 @@ module Grit
|
|
378
483
|
Index.new(self)
|
379
484
|
end
|
380
485
|
|
486
|
+
def update_ref(head, commit_sha)
|
487
|
+
return nil if !commit_sha || (commit_sha.size != 40)
|
488
|
+
self.git.fs_write("refs/heads/#{head}", commit_sha)
|
489
|
+
commit_sha
|
490
|
+
end
|
491
|
+
|
492
|
+
# Rename the current repository directory.
|
493
|
+
# +name+ is the new name
|
494
|
+
#
|
495
|
+
# Returns nothing
|
496
|
+
def rename(name)
|
497
|
+
if @bare
|
498
|
+
self.git.fs_move('/', "../#{name}")
|
499
|
+
else
|
500
|
+
self.git.fs_move('/', "../../#{name}")
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
381
504
|
# Pretty object inspection
|
382
505
|
def inspect
|
383
506
|
%Q{#<Grit::Repo "#{@path}">}
|