forgot gblob
[rubygit.git] / lib / git / base.rb
blob4e1e1251c961a3d463ea6e7c1c7847ba4ed423d4
1 module Git
2   
3   class Base
5     @working_directory = nil
6     @repository = nil
7     @index = nil
9     # opens a bare Git Repository - no working directory options
10     def self.bare(git_dir)
11       self.new :repository => git_dir
12     end
13     
14     # opens a new Git Project from a working directory
15     # you can specify non-standard git_dir and index file in the options
16     def self.open(working_dir, opts={})    
17       default = {:working_directory => working_dir}
18       git_options = default.merge(opts)
19       
20       self.new(git_options)
21     end
23     # initializes a git repository
24     #
25     # options:
26     #  :repository
27     #  :index_file
28     #
29     def self.init(working_dir, opts = {})
30       default = {:working_directory => working_dir,
31                  :repository => File.join(working_dir, '.git')}
32       git_options = default.merge(opts)
33       
34       if git_options[:working_directory]
35         # if !working_dir, make it
36         FileUtils.mkdir_p(git_options[:working_directory]) if !File.directory?(git_options[:working_directory])
37       end
38       
39       # run git_init there
40       Git::Lib.new(git_options).init
41        
42       self.new(git_options)
43     end
45     # clones a git repository locally
46     #
47     #  repository - http://repo.or.cz/w/sinatra.git
48     #  name - sinatra
49     #
50     # options:
51     #   :repository
52     #
53     #    :bare
54     #   or 
55     #    :working_directory
56     #    :index_file
57     #
58     def self.clone(repository, name, opts = {})
59       # run git-clone 
60       self.new(Git::Lib.new.clone(repository, name, opts))
61     end
62         
63     def initialize(options = {})
64       if working_dir = options[:working_directory]
65         options[:repository] = File.join(working_dir, '.git') if !options[:repository]
66         options[:index] = File.join(working_dir, '.git', 'index') if !options[:index]
67       end
68       
69       @working_directory = Git::WorkingDirectory.new(options[:working_directory]) if options[:working_directory]
70       @repository = Git::Repository.new(options[:repository]) if options[:repository]
71       @index = Git::Index.new(options[:index], false) if options[:index]
72     end
73   
74   
75     # returns a reference to the working directory
76     #  @git.dir.path
77     #  @git.dir.writeable?
78     def dir
79       @working_directory
80     end
82     # returns reference to the git repository directory
83     #  @git.dir.path
84     def repo
85       @repository
86     end
87     
88     # returns reference to the git index file
89     def index
90       @index
91     end
92     
93     # changes current working directory for a block
94     # to the git working directory
95     #
96     # example
97     #  @git.chdir do 
98     #    # write files
99     #    @git.add
100     #    @git.commit('message')
101     #  end
102     def chdir
103       Dir.chdir(dir.path) do
104         yield dir.path
105       end
106     end
107     
108     # returns the repository size in bytes
109     def repo_size
110       size = 0
111       Dir.chdir(repo.path) do
112         (size, dot) = `du -d0`.chomp.split
113       end
114       size.to_i
115     end
116     
117     #g.config('user.name', 'Scott Chacon') # sets value
118     #g.config('user.email', 'email@email.com')  # sets value
119     #g.config('user.name')  # returns 'Scott Chacon'
120     #g.config # returns whole config hash
121     def config(name = nil, value = nil)
122       if(name && value)
123         # set value
124         lib.config_set(name, value)
125       elsif (name)
126         # return value
127         lib.config_get(name)
128       else
129         # return hash
130         lib.config_list
131       end
132     end
133     
134     # factory methods
135     
136     # returns a Git::Object of the appropriate type
137     # you can also call @git.gtree('tree'), but that's 
138     # just for readability.  If you call @git.gtree('HEAD') it will
139     # still return a Git::Object::Commit object.  
140     #
141     # @git.object calls a factory method that will run a rev-parse 
142     # on the objectish and determine the type of the object and return 
143     # an appropriate object for that type 
144     def object(objectish)
145       Git::Object.new(self, objectish)
146     end
147     
148     def gtree(objectish)
149       Git::Object.new(self, objectish, 'tree')
150     end
151     
152     def gcommit(objectish)
153       Git::Object.new(self, objectish, 'commit')
154     end
155     
156     def gblob(objectish)
157       Git::Object.new(self, objectish, 'blob')
158     end
159     
160     # returns a Git::Log object with count commits
161     def log(count = 30)
162       Git::Log.new(self, count)
163     end
165     # returns a Git::Status object
166     def status
167       Git::Status.new(self)
168     end
169         
170     # returns a Git::Branches object of all the Git::Branch objects for this repo
171     def branches
172       Git::Branches.new(self)
173     end
174     
175     # returns a Git::Branch object for branch_name
176     def branch(branch_name = 'master')
177       Git::Branch.new(self, branch_name)
178     end
180     # returns a Git::Remote object
181     def remote(remote_name = 'origin')
182       Git::Remote.new(self, remote_name)
183     end
185     # this is a convenience method for accessing the class that wraps all the 
186     # actual 'git' forked system calls.  At some point I hope to replace the Git::Lib
187     # class with one that uses native methods or libgit C bindings
188     def lib
189       Git::Lib.new(self)
190     end
191     
192     # will run a grep for 'string' on the HEAD of the git repository
193     # 
194     # to be more surgical in your grep, you can call grep() off a specific
195     # git object.  for example:
196     #
197     #  @git.object("v2.3").grep('TODO')
198     #
199     # in any case, it returns a hash of arrays of the type:
200     #  hsh[tree-ish] = [[line_no, match], [line_no, match2]]
201     #  hsh[tree-ish] = [[line_no, match], [line_no, match2]]
202     #
203     # so you might use it like this:
204     #
205     #   @git.grep("TODO").each do |sha, arr|
206     #     puts "in blob #{sha}:"
207     #     arr.each do |match|
208     #       puts "\t line #{match[0]}: '#{match[1]}'"
209     #     end
210     #   end
211     def grep(string)
212       self.object('HEAD').grep(string)
213     end
214     
215     # returns a Git::Diff object
216     def diff(objectish = 'HEAD', obj2 = nil)
217       Git::Diff.new(self, objectish, obj2)
218     end
219     
220     # adds files from the working directory to the git repository
221     def add(path = '.')
222       self.lib.add(path)
223     end
225     # removes file(s) from the git repository
226     def remove(path = '.', opts = {})
227       self.lib.remove(path, opts)
228     end
230     # resets the working directory to the provided commitish
231     def reset(commitish = nil, opts = {})
232       self.lib.reset(commitish, opts)
233     end
235     # resets the working directory to the commitish with '--hard'
236     def reset_hard(commitish = nil, opts = {})
237       opts = {:hard => true}.merge(opts)
238       self.lib.reset(commitish, opts)
239     end
241     # commits all pending changes in the index file to the git repository
242     def commit(message, opts = {})
243       self.lib.commit(message, opts)
244     end
245         
246     # commits all pending changes in the index file to the git repository,
247     # but automatically adds all modified files without having to explicitly
248     # calling @git.add() on them.  
249     def commit_all(message, opts = {})
250       opts = {:add_all => true}.merge(opts)
251       self.lib.commit(message, opts)
252     end
254     # checks out a branch as the new git working directory
255     def checkout(branch = 'master', opts = {})
256       self.lib.checkout(branch, opts)
257     end
258     
259     # fetches changes from a remote branch - this does not modify the working directory,
260     # it just gets the changes from the remote if there are any
261     def fetch(remote = 'origin')
262       self.lib.fetch(remote)
263     end
265     # pushes changes to a remote repository - easiest if this is a cloned repository,
266     # otherwise you may have to run something like this first to setup the push parameters:
267     #
268     #  @git.config('remote.remote-name.push', 'refs/heads/master:refs/heads/master')
269     #
270     def push(remote = 'origin', branch = 'master')
271       self.lib.push(remote, branch)
272     end
273     
274     # merges one or more branches into the current working branch
275     #
276     # you can specify more than one branch to merge by passing an array of branches
277     def merge(branch, message = 'merge')
278       self.lib.merge(branch, message)
279     end
281     # fetches a branch from a remote and merges it into the current working branch
282     def pull(remote = 'origin', branch = 'master', message = 'origin pull')
283       fetch(remote)
284       merge(branch, message)
285     end
286     
287     # returns an array of Git:Remote objects
288     def remotes
289       self.lib.remotes.map { |r| Git::Remote.new(self, r) }
290     end
292     # adds a new remote to this repository
293     # url can be a git url or a Git::Base object if it's a local reference
294     # 
295     #  @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git')
296     #  @git.fetch('scotts_git')
297     #  @git.merge('scotts_git/master')
298     #
299     def add_remote(name, url, opts = {})
300       if url.is_a?(Git::Base)
301         url = url.repo.path
302       end
303       self.lib.remote_add(name, url, opts)
304       Git::Remote.new(self, name)
305     end
307     # returns an array of all Git::Tag objects for this repository
308     def tags
309       self.lib.tags.map { |r| tag(r) }
310     end
311     
312     # returns a Git::Tag object
313     def tag(tag_name)
314       Git::Object.new(self, tag_name, 'tag', true)
315     end
317     # creates a new git tag (Git::Tag)
318     def add_tag(tag_name)
319       self.lib.tag(tag_name)
320       tag(tag_name)
321     end
322     
323     # creates an archive file of the given tree-ish
324     def archive(treeish, file = nil, opts = {})
325       self.object(treeish).archive(file, opts)
326     end
327     
328     # repacks the repository
329     def repack
330       self.lib.repack
331     end
332     
333     # runs git rev-parse to convert the objectish to a full sha
334     #
335     #   @git.revparse("HEAD^^")
336     #   @git.revparse('v2.4^{tree}')
337     #   @git.revparse('v2.4:/doc/index.html')
338     #
339     def revparse(objectish)
340       self.lib.revparse(objectish)
341     end
343     # returns the name of the branch the working directory is currently on
344     def current_branch
345       self.lib.branch_current
346     end
348     
349   end
350