class Gash
What is Gash
?¶ ↑
-
Gash
lets you access a Git-repo as a Hash. -
Gash
doesn’t touch your working directory -
Gash
only cares about the data, not the commits. -
Gash
only cares about the latest data. -
Gash
can commit. -
Gash
will automatically create branches if they don’t exist. -
Gash
only loads what it needs, so it handles large repos well. -
Gash
got a bug tracker. -
Gash
is being developed at GitHub.
Some of these “rules” might change it the future.
How do you install it?¶ ↑
The stable version can installed through RubyGems:
sudo gem install gash
The unstable version can be checked out through Git at GitHub, and installed through this command:
rake install
How do you use it?¶ ↑
gash = Gash.new gash["README"] = "new content" gash.commit("Some changes...")
It’s also important to remember that a Gash
is simply a Tree
, so you can also call those methods.
Credits¶ ↑
This code is based upon git-shelve, created by Michael Siebert, which is released under LGPL. However, Michael has allowed me to release this under the MIT-license as long as I keep his name here.
And, in fact: I could never create this without the code written by Michael. You should really thank him!
Older versions of Gash
, which doesn’t include this section or the MIT-license, is still licensed under LGPL.
Attributes
Public Class Methods
Opens the repo
with the specified branch
.
# File lib/gash.rb, line 350 def initialize(repo = ".", branch = "master") @branch = branch @repository = repo @repository = find_repo(repo) __setobj__(Tree.new(:parent => self)) update! end
Public Instance Methods
Checks if the current branch exists
# File lib/gash.rb, line 399 def branch_exists? git_status('rev-parse', @branch) == 0 end
# File lib/gash.rb, line 418 def cat_file(blob) git('cat-file', 'blob', blob) end
Commit the current changes and returns the commit-hash.
Returns nil
if nothing has changed.
# File lib/gash.rb, line 391 def commit(msg) return unless changed? commit = commit_tree(to_tree!, msg) @sha1 = git_tree_sha1 commit end
# File lib/gash.rb, line 442 def commit_tree(tree, msg) if branch_exists? commit = git('commit-tree', tree, '-p', @branch, :input => msg) update_head(commit) else commit = git('commit-tree', tree, :input => msg) git('branch', @branch, commit) end commit end
private
# File lib/gash.rb, line 410 def find_repo(dir) Dir.chdir(dir) do File.expand_path(git('rev-parse', '--git-dir', :git_dir => false)) end rescue Errno::ENOENT, Gash::Errors::Git raise Errors::NoGitRepo.new("No Git repository at: " + @repository) end
passes the command over to git
Parameters¶ ↑
- cmd<String>
-
the git command to execute
- *rest
-
any number of String arguments to the command, followed by an options hash
- &block
-
if you supply a block, you can communicate with git throught a pipe. NEVER even think about closing the stream!
Options¶ ↑
- :strip<Boolean>
-
true to strip the output String#strip, false not to to it
Raises¶ ↑
Errors::Git
-
if git returns non-null, an Exception is raised
Returns¶ ↑
- String
-
if you didn’t supply a block, the things git said on STDOUT, otherwise noting
# File lib/gash.rb, line 487 def git(cmd, *rest, &block) result, reserr, status = run_git(cmd, *rest, &block) if status != 0 raise Errors::Git.new("Error: #{cmd} returned #{status}. STDERR: #{reserr}") end result end
passes the command over to git and returns its status ($?)
Parameters¶ ↑
- cmd<String>
-
the git command to execute
- *rest
-
any number of String arguments to the command, followed by an options hash
- &block
-
if you supply a block, you can communicate with git throught a pipe. NEVER even think about closing the stream!
Returns¶ ↑
- Integer
-
the return status of git
# File lib/gash.rb, line 506 def git_status(cmd, *rest, &block) run_git(cmd, *rest, &block)[2] end
# File lib/gash.rb, line 453 def git_tree(&blk) git('ls-tree', '-r', '-t', '-z', @branch).split("\0").each(&blk) rescue Errors::Git "" end
# File lib/gash.rb, line 459 def git_tree_sha1(from = @branch) git('rev-parse', @branch + '^{tree}') rescue Errors::Git end
# File lib/gash.rb, line 464 def method_missing(meth, *args, &blk) target = self.__getobj__ unless target.respond_to?(meth) Object.instance_method(:method_missing).bind(self).call(meth, *args, &blk) end target.__send__(meth, *args, &blk) end
passes the command over to git (you should not call this directly)
Parameters¶ ↑
- cmd<String>
-
the git command to execute
- *rest
-
any number of String arguments to the command, followed by an options hash
- &block
-
if you supply a block, you can communicate with git throught a pipe. NEVER even think about closing the stream!
Options¶ ↑
- :strip<Boolean>
-
true to strip the output String#strip, false not to to it
- :git_dir<Boolean>
-
true to automatically use @repository as git-dir, false to not use anything.
Raises¶ ↑
Errors::Git
-
if git returns non-null, an Exception is raised
Returns¶ ↑
- Array[String, String, Integer]
-
the first item is the STDOUT of git, the second is the STDERR, the third is the return-status
# File lib/gash.rb, line 526 def run_git(cmd, *args, &block) options = if args.last.kind_of?(Hash) args.pop else {} end options[:strip] = true unless options.key?(:strip) git_cmd = ["git"] unless options[:git_dir] == false git_cmd.push("--git-dir", @repository) end git_cmd.push(cmd, *args) result = "" reserr = "" status = Open4.popen4(*git_cmd) do |pid, stdin, stdout, stderr| if input = options.delete(:input) stdin.write(input.join) elsif block_given? yield stdin end stdin.close_write result = "" reserr = "" while !stdout.eof result << stdout.read end while !stderr.eof reserr << stderr.read end end result.strip! if options[:strip] == true [result, reserr, status] end
# File lib/gash.rb, line 422 def to_tree!(from = self) input = [] from.each do |key, value| if value.tree? value.sha1 ||= to_tree!(value) value.mode ||= "040000" input << "#{value.mode} tree #{value.sha1}\t#{key}\0" else value.sha1 ||= git('hash-object', '-w', '--stdin', :input => value.to_s) value.mode ||= "100644" input << "#{value.mode} blob #{value.sha1}\t#{key}\0" end end git('mktree', '-z', :input => input) end
Fetch the latest data from Git; you can use this as a clear
-method.
# File lib/gash.rb, line 363 def update! clear self.sha1 = git_tree_sha1 git_tree do |line| line.strip! mode = line[0, 6] type = line[7] sha1 = line[12, 40] name = line[53..-1] name = name[/[^\/]+$/] parent = if $`.empty? self else self[$`.chomp("/")] end parent[name, true] = case type when ?b Blob.new(:sha1 => sha1, :mode => mode) when ?t Tree.new(:sha1 => sha1, :mode => mode) end end self end
# File lib/gash.rb, line 438 def update_head(new_head) git('update-ref', 'refs/heads/%s' % @branch, new_head) end