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 ‘master’)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.
70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/git-ds/repo.rb', line 70 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 |
# File 'lib/git-ds/repo.rb', line 43 def self.create(path) Grit::Repo.init(path) 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’.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/git-ds/repo.rb', line 51 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` 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.
314 315 316 |
# File 'lib/git-ds/repo.rb', line 314 def add(path, data='', on_fs=false) self.stage { |idx| idx.add(path, data, on_fs) } end |
#add_files ⇒ Object
307 |
# File 'lib/git-ds/repo.rb', line 307 alias :add_files :add |
#branch(tag = @current_branch) ⇒ Object
Return the Head object for the specified branch
120 121 122 |
# File 'lib/git-ds/repo.rb', line 120 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 “_”.
105 106 107 |
# File 'lib/git-ds/repo.rb', line 105 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.
129 130 131 132 133 134 135 136 137 |
# File 'lib/git-ds/repo.rb', line 129 def create_branch( tag=next_branch_tag(), sha=nil ) if not sha sha = commits.first.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.
321 322 323 |
# File 'lib/git-ds/repo.rb', line 321 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.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/git-ds/repo.rb', line 276 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.
265 266 267 268 269 270 271 |
# File 'lib/git-ds/repo.rb', line 265 def exec_in_git_dir(&block) curr = Dir.getwd Dir.chdir top_level result = yield Dir.chdir curr result end |
#include?(path) ⇒ Boolean Also known as: exist?
Return true if path exists in repo (on fs or in-tree)
94 95 96 |
# File 'lib/git-ds/repo.rb', line 94 def include?(path) path_to_object(path) ? true : false end |
#index_new ⇒ Object
Return an empty git index for the repo.
198 199 200 |
# File 'lib/git-ds/repo.rb', line 198 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.
406 407 408 409 410 411 |
# File 'lib/git-ds/repo.rb', line 406 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('master', (path ? [path] : [])) t ? tree_contents( t ) : {} end |
#list_blobs(path = '') ⇒ Object
Return Hash of all Blob child objects at ‘path’.
416 417 418 |
# File 'lib/git-ds/repo.rb', line 416 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’.
423 424 425 |
# File 'lib/git-ds/repo.rb', line 423 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.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/git-ds/repo.rb', line 166 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.
113 114 115 |
# File 'lib/git-ds/repo.rb', line 113 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.
329 330 331 332 |
# File 'lib/git-ds/repo.rb', line 329 def object_data(path) blob = path_to_object(path) (blob && blob.kind_of?(Grit::Blob)) ? blob.data : nil 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 ‘master’ will be used.
The object returned will be a Grit::Blob, a Grit::Tree, or nil.
446 447 448 449 450 451 452 |
# File 'lib/git-ds/repo.rb', line 446 def path_to_object(path) treeish = (@staging_index ? staging.sha : 'master') 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?) nil end |
#path_to_sha(path, head = @current_branch) ⇒ Object
Return the SHA1 of ‘path’ in repo. Uses staging index if present.
366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/git-ds/repo.rb', line 366 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.
430 431 432 433 434 435 436 |
# File 'lib/git-ds/repo.rb', line 430 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.
384 385 386 387 388 389 390 391 |
# File 'lib/git-ds/repo.rb', line 384 def root_sha(head=@current_branch) if staging? @staging_index.sync return @staging_index.sha end (self.commits.count > 0) ? self.commits.first.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.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/git-ds/repo.rb', line 143 def set_branch( tag, actor=nil ) # allow creating of new branches opt = (is_head? tag) ? '' : '-b' # Save staging index for current branch @saved_stages[@current_branch] = self.staging if self.staging? exec_git_cmd( "git checkout -q -m #{opt} '#{tag}'", actor ) # Synchronize staging index (required before merge) unstage self.staging.sync # Update current_branch info and restore staging for branch self.staging = @saved_stages[tag] @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.
244 245 246 247 248 249 |
# File 'lib/git-ds/repo.rb', line 244 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.
256 257 258 259 |
# File 'lib/git-ds/repo.rb', line 256 def stage_and_commit(msg, actor=nil, &block) stage(&block) self.staging.commit(msg, actor) end |
#staging ⇒ Object Also known as: index
Return the staging index for the repo.
205 206 207 208 |
# File 'lib/git-ds/repo.rb', line 205 def staging # TODO: mutex @staging_index ||= StageIndex.new(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.
214 215 216 217 |
# File 'lib/git-ds/repo.rb', line 214 def staging=(idx) # TODO: mutex @staging_index = idx end |
#staging? ⇒ Boolean
Return true if a staging index is active.
230 231 232 |
# File 'lib/git-ds/repo.rb', line 230 def staging? @staging_index != nil end |
#tag_object(tag, sha) ⇒ Object
Tag (name) an object, e.g. a commit.
189 190 191 |
# File 'lib/git-ds/repo.rb', line 189 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).
87 88 89 |
# File 'lib/git-ds/repo.rb', line 87 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 'master')
+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)
347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/git-ds/repo.rb', line 347 def tree(treeish=nil, paths = []) begin if staging? && (not treeish) @staging_index.sync super(@staging_index.current_tree.id, paths) else treeish = 'master' 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).
397 398 399 400 |
# File 'lib/git-ds/repo.rb', line 397 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.
223 224 225 |
# File 'lib/git-ds/repo.rb', line 223 def unstage self.staging=(nil) end |