tekkub-fugit 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/Rakefile +19 -0
  2. data/VERSION.yml +3 -3
  3. data/bin/fugit +0 -0
  4. data/lib/fugit/commit_dialog.rb +6 -9
  5. data/lib/fugit/commit_tab.rb +1 -1
  6. data/lib/fugit/create_branch_dialog.rb +65 -0
  7. data/lib/fugit/delete_branch_dialog.rb +1 -1
  8. data/lib/fugit/fetch_dialog.rb +52 -0
  9. data/lib/fugit/history_list.rb +16 -12
  10. data/lib/fugit/history_tab.rb +3 -0
  11. data/lib/fugit/index_list.rb +8 -3
  12. data/lib/fugit/io_get_line.rb +4 -4
  13. data/lib/fugit/logged_dialog.rb +49 -0
  14. data/lib/fugit/main_frame.rb +16 -1
  15. data/lib/fugit/merge_dialog.rb +68 -0
  16. data/lib/fugit/push_dialog.rb +11 -61
  17. data/lib/fugit/revert_commit_dialog.rb +51 -0
  18. data/lib/fugit/run_command_dialog.rb +40 -0
  19. data/lib/fugit/tab_toolbar.rb +145 -0
  20. data/lib/fugit.rb +19 -1
  21. data/lib/grit/API.txt +101 -0
  22. data/lib/grit/History.txt +28 -0
  23. data/lib/grit/PURE_TODO +35 -0
  24. data/lib/grit/README.txt +222 -0
  25. data/lib/grit/Rakefile +54 -0
  26. data/lib/grit/VERSION.yml +4 -0
  27. data/lib/grit/benchmarks.rb +129 -0
  28. data/lib/grit/benchmarks.txt +21 -0
  29. data/lib/grit/examples/ex_add_commit.rb +13 -0
  30. data/lib/grit/examples/ex_index.rb +14 -0
  31. data/lib/grit/grit.gemspec +36 -0
  32. data/lib/grit/lib/grit/actor.rb +36 -0
  33. data/lib/grit/lib/grit/blame.rb +61 -0
  34. data/lib/grit/lib/grit/blob.rb +117 -0
  35. data/lib/grit/lib/grit/commit.rb +238 -0
  36. data/lib/grit/lib/grit/commit_stats.rb +104 -0
  37. data/lib/grit/lib/grit/config.rb +44 -0
  38. data/lib/grit/lib/grit/diff.rb +70 -0
  39. data/lib/grit/lib/grit/errors.rb +7 -0
  40. data/lib/grit/lib/grit/git-ruby/commit_db.rb +52 -0
  41. data/lib/grit/lib/grit/git-ruby/file_index.rb +193 -0
  42. data/lib/grit/lib/grit/git-ruby/git_object.rb +344 -0
  43. data/lib/grit/lib/grit/git-ruby/internal/loose.rb +137 -0
  44. data/lib/grit/lib/grit/git-ruby/internal/mmap.rb +58 -0
  45. data/lib/grit/lib/grit/git-ruby/internal/pack.rb +382 -0
  46. data/lib/grit/lib/grit/git-ruby/internal/raw_object.rb +37 -0
  47. data/lib/grit/lib/grit/git-ruby/object.rb +319 -0
  48. data/lib/grit/lib/grit/git-ruby/repository.rb +736 -0
  49. data/lib/grit/lib/grit/git-ruby.rb +186 -0
  50. data/lib/grit/lib/grit/git.rb +141 -0
  51. data/lib/grit/lib/grit/index.rb +122 -0
  52. data/lib/grit/lib/grit/lazy.rb +33 -0
  53. data/lib/grit/lib/grit/merge.rb +45 -0
  54. data/lib/grit/lib/grit/ref.rb +99 -0
  55. data/lib/grit/lib/grit/repo.rb +441 -0
  56. data/lib/grit/lib/grit/status.rb +151 -0
  57. data/lib/grit/lib/grit/submodule.rb +84 -0
  58. data/lib/grit/lib/grit/tag.rb +66 -0
  59. data/lib/grit/lib/grit/tree.rb +104 -0
  60. data/lib/grit/lib/grit.rb +71 -0
  61. data/lib/grit/lib/open3_detach.rb +46 -0
  62. data/lib/icons/application_go.png +0 -0
  63. data/lib/icons/arrow_divide_add.png +0 -0
  64. data/lib/icons/arrow_refresh.png +0 -0
  65. data/lib/icons/cross.png +0 -0
  66. metadata +56 -10
  67. data/fugit.gemspec +0 -32
  68. data/lib/fugit/commit_tab_toolbar.rb +0 -111
@@ -0,0 +1,186 @@
1
+ require 'grit/git-ruby/repository'
2
+ require 'grit/git-ruby/file_index'
3
+
4
+ module Grit
5
+
6
+ # the functions in this module intercept the calls to git binary
7
+ # made buy the grit objects and attempts to run them in pure ruby
8
+ # if it will be faster, or if the git binary is not available (!!TODO!!)
9
+ module GitRuby
10
+
11
+ attr_accessor :ruby_git_repo, :git_file_index
12
+
13
+ def init(options)
14
+ if options.size == 0
15
+ Grit::GitRuby::Repository.init(@git_dir)
16
+ else
17
+ method_missing('init', options)
18
+ end
19
+ end
20
+
21
+ def cat_file(options, ref)
22
+ if options[:t]
23
+ file_type(ref)
24
+ elsif options[:s]
25
+ file_size(ref)
26
+ elsif options[:p]
27
+ try_run { ruby_git.cat_file(ref) }
28
+ end
29
+ rescue Grit::GitRuby::Repository::NoSuchShaFound
30
+ ''
31
+ end
32
+
33
+ # lib/grit/tree.rb:16: output = repo.git.ls_tree({}, treeish, *paths)
34
+ def ls_tree(options, treeish, *paths)
35
+ sha = rev_parse({}, treeish)
36
+ ruby_git.ls_tree(sha, paths.flatten)
37
+ rescue Grit::GitRuby::Repository::NoSuchShaFound
38
+ ''
39
+ end
40
+
41
+ # git diff --full-index 'ec037431382e83c3e95d4f2b3d145afbac8ea55d' 'f1ec1aea10986159456846b8a05615b87828d6c6'
42
+ def diff(options, sha1, sha2)
43
+ try_run { ruby_git.diff(sha1, sha2, options) }
44
+ end
45
+
46
+ def rev_list(options, ref = 'master')
47
+ options.delete(:skip) if options[:skip].to_i == 0
48
+ allowed_options = [:max_count, :since, :until, :pretty] # this is all I can do right now
49
+ if ((options.keys - allowed_options).size > 0)
50
+ return method_missing('rev-list', options, ref)
51
+ elsif (options.size == 0)
52
+ # pure rev-list
53
+ begin
54
+ return file_index.commits_from(rev_parse({}, ref)).join("\n") + "\n"
55
+ rescue
56
+ return method_missing('rev-list', options, ref)
57
+ end
58
+ else
59
+ aref = rev_parse({}, ref)
60
+ if aref.is_a? Array
61
+ return method_missing('rev-list', options, ref)
62
+ else
63
+ return try_run { ruby_git.rev_list(aref, options) }
64
+ end
65
+ end
66
+ end
67
+
68
+ def rev_parse(options, string)
69
+ raise RuntimeError, "invalid string: #{string}" unless string.is_a?(String)
70
+
71
+ if string =~ /\.\./
72
+ (sha1, sha2) = string.split('..')
73
+ return [rev_parse({}, sha1), rev_parse({}, sha2)]
74
+ end
75
+
76
+ if /^[0-9a-f]{40}$/.match(string) # passing in a sha - just no-op it
77
+ return string.chomp
78
+ end
79
+
80
+ head = File.join(@git_dir, 'refs', 'heads', string)
81
+ return File.read(head).chomp if File.file?(head)
82
+
83
+ head = File.join(@git_dir, 'refs', 'remotes', string)
84
+ return File.read(head).chomp if File.file?(head)
85
+
86
+ head = File.join(@git_dir, 'refs', 'tags', string)
87
+ return File.read(head).chomp if File.file?(head)
88
+
89
+ ## check packed-refs file, too
90
+ packref = File.join(@git_dir, 'packed-refs')
91
+ if File.file?(packref)
92
+ File.readlines(packref).each do |line|
93
+ if m = /^(\w{40}) refs\/.+?\/(.*?)$/.match(line)
94
+ next if !Regexp.new(Regexp.escape(string) + '$').match(m[3])
95
+ return m[1].chomp
96
+ end
97
+ end
98
+ end
99
+
100
+ ## !! more - partials and such !!
101
+
102
+ # revert to calling git - grr
103
+ return method_missing('rev-parse', {}, string).chomp
104
+ end
105
+
106
+ def file_size(ref)
107
+ try_run { ruby_git.cat_file_size(ref).to_s }
108
+ end
109
+
110
+ def file_type(ref)
111
+ try_run { ruby_git.cat_file_type(ref).to_s }
112
+ end
113
+
114
+ def blame_tree(commit, path = nil)
115
+ begin
116
+ path = path.to_a.join('/').to_s + '/' if (path && path != '')
117
+ path = '' if !path.is_a? String
118
+ commits = file_index.last_commits(rev_parse({}, commit), looking_for(commit, path))
119
+ clean_paths(commits)
120
+ rescue FileIndex::IndexFileNotFound
121
+ {}
122
+ end
123
+ end
124
+
125
+ def file_index
126
+ @git_file_index ||= FileIndex.new(@git_dir)
127
+ end
128
+
129
+ def ruby_git
130
+ @ruby_git_repo ||= Repository.new(@git_dir)
131
+ end
132
+
133
+ private
134
+
135
+ def try_run
136
+ ret = ''
137
+ Timeout.timeout(self.class.git_timeout) do
138
+ ret = yield
139
+ end
140
+ @bytes_read += ret.size
141
+
142
+ #if @bytes_read > 5242880 # 5.megabytes
143
+ # bytes = @bytes_read
144
+ # @bytes_read = 0
145
+ # raise Grit::Git::GitTimeout.new(command, bytes)
146
+ #end
147
+
148
+ ret
149
+ rescue Timeout::Error => e
150
+ bytes = @bytes_read
151
+ @bytes_read = 0
152
+ raise Grit::Git::GitTimeout.new(command, bytes)
153
+ end
154
+
155
+ def looking_for(commit, path = nil)
156
+ tree_sha = ruby_git.get_subtree(rev_parse({}, commit), path)
157
+
158
+ looking_for = []
159
+ ruby_git.get_object_by_sha1(tree_sha).entry.each do |e|
160
+ if path && !(path == '' || path == '.' || path == './')
161
+ file = File.join(path, e.name)
162
+ else
163
+ file = e.name
164
+ end
165
+ file += '/' if e.type == :directory
166
+ looking_for << file
167
+ end
168
+ looking_for
169
+ end
170
+
171
+ def clean_paths(commit_array)
172
+ new_commits = {}
173
+ commit_array.each do |file, sha|
174
+ file = file.chop if file[file.size - 1 , 1] == '/'
175
+ new_commits[file] = sha
176
+ end
177
+ new_commits
178
+ end
179
+
180
+ # TODO
181
+ # git grep -n 'foo' 'master'
182
+ # git log --pretty='raw' --max-count='1' 'master' -- 'LICENSE'
183
+ # git log --pretty='raw' --max-count='1' 'master' -- 'test'
184
+
185
+ end
186
+ end
@@ -0,0 +1,141 @@
1
+ module Grit
2
+
3
+ class Git
4
+ class GitTimeout < RuntimeError
5
+ attr_reader :command, :bytes_read
6
+
7
+ def initialize(command = nil, bytes_read = nil)
8
+ @command = command
9
+ @bytes_read = bytes_read
10
+ end
11
+ end
12
+
13
+ undef_method :clone
14
+
15
+ include GitRuby
16
+
17
+ class << self
18
+ attr_accessor :git_binary, :git_timeout
19
+ end
20
+
21
+ self.git_binary = case RUBY_PLATFORM
22
+ when /mswin|mingw/
23
+ "c:/Program Files/Git/bin/git.exe"
24
+ else
25
+ "/usr/bin/env git"
26
+ end
27
+ self.git_timeout = 10
28
+
29
+ def self.with_timeout(timeout = 10.seconds)
30
+ old_timeout = Grit::Git.git_timeout
31
+ Grit::Git.git_timeout = timeout
32
+ yield
33
+ Grit::Git.git_timeout = old_timeout
34
+ end
35
+
36
+ attr_accessor :git_dir, :bytes_read, :last_err, :last_status
37
+
38
+ def initialize(git_dir)
39
+ self.git_dir = git_dir
40
+ self.bytes_read = 0
41
+ end
42
+
43
+ # Run the given git command with the specified arguments and return
44
+ # the result as a String
45
+ # +cmd+ is the command
46
+ # +options+ is a hash of Ruby style options
47
+ # +args+ is the list of arguments (to be joined by spaces)
48
+ #
49
+ # Examples
50
+ # git.rev_list({:max_count => 10, :header => true}, "master")
51
+ #
52
+ # Returns String
53
+ def method_missing(cmd, options = {}, *args)
54
+ run('', cmd, '', options, args)
55
+ end
56
+
57
+ def run(prefix, cmd, postfix, options, args)
58
+ timeout = options.delete(:timeout) rescue nil
59
+ timeout = true if timeout.nil?
60
+
61
+ opt_args = transform_options(options)
62
+ ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|') ? a : %Q|"#{a}"| }
63
+
64
+ call = %Q|#{prefix}#{Git.git_binary} --git-dir="#{self.git_dir}" #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{postfix}|
65
+ Grit.log(call) if Grit.debug
66
+ response, err = timeout ? sh(call) : wild_sh(call)
67
+ Grit.log(response) if Grit.debug
68
+ Grit.log(err) if Grit.debug
69
+ self.last_err = err
70
+ self.last_status = $?
71
+ response
72
+ end
73
+
74
+ def sh(command)
75
+ ret, err = '', ''
76
+ Open3.popen3(command) do |_, stdout, stderr|
77
+ Timeout.timeout(self.class.git_timeout) do
78
+ while tmp = stdout.read(1024)
79
+ ret += tmp
80
+ if (@bytes_read += tmp.size) > 5242880 # 5.megabytes
81
+ bytes = @bytes_read
82
+ @bytes_read = 0
83
+ raise GitTimeout.new(command, bytes)
84
+ end
85
+ end
86
+ end
87
+
88
+ while tmp = stderr.read(1024)
89
+ err += tmp
90
+ end
91
+ end
92
+ [ret, err]
93
+ rescue Timeout::Error, Grit::Git::GitTimeout
94
+ bytes = @bytes_read
95
+ @bytes_read = 0
96
+ raise GitTimeout.new(command, bytes)
97
+ end
98
+
99
+ def wild_sh(command)
100
+ ret, err = '', ''
101
+ Open3.popen3(command) do |_, stdout, stderr|
102
+ while tmp = stdout.read(1024)
103
+ ret += tmp
104
+ end
105
+
106
+ while tmp = stderr.read(1024)
107
+ err += tmp
108
+ end
109
+ end
110
+ [ret, err]
111
+ end
112
+
113
+ # Transform Ruby style options into git command line options
114
+ # +options+ is a hash of Ruby style options
115
+ #
116
+ # Returns String[]
117
+ # e.g. ["--max-count=10", "--header"]
118
+ def transform_options(options)
119
+ args = []
120
+ options.keys.each do |opt|
121
+ if opt.to_s.size == 1
122
+ if options[opt] == true
123
+ args << "-#{opt}"
124
+ else
125
+ val = options.delete(opt)
126
+ args << "-#{opt.to_s} '#{val}'"
127
+ end
128
+ else
129
+ if options[opt] == true
130
+ args << "--#{opt.to_s.gsub(/_/, '-')}"
131
+ else
132
+ val = options.delete(opt)
133
+ args << "--#{opt.to_s.gsub(/_/, '-')}='#{val}'"
134
+ end
135
+ end
136
+ end
137
+ args
138
+ end
139
+ end # Git
140
+
141
+ end # Grit
@@ -0,0 +1,122 @@
1
+ module Grit
2
+
3
+ class Index
4
+ attr_accessor :repo, :tree, :current_tree
5
+
6
+ def initialize(repo)
7
+ self.repo = repo
8
+ self.tree = {}
9
+ self.current_tree = nil
10
+ end
11
+
12
+ # Add a file to the index
13
+ # +path+ is the path (including filename)
14
+ # +data+ is the binary contents of the file
15
+ #
16
+ # Returns nothing
17
+ def add(file_path, data)
18
+ path = file_path.split('/')
19
+ filename = path.pop
20
+
21
+ current = self.tree
22
+
23
+ path.each do |dir|
24
+ current[dir] ||= {}
25
+ node = current[dir]
26
+ current = node
27
+ end
28
+
29
+ current[filename] = data
30
+ end
31
+
32
+ # Sets the current tree
33
+ # +tree+ the branch/tag/sha... to use - a string
34
+ #
35
+ # Returns index (self)
36
+ def read_tree(tree)
37
+ self.current_tree = self.repo.tree(tree)
38
+ end
39
+
40
+ # Commit the contents of the index
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]
46
+ #
47
+ # Returns a String of the SHA1 of the commit
48
+ def commit(message, parents = nil, actor = nil, last_tree = nil, head = 'master')
49
+ tree_sha1 = write_tree(self.tree, self.current_tree)
50
+ return false if tree_sha1 == last_tree # don't write identical commits
51
+
52
+ contents = []
53
+ contents << ['tree', tree_sha1].join(' ')
54
+ parents.each do |p|
55
+ contents << ['parent', p].join(' ') if p
56
+ end if parents
57
+
58
+ if actor
59
+ name = actor.name
60
+ email = actor.email
61
+ else
62
+ config = Config.new(self.repo)
63
+ name = config['user.name']
64
+ email = config['user.email']
65
+ end
66
+
67
+ author_string = "#{name} <#{email}> #{Time.now.to_i} -0700" # !! TODO : gotta fix this
68
+ contents << ['author', author_string].join(' ')
69
+ contents << ['committer', author_string].join(' ')
70
+ contents << ''
71
+ contents << message
72
+
73
+ commit_sha1 = self.repo.git.ruby_git.put_raw_object(contents.join("\n"), 'commit')
74
+
75
+ self.repo.update_ref(head, commit_sha1)
76
+ end
77
+
78
+ # Recursively write a tree to the index
79
+ # +tree+ is the tree
80
+ #
81
+ # Returns the SHA1 String of the tree
82
+ def write_tree(tree, now_tree = nil)
83
+ tree_contents = {}
84
+
85
+ # fill in original tree
86
+ now_tree.contents.each do |obj|
87
+ sha = [obj.id].pack("H*")
88
+ k = obj.name
89
+ k += '/' if (obj.class == Grit::Tree)
90
+ tree_contents[k] = "%s %s\0%s" % [obj.mode.to_s, obj.name, sha]
91
+ end if now_tree
92
+
93
+ # overwrite with new tree contents
94
+ tree.each do |k, v|
95
+ case v
96
+ when String:
97
+ sha = write_blob(v)
98
+ sha = [sha].pack("H*")
99
+ str = "%s %s\0%s" % ['100644', k, sha]
100
+ tree_contents[k] = str
101
+ when Hash:
102
+ ctree = now_tree/k if now_tree
103
+ sha = write_tree(v, ctree)
104
+ sha = [sha].pack("H*")
105
+ str = "%s %s\0%s" % ['040000', k, sha]
106
+ tree_contents[k + '/'] = str
107
+ end
108
+ end
109
+ tr = tree_contents.sort.map { |k, v| v }.join('')
110
+ self.repo.git.ruby_git.put_raw_object(tr, 'tree')
111
+ end
112
+
113
+ # Write the blob to the index
114
+ # +data+ is the data to write
115
+ #
116
+ # Returns the SHA1 String of the blob
117
+ def write_blob(data)
118
+ self.repo.git.ruby_git.put_raw_object(data, 'blob')
119
+ end
120
+ end # Index
121
+
122
+ end # Grit
@@ -0,0 +1,33 @@
1
+ ##
2
+ # Allows attributes to be declared as lazy, meaning that they won't be
3
+ # computed until they are asked for.
4
+ #
5
+ # Works by delegating each lazy_reader to a cached lazy_source method.
6
+ #
7
+ # class Person
8
+ # lazy_reader :eyes
9
+ #
10
+ # def lazy_source
11
+ # OpenStruct.new(:eyes => 2)
12
+ # end
13
+ # end
14
+ #
15
+ # >> Person.new.eyes
16
+ # => 2
17
+ #
18
+ module Lazy
19
+ def lazy_reader(*args)
20
+ args.each do |arg|
21
+ ivar = "@#{arg}"
22
+ define_method(arg) do
23
+ if instance_variable_defined?(ivar)
24
+ val = instance_variable_get(ivar)
25
+ return val if val
26
+ end
27
+ instance_variable_set(ivar, (@lazy_source ||= lazy_source).send(arg))
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ Object.extend Lazy unless Object.ancestors.include? Lazy
@@ -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
@@ -0,0 +1,99 @@
1
+ module Grit
2
+
3
+ class Ref
4
+
5
+ class << self
6
+
7
+ # Find all Refs
8
+ # +repo+ is the Repo
9
+ # +options+ is a Hash of options
10
+ #
11
+ # Returns Grit::Ref[] (baked)
12
+ def find_all(repo, options = {})
13
+ refs = []
14
+ already = {}
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
+
28
+ if File.file?('packed-refs')
29
+ File.readlines('packed-refs').each do |line|
30
+ if m = /^(\w{40}) (.*?)$/.match(line)
31
+ next if !Regexp.new('^' + prefix).match(m[2])
32
+ name = m[2].sub("#{prefix}/", '')
33
+ commit = Commit.create(repo, :id => m[1])
34
+ if !already[name]
35
+ refs << self.new(name, commit)
36
+ already[name] = true
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ refs
44
+ end
45
+
46
+ protected
47
+
48
+ def prefix
49
+ "refs/#{name.to_s.gsub(/^.*::/, '').downcase}s"
50
+ end
51
+
52
+ end
53
+
54
+ attr_reader :name
55
+ attr_reader :commit
56
+
57
+ # Instantiate a new Head
58
+ # +name+ is the name of the head
59
+ # +commit+ is the Commit that the head points to
60
+ #
61
+ # Returns Grit::Head (baked)
62
+ def initialize(name, commit)
63
+ @name = name
64
+ @commit = commit
65
+ end
66
+
67
+ # Pretty object inspection
68
+ def inspect
69
+ %Q{#<#{self.class.name} "#{@name}">}
70
+ end
71
+ end # Ref
72
+
73
+ # A Head is a named reference to a Commit. Every Head instance contains a name
74
+ # and a Commit object.
75
+ #
76
+ # r = Grit::Repo.new("/path/to/repo")
77
+ # h = r.heads.first
78
+ # h.name # => "master"
79
+ # h.commit # => #<Grit::Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455">
80
+ # h.commit.id # => "1c09f116cbc2cb4100fb6935bb162daa4723f455"
81
+ class Head < Ref
82
+
83
+ # Get the HEAD revision of the repo.
84
+ # +repo+ is the Repo
85
+ # +options+ is a Hash of options
86
+ #
87
+ # Returns Grit::Head (baked)
88
+ def self.current(repo, options = {})
89
+ head = File.read(File.join(repo.path, 'HEAD')).chomp
90
+ if /ref: refs\/heads\/(.*)/.match(head)
91
+ self.new($1, repo.git.rev_parse(options, 'HEAD'))
92
+ end
93
+ end
94
+
95
+ end # Head
96
+
97
+ class Remote < Ref; end
98
+
99
+ end # Grit