Class: Gash
- Inherits:
-
SimpleDelegator
- Object
- SimpleDelegator
- Gash
- Defined in:
- lib/gash.rb
Overview
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 pretty good documentation.
-
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.
See also: #new, #commit, Tree
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.
Defined Under Namespace
Modules: Errors, Helpers Classes: Blob, Tree
Instance Attribute Summary collapse
-
#branch ⇒ Object
Returns the value of attribute branch.
-
#repository ⇒ Object
Returns the value of attribute repository.
Instance Method Summary collapse
-
#branch_exists? ⇒ Boolean
Checks if the current branch exists.
- #cat_file(blob) ⇒ Object
-
#commit(msg) ⇒ Object
Commit the current changes and returns the commit-hash.
- #commit_tree(tree, msg) ⇒ Object
-
#find_repo(dir) ⇒ Object
private.
-
#gash ⇒ Object
:nodoc:.
-
#git(cmd, *rest, &block) ⇒ Object
passes the command over to git.
-
#git_status(cmd, *rest, &block) ⇒ Object
passes the command over to git and returns its status ($?).
- #git_tree(&blk) ⇒ Object
- #git_tree_sha1(from = @branch) ⇒ Object
-
#initialize(repo = ".", branch = "master") ⇒ Gash
constructor
Opens the
repo
with the specifiedbranch
. -
#inspect ⇒ Object
:nodoc:.
- #method_missing(meth, *args, &blk) ⇒ Object
-
#run_git(cmd, *args, &block) ⇒ Object
passes the command over to git (you should not call this directly).
- #to_tree!(from = self) ⇒ Object
-
#update! ⇒ Object
Fetch the latest data from Git; you can use this as a
clear
-method. - #update_head(new_head) ⇒ Object
Constructor Details
#initialize(repo = ".", branch = "master") ⇒ Gash
Opens the repo
with the specified branch
.
350 351 352 353 354 355 356 |
# 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 |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args, &blk) ⇒ Object
464 465 466 467 468 469 470 |
# 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 |
Instance Attribute Details
#branch ⇒ Object
Returns the value of attribute branch.
347 348 349 |
# File 'lib/gash.rb', line 347 def branch @branch end |
#repository ⇒ Object
Returns the value of attribute repository.
347 348 349 |
# File 'lib/gash.rb', line 347 def repository @repository end |
Instance Method Details
#branch_exists? ⇒ Boolean
Checks if the current branch exists
399 400 401 |
# File 'lib/gash.rb', line 399 def branch_exists? git_status('rev-parse', @branch) == 0 end |
#cat_file(blob) ⇒ Object
418 419 420 |
# File 'lib/gash.rb', line 418 def cat_file(blob) git('cat-file', 'blob', blob) end |
#commit(msg) ⇒ Object
Commit the current changes and returns the commit-hash.
Returns nil
if nothing has changed.
391 392 393 394 395 396 |
# File 'lib/gash.rb', line 391 def commit(msg) return unless changed? commit = commit_tree(to_tree!, msg) @sha1 = git_tree_sha1 commit end |
#commit_tree(tree, msg) ⇒ Object
442 443 444 445 446 447 448 449 450 451 |
# 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 |
#find_repo(dir) ⇒ Object
private
410 411 412 413 414 415 416 |
# File 'lib/gash.rb', line 410 def find_repo(dir) Dir.chdir(dir) do File.(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 |
#gash ⇒ Object
:nodoc:
358 359 360 |
# File 'lib/gash.rb', line 358 def gash #:nodoc: self end |
#git(cmd, *rest, &block) ⇒ Object
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
487 488 489 490 491 492 493 494 |
# 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 |
#git_status(cmd, *rest, &block) ⇒ Object
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
506 507 508 |
# File 'lib/gash.rb', line 506 def git_status(cmd, *rest, &block) run_git(cmd, *rest, &block)[2] end |
#git_tree(&blk) ⇒ Object
453 454 455 456 457 |
# 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 |
#git_tree_sha1(from = @branch) ⇒ Object
459 460 461 462 |
# File 'lib/gash.rb', line 459 def git_tree_sha1(from = @branch) git('rev-parse', @branch + '^{tree}') rescue Errors::Git end |
#inspect ⇒ Object
:nodoc:
403 404 405 |
# File 'lib/gash.rb', line 403 def inspect #:nodoc: __getobj__.inspect end |
#run_git(cmd, *args, &block) ⇒ Object
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
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 |
# File 'lib/gash.rb', line 526 def run_git(cmd, *args, &block) = if args.last.kind_of?(Hash) args.pop else {} end [:strip] = true unless .key?(:strip) git_cmd = ["git"] unless [: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 = .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 [:strip] == true [result, reserr, status] end |
#to_tree!(from = self) ⇒ Object
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
# 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 |
#update! ⇒ Object
Fetch the latest data from Git; you can use this as a clear
-method.
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
# 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 |
#update_head(new_head) ⇒ Object
438 439 440 |
# File 'lib/gash.rb', line 438 def update_head(new_head) git('update-ref', 'refs/heads/%s' % @branch, new_head) end |