Class: RightGit::Git::Repository
- Inherits:
-
Object
- Object
- RightGit::Git::Repository
- Defined in:
- lib/right_git/git/repository.rb
Overview
Provides an API for managing a git repository that is suitable for automation. It is assumed that gestures like creating a new repository, branch or tag are manual tasks beyond the scope of automation so those are not covered here. What is provided are APIs for cloning, fetching, listing and grooming git-related objects.
Constant Summary collapse
- COMMIT_SHA1_REGEX =
/^commit ([0-9a-fA-F]{40})$/- SUBMODULE_STATUS_REGEX =
/^([+\- ])([0-9a-fA-F]{40}) (.*) (.*)$/
Instance Attribute Summary collapse
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#repo_dir ⇒ Object
readonly
Returns the value of attribute repo_dir.
-
#shell ⇒ Object
readonly
Returns the value of attribute shell.
Class Method Summary collapse
-
.clone_to(repo_url, destination, options = {}) ⇒ Repository
Factory method to clone the repo given by URL to the given destination and return a new Repository object.
Instance Method Summary collapse
-
#branch_for(branch_name) ⇒ Branch
Factory method for a branch object referencing this repository.
-
#branches(options = {}) ⇒ Array
Generates a list of known (checked-out) branches from the current git directory.
-
#checkout_to(revision, options = {}) ⇒ TrueClass
Checkout.
-
#clean(*args) ⇒ TrueClass
Cleans the current repository of untracked files.
-
#clean_all(options = {}) ⇒ TrueClass
Cleans everything and optionally cleans .gitignored files.
-
#fetch(*args) ⇒ TrueClass
Fetches using the given options, if any.
-
#fetch_all(options = {}) ⇒ TrueClass
Fetches branch and tag information from remote origin.
-
#git_output(*args) ⇒ String
Executes and returns the output for a git command.
-
#hard_reset_to(revision) ⇒ TrueClass
Performs a hard reset to the given revision, if given, or else the last checked-out SHA.
-
#initialize(repo_dir, options = {}) ⇒ Repository
constructor
A new instance of Repository.
-
#log(revision, options = {}) ⇒ Array
Generates a list of commits using the given ‘git log’ arguments.
-
#sha_for(revision) ⇒ String
Determines the SHA referenced by the given revision.
-
#spit_output(*args) ⇒ TrueClass
Prints the output for a git command.
-
#submodule_paths(options = {}) ⇒ Array
Queries the recursive list of submodule paths for the current workspace.
-
#tag_for(tag_name) ⇒ Branch
Factory method for a tag object referencing this repository.
-
#tags ⇒ Array
Generates a list of known (fetched) tags from the current git directory.
-
#update_submodules(options = {}) ⇒ TrueClass
Updates submodules for the current workspace.
-
#vet_output(*args) ⇒ TrueClass
msysgit on Windows exits zero even when checkout|reset|fetch fails so we need to scan the output for error or fatal messages.
Constructor Details
#initialize(repo_dir, options = {}) ⇒ Repository
Returns a new instance of Repository.
44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/right_git/git/repository.rb', line 44 def initialize(repo_dir, = {}) = { :shell => nil, :logger => nil }.merge() if repo_dir && ::File.directory?(repo_dir) @repo_dir = ::File.(repo_dir) else raise ::ArgumentError.new('A valid repo_dir is required') end @shell = [:shell] || ::RightGit::Shell::Default @logger = [:logger] || ::RightGit::Shell::Default.default_logger end |
Instance Attribute Details
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
38 39 40 |
# File 'lib/right_git/git/repository.rb', line 38 def logger @logger end |
#repo_dir ⇒ Object (readonly)
Returns the value of attribute repo_dir.
38 39 40 |
# File 'lib/right_git/git/repository.rb', line 38 def repo_dir @repo_dir end |
#shell ⇒ Object (readonly)
Returns the value of attribute shell.
38 39 40 |
# File 'lib/right_git/git/repository.rb', line 38 def shell @shell end |
Class Method Details
.clone_to(repo_url, destination, options = {}) ⇒ Repository
Factory method to clone the repo given by URL to the given destination and return a new Repository object.
Note that cloning to the default working directory-relative location is not currently supported.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/right_git/git/repository.rb', line 69 def self.clone_to(repo_url, destination, = {}) destination = ::File.(destination) git_args = ['clone', '--', repo_url, destination] expected_git_dir = ::File.join(destination, '.git') if ::File.directory?(expected_git_dir) raise ::ArgumentError, "Destination is already a git repository: #{destination.inspect}" end repo = self.new('.', ) repo.vet_output(git_args) if ::File.directory?(expected_git_dir) repo.instance_variable_set(:@repo_dir, destination) else raise GitError, "Failed to clone #{repo_url.inspect} to #{destination.inspect}" end repo end |
Instance Method Details
#branch_for(branch_name) ⇒ Branch
Factory method for a branch object referencing this repository.
118 119 120 |
# File 'lib/right_git/git/repository.rb', line 118 def branch_for(branch_name) Branch.new(self, branch_name) end |
#branches(options = {}) ⇒ Array
Generates a list of known (checked-out) branches from the current git directory.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/right_git/git/repository.rb', line 129 def branches( = {}) = { :all => true }.merge() git_args = ['branch'] git_args << '-a' if [:all] # note older versions of git don't accept --all branches = BranchCollection.new(self) git_output(git_args).lines.each do |line| # ignore the no-branch branch that git helpfully provides when current # HEAD is a tag or otherwise not-a-branch. unless line.strip == '* (no branch)' branch = Branch.new(self, line) branches << branch if branch end end branches end |
#checkout_to(revision, options = {}) ⇒ TrueClass
Checkout.
232 233 234 235 236 237 238 239 240 |
# File 'lib/right_git/git/repository.rb', line 232 def checkout_to(revision, = {}) = { :force => false }.merge() git_args = ['checkout', revision] git_args << '--force' if [:force] vet_output(git_args) true end |
#clean(*args) ⇒ TrueClass
Cleans the current repository of untracked files.
197 198 199 200 201 |
# File 'lib/right_git/git/repository.rb', line 197 def clean(*args) git_args = ['clean', args] spit_output(git_args) true end |
#clean_all(options = {}) ⇒ TrueClass
Cleans everything and optionally cleans .gitignored files.
211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/right_git/git/repository.rb', line 211 def clean_all( = {}) = { :directories => false, :gitignored => false, :submodules => false, }.merge() git_args = ['-f'] # force is required or else -n only lists files. git_args << '-f' if [:submodules] # double-tap -f to kill untracked submodules git_args << '-d' if [:directories] git_args << '-x' if [:gitignored] clean(git_args) true end |
#fetch(*args) ⇒ TrueClass
Fetches using the given options, if any.
93 94 95 96 |
# File 'lib/right_git/git/repository.rb', line 93 def fetch(*args) vet_output(['fetch', args]) true end |
#fetch_all(options = {}) ⇒ TrueClass
Fetches branch and tag information from remote origin.
104 105 106 107 108 109 110 111 |
# File 'lib/right_git/git/repository.rb', line 104 def fetch_all( = {}) = { :prune => false }.merge() git_args = ['--all'] git_args << '--prune' if [:prune] fetch(git_args) fetch('--tags') # need a separate call for tags or else you don't get all the tags true end |
#git_output(*args) ⇒ String
Executes and returns the output for a git command. Raises on failure.
322 323 324 |
# File 'lib/right_git/git/repository.rb', line 322 def git_output(*args) inner_execute(:output_for, args) end |
#hard_reset_to(revision) ⇒ TrueClass
Performs a hard reset to the given revision, if given, or else the last checked-out SHA.
248 249 250 251 252 253 |
# File 'lib/right_git/git/repository.rb', line 248 def hard_reset_to(revision) git_args = ['reset', '--hard'] git_args << revision if revision vet_output(git_args) true end |
#log(revision, options = {}) ⇒ Array
Generates a list of commits using the given ‘git log’ arguments.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/right_git/git/repository.rb', line 173 def log(revision, = {}) = { :skip => nil, :tail => 1_000, :no_merges => false, :full_hashes => false, }.merge() skip = [:skip] git_args = [ 'log', "-n#{options[:tail]}", "--format=\"%#{options[:full_hashes] ? 'H' : 'h'} %at %aE\"" # double-quotes are Windows friendly ] git_args << "--skip #{skip}" if skip git_args << "--no-merges" if [:no_merges] git_args << revision if revision git_output(git_args).lines.map { |line| Commit.new(self, line) } end |
#sha_for(revision) ⇒ String
Determines the SHA referenced by the given revision. Raises on failure.
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/right_git/git/repository.rb', line 299 def sha_for(revision) # note that 'git show-ref' produces easier-to-parse output but it matches # both local and remote branch to a simple branch name whereas 'git show' # matches at-most-one and requires origin/ for remote branches. git_args = ['show', revision].compact result = nil git_output(git_args).lines.each do |line| if matched = COMMIT_SHA1_REGEX.match(line.strip) result = matched[1] break end end unless result raise GitError, 'Unable to locate commit in show output.' end result end |
#spit_output(*args) ⇒ TrueClass
Prints the output for a git command. Raises on failure.
331 332 333 |
# File 'lib/right_git/git/repository.rb', line 331 def spit_output(*args) inner_execute(:execute, args) end |
#submodule_paths(options = {}) ⇒ Array
Queries the recursive list of submodule paths for the current workspace.
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/right_git/git/repository.rb', line 261 def submodule_paths( = {}) = { :recursive => false }.merge() git_args = ['submodule', 'status'] git_args << '--recursive' if [:recursive] git_output(git_args).lines.map do |line| data = line.chomp if matched = SUBMODULE_STATUS_REGEX.match(data) matched[3] else raise GitError, "Unexpected output from submodule status: #{data.inspect}" end end end |
#tag_for(tag_name) ⇒ Branch
Factory method for a tag object referencing this repository.
152 153 154 |
# File 'lib/right_git/git/repository.rb', line 152 def tag_for(tag_name) Tag.new(self, tag_name) end |
#tags ⇒ Array
Generates a list of known (fetched) tags from the current git directory.
159 160 161 |
# File 'lib/right_git/git/repository.rb', line 159 def git_output('tag').lines.map { |line| Tag.new(self, line.strip) } end |
#update_submodules(options = {}) ⇒ TrueClass
Updates submodules for the current workspace.
284 285 286 287 288 289 290 291 292 |
# File 'lib/right_git/git/repository.rb', line 284 def update_submodules( = {}) = { :recursive => false }.merge() git_args = ['submodule', 'update', '--init'] git_args << '--recursive' if [:recursive] spit_output(git_args) true end |
#vet_output(*args) ⇒ TrueClass
msysgit on Windows exits zero even when checkout|reset|fetch fails so we need to scan the output for error or fatal messages. it does no harm to do the same on Linux even though the exit code works properly there.
342 343 344 345 346 347 348 349 |
# File 'lib/right_git/git/repository.rb', line 342 def vet_output(*args) last_output = git_output(*args).strip logger.info(last_output) unless last_output.empty? if last_output.downcase =~ /^(error|fatal):/ raise GitError, "Git exited zero but an error was detected in output." end true end |