5 @working_directory = nil
12 # opens a bare Git Repository - no working directory options
13 def self.bare(git_dir, opts = {})
14 default = {:repository => git_dir}
15 git_options = default.merge(opts)
20 # opens a new Git Project from a working directory
21 # you can specify non-standard git_dir and index file in the options
22 def self.open(working_dir, opts={})
23 default = {:working_directory => working_dir}
24 git_options = default.merge(opts)
29 # initializes a git repository
35 def self.init(working_dir, opts = {})
36 default = {:working_directory => working_dir,
37 :repository => File.join(working_dir, '.git')}
38 git_options = default.merge(opts)
40 if git_options[:working_directory]
41 # if !working_dir, make it
42 FileUtils.mkdir_p(git_options[:working_directory]) if !File.directory?(git_options[:working_directory])
46 Git::Lib.new(git_options).init
51 # clones a git repository locally
53 # repository - http://repo.or.cz/w/sinatra.git
64 def self.clone(repository, name, opts = {})
66 self.new(Git::Lib.new.clone(repository, name, opts))
69 def initialize(options = {})
70 if working_dir = options[:working_directory]
71 options[:repository] = File.join(working_dir, '.git') if !options[:repository]
72 options[:index] = File.join(working_dir, '.git', 'index') if !options[:index]
75 @logger = options[:log]
76 @logger.info("Starting Git")
79 @working_directory = Git::WorkingDirectory.new(options[:working_directory]) if options[:working_directory]
80 @repository = Git::Repository.new(options[:repository]) if options[:repository]
81 @index = Git::Index.new(options[:index], false) if options[:index]
85 # returns a reference to the working directory
92 # returns reference to the git repository directory
98 # returns reference to the git index file
104 def set_working(work_dir, check = true)
106 @working_directory = Git::WorkingDirectory.new(work_dir.to_s, check)
109 def set_index(index_file, check = true)
111 @index = Git::Index.new(index_file.to_s, check)
114 # changes current working directory for a block
115 # to the git working directory
121 # @git.commit('message')
124 Dir.chdir(dir.path) do
129 # returns the repository size in bytes
132 Dir.chdir(repo.path) do
133 (size, dot) = `du -d0`.chomp.split
138 #g.config('user.name', 'Scott Chacon') # sets value
139 #g.config('user.email', 'email@email.com') # sets value
140 #g.config('user.name') # returns 'Scott Chacon'
141 #g.config # returns whole config hash
142 def config(name = nil, value = nil)
145 lib.config_set(name, value)
157 # returns a Git::Object of the appropriate type
158 # you can also call @git.gtree('tree'), but that's
159 # just for readability. If you call @git.gtree('HEAD') it will
160 # still return a Git::Object::Commit object.
162 # @git.object calls a factory method that will run a rev-parse
163 # on the objectish and determine the type of the object and return
164 # an appropriate object for that type
165 def object(objectish)
166 Git::Object.new(self, objectish)
170 Git::Object.new(self, objectish, 'tree')
173 def gcommit(objectish)
174 Git::Object.new(self, objectish, 'commit')
178 Git::Object.new(self, objectish, 'blob')
181 # returns a Git::Log object with count commits
183 Git::Log.new(self, count)
186 # returns a Git::Status object
188 Git::Status.new(self)
191 # returns a Git::Branches object of all the Git::Branch objects for this repo
193 Git::Branches.new(self)
196 # returns a Git::Branch object for branch_name
197 def branch(branch_name = 'master')
198 Git::Branch.new(self, branch_name)
201 # returns a Git::Remote object
202 def remote(remote_name = 'origin')
203 Git::Remote.new(self, remote_name)
206 # this is a convenience method for accessing the class that wraps all the
207 # actual 'git' forked system calls. At some point I hope to replace the Git::Lib
208 # class with one that uses native methods or libgit C bindings
210 @lib ||= Git::Lib.new(self, @logger)
213 # will run a grep for 'string' on the HEAD of the git repository
215 # to be more surgical in your grep, you can call grep() off a specific
216 # git object. for example:
218 # @git.object("v2.3").grep('TODO')
220 # in any case, it returns a hash of arrays of the type:
221 # hsh[tree-ish] = [[line_no, match], [line_no, match2]]
222 # hsh[tree-ish] = [[line_no, match], [line_no, match2]]
224 # so you might use it like this:
226 # @git.grep("TODO").each do |sha, arr|
227 # puts "in blob #{sha}:"
228 # arr.each do |match|
229 # puts "\t line #{match[0]}: '#{match[1]}'"
233 self.object('HEAD').grep(string)
236 # returns a Git::Diff object
237 def diff(objectish = 'HEAD', obj2 = nil)
238 Git::Diff.new(self, objectish, obj2)
241 # adds files from the working directory to the git repository
246 # removes file(s) from the git repository
247 def remove(path = '.', opts = {})
248 self.lib.remove(path, opts)
251 # resets the working directory to the provided commitish
252 def reset(commitish = nil, opts = {})
253 self.lib.reset(commitish, opts)
256 # resets the working directory to the commitish with '--hard'
257 def reset_hard(commitish = nil, opts = {})
258 opts = {:hard => true}.merge(opts)
259 self.lib.reset(commitish, opts)
262 # commits all pending changes in the index file to the git repository
263 def commit(message, opts = {})
264 self.lib.commit(message, opts)
267 # commits all pending changes in the index file to the git repository,
268 # but automatically adds all modified files without having to explicitly
269 # calling @git.add() on them.
270 def commit_all(message, opts = {})
271 opts = {:add_all => true}.merge(opts)
272 self.lib.commit(message, opts)
275 # checks out a branch as the new git working directory
276 def checkout(branch = 'master', opts = {})
277 self.lib.checkout(branch, opts)
280 # fetches changes from a remote branch - this does not modify the working directory,
281 # it just gets the changes from the remote if there are any
282 def fetch(remote = 'origin')
283 self.lib.fetch(remote)
286 # pushes changes to a remote repository - easiest if this is a cloned repository,
287 # otherwise you may have to run something like this first to setup the push parameters:
289 # @git.config('remote.remote-name.push', 'refs/heads/master:refs/heads/master')
291 def push(remote = 'origin', branch = 'master')
292 self.lib.push(remote, branch)
295 # merges one or more branches into the current working branch
297 # you can specify more than one branch to merge by passing an array of branches
298 def merge(branch, message = 'merge')
299 self.lib.merge(branch, message)
302 # fetches a branch from a remote and merges it into the current working branch
303 def pull(remote = 'origin', branch = 'master', message = 'origin pull')
305 merge(branch, message)
308 # returns an array of Git:Remote objects
310 self.lib.remotes.map { |r| Git::Remote.new(self, r) }
313 # adds a new remote to this repository
314 # url can be a git url or a Git::Base object if it's a local reference
316 # @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git')
317 # @git.fetch('scotts_git')
318 # @git.merge('scotts_git/master')
320 def add_remote(name, url, opts = {})
321 if url.is_a?(Git::Base)
324 self.lib.remote_add(name, url, opts)
325 Git::Remote.new(self, name)
328 # returns an array of all Git::Tag objects for this repository
330 self.lib.tags.map { |r| tag(r) }
333 # returns a Git::Tag object
335 Git::Object.new(self, tag_name, 'tag', true)
338 # creates a new git tag (Git::Tag)
339 def add_tag(tag_name)
340 self.lib.tag(tag_name)
344 # creates an archive file of the given tree-ish
345 def archive(treeish, file = nil, opts = {})
346 self.object(treeish).archive(file, opts)
349 # repacks the repository
355 ## LOWER LEVEL INDEX OPERATIONS ##
357 def with_index(new_index)
359 set_index(new_index, false)
360 return_value = yield @index
365 def with_temp_index &blk
366 tempfile = Tempfile.new('temp-index')
367 temp_path = tempfile.path
369 with_index(temp_path, &blk)
372 def checkout_index(opts = {})
373 self.lib.checkout_index(opts)
376 def read_tree(treeish, opts = {})
377 self.lib.read_tree(treeish, opts)
384 def commit_tree(tree = nil, opts = {})
385 Git::Object::Commit.new(self, self.lib.commit_tree(tree, opts))
388 def write_and_commit_tree(opts = {})
390 commit_tree(tree, opts)
393 def update_ref(branch, commit)
394 branch(branch).update_ref(commit)
402 def with_working(work_dir)
404 old_working = @working_directory
405 set_working(work_dir)
406 Dir.chdir work_dir do
407 return_value = yield @working_directory
409 set_working(old_working)
413 def with_temp_working &blk
414 tempfile = Tempfile.new("temp-workdir")
415 temp_dir = tempfile.path
417 Dir.mkdir(temp_dir, 0700)
418 with_working(temp_dir, &blk)
422 # runs git rev-parse to convert the objectish to a full sha
424 # @git.revparse("HEAD^^")
425 # @git.revparse('v2.4^{tree}')
426 # @git.revparse('v2.4:/doc/index.html')
428 def revparse(objectish)
429 self.lib.revparse(objectish)
432 # returns the name of the branch the working directory is currently on
434 self.lib.branch_current