mojombo-grit 0.9.4 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/API.txt +101 -0
  2. data/History.txt +38 -2
  3. data/README.md +210 -0
  4. data/VERSION.yml +4 -0
  5. data/lib/grit.rb +13 -4
  6. data/lib/grit/blame.rb +61 -0
  7. data/lib/grit/blob.rb +11 -2
  8. data/lib/grit/commit.rb +44 -31
  9. data/lib/grit/commit_stats.rb +26 -2
  10. data/lib/grit/diff.rb +6 -6
  11. data/lib/grit/git-ruby.rb +4 -2
  12. data/lib/grit/git-ruby/file_index.rb +10 -3
  13. data/lib/grit/git-ruby/git_object.rb +9 -3
  14. data/lib/grit/git-ruby/internal/{mmap.rb → file_window.rb} +2 -2
  15. data/lib/grit/git-ruby/internal/loose.rb +6 -6
  16. data/lib/grit/git-ruby/internal/pack.rb +19 -19
  17. data/lib/grit/git-ruby/object.rb +8 -2
  18. data/lib/grit/git-ruby/repository.rb +11 -6
  19. data/lib/grit/git.rb +23 -10
  20. data/lib/grit/index.rb +12 -11
  21. data/lib/grit/merge.rb +45 -0
  22. data/lib/grit/ref.rb +20 -16
  23. data/lib/grit/repo.rb +59 -9
  24. data/lib/grit/ruby1.9.rb +7 -0
  25. data/lib/grit/submodule.rb +5 -1
  26. data/lib/grit/tag.rb +61 -66
  27. data/lib/grit/tree.rb +20 -1
  28. metadata +29 -47
  29. data/Manifest.txt +0 -71
  30. data/README.txt +0 -213
  31. data/Rakefile +0 -29
  32. data/grit.gemspec +0 -62
  33. data/lib/grit/head.rb +0 -83
  34. data/test/test_actor.rb +0 -35
  35. data/test/test_blob.rb +0 -79
  36. data/test/test_commit.rb +0 -190
  37. data/test/test_config.rb +0 -58
  38. data/test/test_diff.rb +0 -18
  39. data/test/test_git.rb +0 -64
  40. data/test/test_grit.rb +0 -32
  41. data/test/test_head.rb +0 -47
  42. data/test/test_real.rb +0 -19
  43. data/test/test_reality.rb +0 -17
  44. data/test/test_remote.rb +0 -14
  45. data/test/test_repo.rb +0 -277
  46. data/test/test_tag.rb +0 -25
  47. data/test/test_tree.rb +0 -96
@@ -11,7 +11,7 @@
11
11
 
12
12
  require 'zlib'
13
13
  require 'grit/git-ruby/internal/raw_object'
14
- require 'grit/git-ruby/internal/mmap'
14
+ require 'grit/git-ruby/internal/file_window'
15
15
 
16
16
  PACK_SIGNATURE = "PACK"
17
17
  PACK_IDX_SIGNATURE = "\377tOc"
@@ -48,9 +48,9 @@ module Grit
48
48
  def with_idx(index_file = nil)
49
49
  if !index_file
50
50
  index_file = @name
51
- idxfile = File.open(@name[0...-4]+'idx')
51
+ idxfile = File.open(@name[0...-4]+'idx', 'rb')
52
52
  else
53
- idxfile = File.open(index_file)
53
+ idxfile = File.open(index_file, 'rb')
54
54
  end
55
55
 
56
56
  # read header
@@ -66,14 +66,14 @@ module Grit
66
66
  @version = 1
67
67
  end
68
68
 
69
- idx = Mmap.new(idxfile, @version)
69
+ idx = FileWindow.new(idxfile, @version)
70
70
  yield idx
71
71
  idx.unmap
72
72
  idxfile.close
73
73
  end
74
74
 
75
75
  def with_packfile
76
- packfile = File.open(@name)
76
+ packfile = File.open(@name, 'rb')
77
77
  yield packfile
78
78
  packfile.close
79
79
  end
@@ -189,7 +189,7 @@ module Grit
189
189
  end
190
190
 
191
191
  def find_object_in_index(idx, sha1)
192
- slot = sha1[0]
192
+ slot = sha1.getord(0)
193
193
  return nil if !slot
194
194
  first, last = @offsets[slot,2]
195
195
  while first < last
@@ -248,13 +248,13 @@ module Grit
248
248
  obj_offset = offset
249
249
  packfile.seek(offset)
250
250
 
251
- c = packfile.read(1)[0]
251
+ c = packfile.read(1).getord(0)
252
252
  size = c & 0xf
253
253
  type = (c >> 4) & 7
254
254
  shift = 4
255
255
  offset += 1
256
256
  while c & 0x80 != 0
257
- c = packfile.read(1)[0]
257
+ c = packfile.read(1).getord(0)
258
258
  size |= ((c & 0x7f) << shift)
259
259
  shift += 7
260
260
  offset += 1
@@ -281,10 +281,10 @@ module Grit
281
281
 
282
282
  if type == OBJ_OFS_DELTA
283
283
  i = 0
284
- c = data[i]
284
+ c = data.getord(i)
285
285
  base_offset = c & 0x7f
286
286
  while c & 0x80 != 0
287
- c = data[i += 1]
287
+ c = data.getord(i += 1)
288
288
  base_offset += 1
289
289
  base_offset <<= 7
290
290
  base_offset |= c & 0x7f
@@ -335,18 +335,18 @@ module Grit
335
335
  dest_size, pos = patch_delta_header_size(delta, pos)
336
336
  dest = ""
337
337
  while pos < delta.size
338
- c = delta[pos]
338
+ c = delta.getord(pos)
339
339
  pos += 1
340
340
  if c & 0x80 != 0
341
341
  pos -= 1
342
342
  cp_off = cp_size = 0
343
- cp_off = delta[pos += 1] if c & 0x01 != 0
344
- cp_off |= delta[pos += 1] << 8 if c & 0x02 != 0
345
- cp_off |= delta[pos += 1] << 16 if c & 0x04 != 0
346
- cp_off |= delta[pos += 1] << 24 if c & 0x08 != 0
347
- cp_size = delta[pos += 1] if c & 0x10 != 0
348
- cp_size |= delta[pos += 1] << 8 if c & 0x20 != 0
349
- cp_size |= delta[pos += 1] << 16 if c & 0x40 != 0
343
+ cp_off = delta.getord(pos += 1) if c & 0x01 != 0
344
+ cp_off |= delta.getord(pos += 1) << 8 if c & 0x02 != 0
345
+ cp_off |= delta.getord(pos += 1) << 16 if c & 0x04 != 0
346
+ cp_off |= delta.getord(pos += 1) << 24 if c & 0x08 != 0
347
+ cp_size = delta.getord(pos += 1) if c & 0x10 != 0
348
+ cp_size |= delta.getord(pos += 1) << 8 if c & 0x20 != 0
349
+ cp_size |= delta.getord(pos += 1) << 16 if c & 0x40 != 0
350
350
  cp_size = 0x10000 if cp_size == 0
351
351
  pos += 1
352
352
  dest += base[cp_off,cp_size]
@@ -365,7 +365,7 @@ module Grit
365
365
  size = 0
366
366
  shift = 0
367
367
  begin
368
- c = delta[pos]
368
+ c = delta.getord(pos)
369
369
  if c == nil
370
370
  raise PackFormatError, 'invalid delta header'
371
371
  end
@@ -163,8 +163,14 @@ module Grit
163
163
 
164
164
  def self.read_bytes_until(io, char)
165
165
  string = ''
166
- while ((next_char = io.getc.chr) != char) && !io.eof
167
- string += next_char
166
+ if RUBY_VERSION > '1.9'
167
+ while ((next_char = io.getc) != char) && !io.eof
168
+ string += next_char
169
+ end
170
+ else
171
+ while ((next_char = io.getc.chr) != char) && !io.eof
172
+ string += next_char
173
+ end
168
174
  end
169
175
  string
170
176
  end
@@ -185,16 +185,15 @@ module Grit
185
185
  def get_raw_tree(sha)
186
186
  o = get_raw_object_by_sha1(sha)
187
187
  if o.type == :commit
188
- tree = cat_file(get_object_by_sha1(sha).tree)
188
+ cat_file(get_object_by_sha1(sha).tree)
189
189
  elsif o.type == :tag
190
190
  commit_sha = get_object_by_sha1(sha).object
191
- tree = cat_file(get_object_by_sha1(commit_sha).tree)
192
- else
193
- tree = cat_file(sha)
191
+ cat_file(get_object_by_sha1(commit_sha).tree)
192
+ elsif o.type == :tree
193
+ cat_file(sha)
194
194
  end
195
- return tree
196
195
  end
197
-
196
+
198
197
  # return array of tree entries
199
198
  ## TODO : refactor this to remove the fugly
200
199
  def ls_tree_path(sha, path, append = nil)
@@ -664,6 +663,7 @@ module Grit
664
663
  private
665
664
 
666
665
  def initloose
666
+ @loaded = []
667
667
  @loose = []
668
668
  load_loose(git_path('objects'))
669
669
  load_alternate_loose(git_path('objects'))
@@ -675,6 +675,7 @@ module Grit
675
675
  alt = File.join(path, 'info/alternates')
676
676
  if File.exists?(alt)
677
677
  File.readlines(alt).each do |line|
678
+ next if @loaded.include?(line.chomp)
678
679
  if line[0, 2] == '..'
679
680
  line = File.expand_path(File.join(@git_dir, line))
680
681
  end
@@ -685,12 +686,14 @@ module Grit
685
686
  end
686
687
 
687
688
  def load_loose(path)
689
+ @loaded << path
688
690
  return if !File.exists?(path)
689
691
  @loose << Grit::GitRuby::Internal::LooseStorage.new(path)
690
692
  end
691
693
 
692
694
  def initpacks
693
695
  close
696
+ @loaded_packs = []
694
697
  @packs = []
695
698
  load_packs(git_path("objects/pack"))
696
699
  load_alternate_packs(git_path('objects'))
@@ -705,6 +708,7 @@ module Grit
705
708
  line = File.expand_path(File.join(@git_dir, line))
706
709
  end
707
710
  full_pack = File.join(line.chomp, 'pack')
711
+ next if @loaded_packs.include?(full_pack)
708
712
  load_packs(full_pack)
709
713
  load_alternate_packs(File.join(line.chomp))
710
714
  end
@@ -712,6 +716,7 @@ module Grit
712
716
  end
713
717
 
714
718
  def load_packs(path)
719
+ @loaded_packs << path
715
720
  return if !File.exists?(path)
716
721
  Dir.open(path) do |dir|
717
722
  dir.each do |entry|
@@ -15,11 +15,19 @@ module Grit
15
15
  include GitRuby
16
16
 
17
17
  class << self
18
- attr_accessor :git_binary, :git_timeout
18
+ attr_accessor :git_binary, :git_timeout, :git_max_size
19
19
  end
20
20
 
21
- self.git_binary = "/usr/bin/env git"
22
- self.git_timeout = 10
21
+ self.git_binary = "/usr/bin/env git"
22
+ self.git_timeout = 10
23
+ self.git_max_size = 5242880 # 5.megabytes
24
+
25
+ def self.with_timeout(timeout = 10.seconds)
26
+ old_timeout = Grit::Git.git_timeout
27
+ Grit::Git.git_timeout = timeout
28
+ yield
29
+ Grit::Git.git_timeout = old_timeout
30
+ end
23
31
 
24
32
  attr_accessor :git_dir, :bytes_read
25
33
 
@@ -28,6 +36,11 @@ module Grit
28
36
  self.bytes_read = 0
29
37
  end
30
38
 
39
+ def shell_escape(str)
40
+ str.to_s.gsub("'", "\\\\'").gsub(";", '\\;')
41
+ end
42
+ alias_method :e, :shell_escape
43
+
31
44
  # Run the given git command with the specified arguments and return
32
45
  # the result as a String
33
46
  # +cmd+ is the command
@@ -43,13 +56,13 @@ module Grit
43
56
  end
44
57
 
45
58
  def run(prefix, cmd, postfix, options, args)
46
- timeout = options.delete(:timeout)
59
+ timeout = options.delete(:timeout) rescue nil
47
60
  timeout = true if timeout.nil?
48
61
 
49
62
  opt_args = transform_options(options)
50
- ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|') ? a : "'#{a}'" }
51
-
52
- call = "#{prefix}#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{postfix}"
63
+ ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|') ? a : "'#{e(a)}'" }
64
+
65
+ call = "#{prefix}#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
53
66
  Grit.log(call) if Grit.debug
54
67
  response, err = timeout ? sh(call) : wild_sh(call)
55
68
  Grit.log(response) if Grit.debug
@@ -63,7 +76,7 @@ module Grit
63
76
  Timeout.timeout(self.class.git_timeout) do
64
77
  while tmp = stdout.read(1024)
65
78
  ret += tmp
66
- if (@bytes_read += tmp.size) > 5242880 # 5.megabytes
79
+ if (@bytes_read += tmp.size) > self.class.git_max_size
67
80
  bytes = @bytes_read
68
81
  @bytes_read = 0
69
82
  raise GitTimeout.new(command, bytes)
@@ -109,14 +122,14 @@ module Grit
109
122
  args << "-#{opt}"
110
123
  else
111
124
  val = options.delete(opt)
112
- args << "-#{opt.to_s} '#{val}'"
125
+ args << "-#{opt.to_s} '#{e(val)}'"
113
126
  end
114
127
  else
115
128
  if options[opt] == true
116
129
  args << "--#{opt.to_s.gsub(/_/, '-')}"
117
130
  else
118
131
  val = options.delete(opt)
119
- args << "--#{opt.to_s.gsub(/_/, '-')}='#{val}'"
132
+ args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'"
120
133
  end
121
134
  end
122
135
  end
@@ -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')
@@ -64,14 +72,7 @@ module Grit
64
72
 
65
73
  commit_sha1 = self.repo.git.ruby_git.put_raw_object(contents.join("\n"), 'commit')
66
74
 
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
-
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*")
@@ -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
@@ -9,31 +9,37 @@ module Grit
9
9
  # +options+ is a Hash of options
10
10
  #
11
11
  # Returns Grit::Ref[] (baked)
12
- def find_all(repo, options = {})
12
+ def find_all(repo, options = {})
13
13
  refs = []
14
-
14
+ already = {}
15
15
  Dir.chdir(repo.path) do
16
+ files = Dir.glob(prefix + '/**/*')
17
+ files.each do |ref|
18
+ next if !File.file?(ref)
19
+ id = File.read(ref).chomp
20
+ name = ref.sub("#{prefix}/", '')
21
+ commit = Commit.create(repo, :id => id)
22
+ if !already[name]
23
+ refs << self.new(name, commit)
24
+ already[name] = true
25
+ end
26
+ end
27
+
16
28
  if File.file?('packed-refs')
17
29
  File.readlines('packed-refs').each do |line|
18
30
  if m = /^(\w{40}) (.*?)$/.match(line)
19
31
  next if !Regexp.new('^' + prefix).match(m[2])
20
32
  name = m[2].sub("#{prefix}/", '')
21
33
  commit = Commit.create(repo, :id => m[1])
22
- refs << self.new(name, commit)
34
+ if !already[name]
35
+ refs << self.new(name, commit)
36
+ already[name] = true
37
+ end
23
38
  end
24
39
  end
25
40
  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
35
41
  end
36
-
42
+
37
43
  refs
38
44
  end
39
45
 
@@ -88,8 +94,6 @@ module Grit
88
94
 
89
95
  end # Head
90
96
 
91
- class Tag < Ref ; end
92
-
93
97
  class Remote < Ref; end
94
-
98
+
95
99
  end # Grit
@@ -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
@@ -51,6 +53,11 @@ module Grit
51
53
  def description
52
54
  File.open(File.join(self.path, 'description')).read.chomp
53
55
  end
56
+
57
+ def blame(file, commit = nil)
58
+ Blame.new(self, file, commit)
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 is_head?(head_name)
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
- # Adds files to the index
107
+ # Remove files from the index
97
108
  def remove(*files)
98
109
  self.git.rm({}, *files.flatten)
99
110
  end
@@ -198,6 +209,20 @@ module Grit
198
209
  Commit.find_all(self, id, options).first
199
210
  end
200
211
 
212
+ # Returns a list of commits that is in +other_repo+ but not in self
213
+ #
214
+ # Returns Grit::Commit[]
215
+ def commit_deltas_from(other_repo, ref = "master", other_ref = "master")
216
+ # TODO: we should be able to figure out the branch point, rather than
217
+ # rev-list'ing the whole thing
218
+ repo_refs = self.git.rev_list({}, ref).strip.split("\n")
219
+ other_repo_refs = other_repo.git.rev_list({}, other_ref).strip.split("\n")
220
+
221
+ (other_repo_refs - repo_refs).map do |ref|
222
+ Commit.find_all(other_repo, ref, {:max_count => 1}).first
223
+ end
224
+ end
225
+
201
226
  # The Tree object for the given treeish reference
202
227
  # +treeish+ is the reference (default 'master')
203
228
  # +paths+ is an optional Array of directory paths to restrict the tree (deafult [])
@@ -261,7 +286,7 @@ module Grit
261
286
 
262
287
  # Fork a bare git repository from this repo
263
288
  # +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
289
+ # +options+ is any additional options to the git clone command (:bare and :shared are true by default)
265
290
  #
266
291
  # Returns Grit::Repo (the newly forked repo)
267
292
  def fork_bare(path, options = {})
@@ -313,14 +338,21 @@ module Grit
313
338
  self.git.archive(options, treeish, "| gzip")
314
339
  end
315
340
 
316
- # run archive directly to a file
317
- def archive_to_file(treeish = 'master', prefix = nil, filename = 'archive.tar.gz')
341
+ # Write an archive directly to a file
342
+ # +treeish+ is the treeish name/id (default 'master')
343
+ # +prefix+ is the optional prefix (default nil)
344
+ # +filename+ is the name of the file (default 'archive.tar.gz')
345
+ # +format+ is the optional format (default nil)
346
+ # +pipe+ is the command to run the output through (default 'gzip')
347
+ #
348
+ # Returns nothing
349
+ def archive_to_file(treeish = 'master', prefix = nil, filename = 'archive.tar.gz', format = nil, pipe = "gzip")
318
350
  options = {}
319
351
  options[:prefix] = prefix if prefix
320
- self.git.archive(options, treeish, "| gzip > #{filename}")
352
+ options[:format] = format if format
353
+ self.git.archive(options, treeish, "| #{pipe} > #{filename}")
321
354
  end
322
355
 
323
-
324
356
  # Enable git-daemon serving of this repository by writing the
325
357
  # git-daemon-export-ok file to its git directory
326
358
  #
@@ -337,6 +369,10 @@ module Grit
337
369
  FileUtils.rm_f(File.join(self.path, DAEMON_EXPORT_FILE))
338
370
  end
339
371
 
372
+ def gc_auto
373
+ self.git.gc({:auto => true})
374
+ end
375
+
340
376
  # The list of alternates for this repo
341
377
  #
342
378
  # Returns Array[String] (pathnames of alternates)
@@ -362,7 +398,9 @@ module Grit
362
398
  end
363
399
 
364
400
  if alts.empty?
365
- File.delete(File.join(self.path, *%w{objects info alternates}))
401
+ File.open(File.join(self.path, *%w{objects info alternates}), 'w') do |f|
402
+ f.write ''
403
+ end
366
404
  else
367
405
  File.open(File.join(self.path, *%w{objects info alternates}), 'w') do |f|
368
406
  f.write alts.join("\n")
@@ -378,6 +416,18 @@ module Grit
378
416
  Index.new(self)
379
417
  end
380
418
 
419
+ def update_ref(head, commit_sha)
420
+ return nil if !commit_sha || (commit_sha.size != 40)
421
+
422
+ ref_heads = File.join(self.path, 'refs', 'heads')
423
+ FileUtils.mkdir_p(ref_heads)
424
+ File.open(File.join(ref_heads, head), 'w') do |f|
425
+ f.write(commit_sha)
426
+ end
427
+ commit_sha
428
+
429
+ end
430
+
381
431
  # Pretty object inspection
382
432
  def inspect
383
433
  %Q{#<Grit::Repo "#{@path}">}