Class: GitDS::Repo
- Inherits:
-
Grit::Repo
- Object
- Grit::Repo
- GitDS::Repo
- Defined in:
- lib/git-ds/repo.rb
Overview
A Git repository.
Note: StagingIndex is cached, as it is from the command line.
Direct Known Subclasses
Constant Summary collapse
- GIT_DIR =
::File::SEPARATOR + '.git'
- DEFAULT_TAG =
'0.0.0'
- DEFAULT_BRANCH =
'master'
Instance Attribute Summary collapse
-
#current_branch ⇒ Object
readonly
Returns the value of attribute current_branch.
-
#last_branch_tag ⇒ Object
readonly
Returns the value of attribute last_branch_tag.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Class Method Summary collapse
-
.create(path) ⇒ Object
TODO: something more intelligent, e.g.
-
.top_level(path = '.') ⇒ Object
Return the top-level directory of the repo containing the location ‘path’.
Instance Method Summary collapse
-
#add(path, data = '', on_fs = false) ⇒ Object
Add a DB entry at the filesystem path ‘path’ with contents ‘data’.
-
#add_files ⇒ Object
———————————————————————-.
-
#branch(tag = @current_branch) ⇒ Object
Return the Head object for the specified branch.
-
#clean_tag(name) ⇒ Object
Return a cleaned-up version of the tag name, suitable for use as a filename.
-
#create_branch(tag = next_branch_tag(), sha = nil) ⇒ Object
Creates a branch in refs/heads and associates it with the specified commit.
-
#delete(path) ⇒ Object
Remove an object from the database.
-
#exec_git_cmd(cmd, actor = nil) ⇒ Object
Execute the specified command using Repo#exec_in_git_dir.
-
#exec_in_git_dir(&block) ⇒ Object
Change to the Repo#top_level dir, yield to block, then pop the dir stack.
-
#include?(path) ⇒ Boolean
(also: #exist?)
Return true if path exists in repo (on fs or in-tree).
-
#index_new ⇒ Object
Return an empty git index for the repo.
-
#initialize(path) ⇒ Repo
constructor
Initialize a repo from the .git subdir in the given path.
-
#list(path = nil) ⇒ Object
Return a Hash of the contents of ‘path’.
-
#list_blobs(path = '') ⇒ Object
Return Hash of all Blob child objects at ‘path’.
-
#list_trees(path = '') ⇒ Object
Return Hash of all Tree child objects at ‘path’.
-
#merge_branch(tag = @current_branch, actor = nil) ⇒ Object
Merge specified branch into master.
-
#next_branch_tag ⇒ Object
Returns the next value for a tag.
-
#object_data(path) ⇒ Object
Fetch the contents of a DB or FS object from the object database.
-
#path_to_object(path) ⇒ Object
Fetch an object from the repo based on its path.
-
#path_to_sha(path, head = @current_branch) ⇒ Object
Return the SHA1 of ‘path’ in repo.
-
#raw_tree(path, recursive = false) ⇒ Object
Returns the raw (git cat-file) representation of a tree.
-
#root_sha(head = @current_branch) ⇒ Object
Return the SHA of the root Tree in the repository.
-
#set_branch(tag, actor = nil) ⇒ Object
(also: #branch=)
Sets the current branch to the specified tag.
-
#stage(&block) ⇒ Object
Yield staging index to the provided block, then write the index when the block returns.
-
#stage_and_commit(msg, actor = nil, &block) ⇒ Object
Read the Git staging index, then commit it with the provided message and author info.
-
#staging ⇒ Object
(also: #index)
Return the staging index for the repo.
-
#staging=(idx) ⇒ Object
(also: #index=)
Set the staging index.
-
#staging? ⇒ Boolean
Return true if a staging index is active.
-
#tag_object(tag, sha) ⇒ Object
Tag (name) an object, e.g.
-
#top_level ⇒ Object
Return the top-level directory of the repo (the parent of .git).
-
#tree(treeish = nil, paths = []) ⇒ Object
The Tree object for the given treeish reference
treeish
is the reference (default Repo#current_branch)paths
is an optional Array of directory paths to restrict the tree (default []). -
#tree_contents(tree) ⇒ Object
Return a Hash of the contents of ‘tree’.
-
#unstage ⇒ Object
Close staging index.
Constructor Details
#initialize(path) ⇒ Repo
Initialize a repo from the .git subdir in the given path.
76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/git-ds/repo.rb', line 76 def initialize(path) path.chomp(GIT_DIR) if path.end_with? GIT_DIR @path = (path.empty?) ? '.' : path # TODO: get last branch tag from repo # prob as a git-config @last_branch_tag = DEFAULT_TAG.dup @current_branch = DEFAULT_BRANCH.dup @staging_index = nil @saved_stages = {} super(@path + GIT_DIR) end |
Instance Attribute Details
#current_branch ⇒ Object (readonly)
Returns the value of attribute current_branch.
38 39 40 |
# File 'lib/git-ds/repo.rb', line 38 def current_branch @current_branch end |
#last_branch_tag ⇒ Object (readonly)
Returns the value of attribute last_branch_tag.
35 36 37 |
# File 'lib/git-ds/repo.rb', line 35 def last_branch_tag @last_branch_tag end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
40 41 42 |
# File 'lib/git-ds/repo.rb', line 40 def path @path end |
Class Method Details
.create(path) ⇒ Object
TODO: something more intelligent, e.g. with git/repo options
43 44 45 46 47 48 49 50 51 52 |
# File 'lib/git-ds/repo.rb', line 43 def self.create(path) Grit::Repo.init(path) # handle broken Grit init if not File.exist?(path + GIT_DIR) `git init #{path}` end self.new(path) # discard Grit::Repo object and use a Repo object end |
.top_level(path = '.') ⇒ Object
Return the top-level directory of the repo containing the location ‘path’.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/git-ds/repo.rb', line 57 def self.top_level(path='.') local = (path == '.') old_dir = nil if path != '.' old_dir = Dir.getwd dest = (File.directory? path) ? path : File.dirname(path) Dir.chdir dest end dir = `git rev-parse --show-toplevel`.chomp Dir.chdir old_dir if old_dir (dir == '.git') ? '.' : dir.chomp(GIT_DIR) end |
Instance Method Details
#add(path, data = '', on_fs = false) ⇒ Object
Add a DB entry at the filesystem path ‘path’ with contents ‘data’. If ‘on_fs’ is true, the file is created in the filesystem as well. This uses the staging index.
328 329 330 |
# File 'lib/git-ds/repo.rb', line 328 def add(path, data='', on_fs=false) self.stage { |idx| idx.add(path, data, on_fs) } end |
#add_files ⇒ Object
321 |
# File 'lib/git-ds/repo.rb', line 321 alias :add_files :add |
#branch(tag = @current_branch) ⇒ Object
Return the Head object for the specified branch
126 127 128 |
# File 'lib/git-ds/repo.rb', line 126 def branch(tag=@current_branch) get_head(tag) end |
#clean_tag(name) ⇒ Object
Return a cleaned-up version of the tag name, suitable for use as a filename. Replaces all non-alphanumeric characters (except “-.,”) with “_”.
111 112 113 |
# File 'lib/git-ds/repo.rb', line 111 def clean_tag(name) name.gsub( /[^-.,_[:alnum:]]/, '_' ) end |
#create_branch(tag = next_branch_tag(), sha = nil) ⇒ Object
Creates a branch in refs/heads and associates it with the specified commit. If sha is nil, the latest commit from ‘master’ is used. The canonical name of the tag is returned.
135 136 137 138 139 140 141 142 143 |
# File 'lib/git-ds/repo.rb', line 135 def create_branch( tag=next_branch_tag(), sha=nil ) if not sha sha = commits.last.id #sha = branches.first.commit.id if not sha end name = clean_tag(tag) update_ref(name, sha) name end |
#delete(path) ⇒ Object
Remove an object from the database. This can be a path to a Tree or a Blob.
335 336 337 |
# File 'lib/git-ds/repo.rb', line 335 def delete(path) self.stage { |idx| idx.delete(path) } end |
#exec_git_cmd(cmd, actor = nil) ⇒ Object
Execute the specified command using Repo#exec_in_git_dir.
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/git-ds/repo.rb', line 290 def exec_git_cmd( cmd, actor=nil ) old_aname = ENV['GIT_AUTHOR_NAME'] old_aemail = ENV['GIT_AUTHOR_EMAIL'] old_cname = ENV['GIT_COMMITTER_NAME'] old_cemail = ENV['GIT_COMMITTER_EMAIL'] old_pager = ENV['GIT_PAGER'] if actor ENV['GIT_AUTHOR_NAME'] = actor.name ENV['GIT_AUTHOR_EMAIL'] = actor.email ENV['GIT_COMMITTER_NAME'] = actor.name ENV['GIT_COMMITTER_EMAIL'] = actor.email end ENV['GIT_PAGER'] = '' # Note: we cannot use Grit#raw_git_call as it requires an index file rv = exec_in_git_dir do `#{cmd}` raise CommandError, rv if $? != 0 end ENV['GIT_AUTHOR_NAME'] = old_aname ENV['GIT_AUTHOR_EMAIL'] = old_aemail ENV['GIT_COMMITTER_NAME'] = old_cname ENV['GIT_COMMITTER_EMAIL'] = old_cemail ENV['GIT_PAGER'] = old_pager rv end |
#exec_in_git_dir(&block) ⇒ Object
Change to the Repo#top_level dir, yield to block, then pop the dir stack.
273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/git-ds/repo.rb', line 273 def exec_in_git_dir(&block) curr = Dir.getwd result = nil begin Dir.chdir top_level result = yield rescue raise ensure Dir.chdir curr end result end |
#include?(path) ⇒ Boolean Also known as: exist?
Return true if path exists in repo (on fs or in-tree)
100 101 102 |
# File 'lib/git-ds/repo.rb', line 100 def include?(path) path_to_object(path) ? true : false end |
#index_new ⇒ Object
Return an empty git index for the repo.
204 205 206 |
# File 'lib/git-ds/repo.rb', line 204 def index_new Index.new(self) end |
#list(path = nil) ⇒ Object
Return a Hash of the contents of ‘path’. This is just a wrapper for tree_contents.
422 423 424 425 426 427 |
# File 'lib/git-ds/repo.rb', line 422 def list(path=nil) sha = path_to_sha(path) # ensure correct operation even if path doesn't exist in repo t = sha ? tree(sha) : tree(@current_branch, (path ? [path] : [])) t ? tree_contents( t ) : {} end |
#list_blobs(path = '') ⇒ Object
Return Hash of all Blob child objects at ‘path’.
432 433 434 |
# File 'lib/git-ds/repo.rb', line 432 def list_blobs(path='') list(path).delete_if { |k,v| not v.kind_of?(Grit::Blob) } end |
#list_trees(path = '') ⇒ Object
Return Hash of all Tree child objects at ‘path’.
439 440 441 |
# File 'lib/git-ds/repo.rb', line 439 def list_trees(path='') list(path).delete_if { |k,v| not v.kind_of?(Grit::Tree) } end |
#merge_branch(tag = @current_branch, actor = nil) ⇒ Object
Merge specified branch into master.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/git-ds/repo.rb', line 172 def merge_branch( tag=@current_branch, actor=nil ) raise "Invalid branch '#{tag}'" if not is_head?(tag) tag.gsub!(/['\\]/, '') # switch to master branch set_branch(DEFAULT_BRANCH, actor) # merge target branch to master branch rv = nil begin rv = exec_git_cmd("git merge -n --no-ff --no-log --no-squash '#{tag}'", actor) rescue CommandError => e $stderr.puts e. end rv end |
#next_branch_tag ⇒ Object
Returns the next value for a tag. This is primarily used to auto-generate tag names, e.g. 1.0.1, 1.0.2, etc.
119 120 121 |
# File 'lib/git-ds/repo.rb', line 119 def next_branch_tag @last_branch_tag.succ! end |
#object_data(path) ⇒ Object
Fetch the contents of a DB or FS object from the object database. This uses the staging index. Note: This returns nil if path is a Tree instead of a blob
344 345 346 347 348 |
# File 'lib/git-ds/repo.rb', line 344 def object_data(path) blob = path_to_object(path) return nil if (not blob) || (blob.kind_of? Grit::Tree) blob.kind_of?(Grit::Blob) ? blob.data : blob end |
#path_to_object(path) ⇒ Object
Fetch an object from the repo based on its path.
If a staging index exists, its tree will be used; otherwise, the tree Repo#current_branch will be used.
The object returned will be a Grit::Blob, a Grit::Tree, or the raw data from the staging index.
463 464 465 466 467 468 469 470 471 |
# File 'lib/git-ds/repo.rb', line 463 def path_to_object(path) treeish = (@staging_index ? staging.sha : @current_branch) tree = self.tree(treeish, [path]) return tree.blobs.first if tree && (not tree.blobs.empty?) return tree.trees.first if tree && (not tree.trees.empty?) # check staging index in case object has not been written to object DB staging? ? staging.path_to_object(path) : nil end |
#path_to_sha(path, head = @current_branch) ⇒ Object
Return the SHA1 of ‘path’ in repo. Uses staging index if present.
382 383 384 385 386 387 388 389 390 391 392 393 |
# File 'lib/git-ds/repo.rb', line 382 def path_to_sha(path, head=@current_branch) # Return the root of the repo if no path is specified return root_sha(head) if (not path) || (path.empty?) if staging? @staging_index.sync head = @staging_index.current_tree.id end dir = tree(head, [path]) (dir && dir.contents.length > 0) ? dir.contents.first.id : nil end |
#raw_tree(path, recursive = false) ⇒ Object
Returns the raw (git cat-file) representation of a tree.
446 447 448 449 450 451 452 |
# File 'lib/git-ds/repo.rb', line 446 def raw_tree(path, recursive=false) # Note: to construct recursive tree: # Tree.allocate.construct_initialize(repo, treeish, output) # from repo.git.ls_tree or raw_tree sha = path_to_sha(path) sha ? git.ruby_git.get_raw_tree( sha, recursive ) : '' end |
#root_sha(head = @current_branch) ⇒ Object
Return the SHA of the root Tree in the repository.
Uses the staging index if it is active.
400 401 402 403 404 405 406 407 |
# File 'lib/git-ds/repo.rb', line 400 def root_sha(head=@current_branch) if staging? @staging_index.sync return @staging_index.sha end (self.commits.count > 0) ? self.commits.last.tree.id : nil end |
#set_branch(tag, actor = nil) ⇒ Object Also known as: branch=
Sets the current branch to the specified tag. This changes the default branch for all repo activity and sets HEAD.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/git-ds/repo.rb', line 149 def set_branch( tag, actor=nil ) # allow creating of new branches via -b if they do not exist opt = (is_head? tag) ? '' : '-b' # Save staging index for current branch @saved_stages[@current_branch] = self.staging if staging? exec_git_cmd( "git checkout -q -m #{opt} '#{tag}'", actor ) # Synchronize staging index (required before merge) unstage # Update current_branch info and restore staging for branch self.staging = @saved_stages[tag] self.staging.sync if staging? @current_branch = tag end |
#stage(&block) ⇒ Object
Yield staging index to the provided block, then write the index when the block returns. This allows the Git staging index to be modified from within Ruby, with all changes being visible to the Git command-line tools. Returns staging index for chaining purposes.
250 251 252 253 254 255 |
# File 'lib/git-ds/repo.rb', line 250 def stage(&block) idx = self.staging rv = yield idx idx.build rv end |
#stage_and_commit(msg, actor = nil, &block) ⇒ Object
Read the Git staging index, then commit it with the provided message and author info. Returns SHA of commit.
262 263 264 265 266 267 |
# File 'lib/git-ds/repo.rb', line 262 def stage_and_commit(msg, actor=nil, &block) stage(&block) sha = staging.commit(msg, actor) unstage sha end |
#staging ⇒ Object Also known as: index
Return the staging index for the repo.
211 212 213 214 |
# File 'lib/git-ds/repo.rb', line 211 def staging # TODO: mutex @staging_index ||= StageIndex.read(self) end |
#staging=(idx) ⇒ Object Also known as: index=
Set the staging index. This can be used to clear the staging index, or to use a specific index as the staging index.
220 221 222 223 |
# File 'lib/git-ds/repo.rb', line 220 def staging=(idx) # TODO: mutex @staging_index = idx end |
#staging? ⇒ Boolean
Return true if a staging index is active.
236 237 238 |
# File 'lib/git-ds/repo.rb', line 236 def staging? @staging_index != nil end |
#tag_object(tag, sha) ⇒ Object
Tag (name) an object, e.g. a commit.
195 196 197 |
# File 'lib/git-ds/repo.rb', line 195 def tag_object(tag, sha) git.fs_write("refs/tags/#{clean_tag(tag)}", sha) end |
#top_level ⇒ Object
Return the top-level directory of the repo (the parent of .git).
93 94 95 |
# File 'lib/git-ds/repo.rb', line 93 def top_level git.git_dir.chomp(GIT_DIR) end |
#tree(treeish = nil, paths = []) ⇒ Object
The Tree object for the given treeish reference
+treeish+ is the reference (default Repo#current_branch)
+paths+ is an optional Array of directory paths to restrict the tree (default [])
Uses staging index if present and provides wrapper for nil treeish.
Examples
repo.tree('master', ['lib/'])
Returns Grit::Tree (baked)
363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/git-ds/repo.rb', line 363 def tree(treeish=nil, paths = []) begin if staging? && (not treeish) @staging_index.sync super(@staging_index.current_tree.id, paths) else treeish = @current_branch if not treeish super end rescue Grit::GitRuby::Repository::NoSuchPath end end |
#tree_contents(tree) ⇒ Object
Return a Hash of the contents of ‘tree’. The key is the filename, the value is the Grit object (a Tree or a Blob).
413 414 415 416 |
# File 'lib/git-ds/repo.rb', line 413 def tree_contents(tree) return {} if not tree tree.contents.inject({}) { |h,item| h[item.name] = item; h } end |
#unstage ⇒ Object
Close staging index. This discards all (non-committed) changes in the staging index.
229 230 231 |
# File 'lib/git-ds/repo.rb', line 229 def unstage self.staging=(nil) # yes, the self is required. not sure why. end |