From 197a12943d6bfcc8ce619ff9022a32ea08e41c0d Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Thu, 22 Oct 2015 10:56:57 -0700 Subject: [PATCH 01/18] Adding options all, refspec and refspecs to git fetch --- lib/git/lib.rb | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 777e42ea..7aed984c 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -722,11 +722,30 @@ def tag(name, *opts) command('tag', arr_opts) end - + # + # Fetch from given remote + # + # accepts options: + # :all + # :t or :tags + # :p or :prune + # :refspec + # :refspecs + # + # @param [String|NilClass] remote to fetch from + # @param [{Symbol=>Object}] opts the given options + # def fetch(remote, opts) - arr_opts = [remote] + arr_opts = [] + if remote == :all + arr_opts << '--all' + else + arr_opts << remote + end arr_opts << '--tags' if opts[:t] || opts[:tags] arr_opts << '--prune' if opts[:p] || opts[:prune] + arr_opts << opts[:refspec] if opts[:refspec] + arr_opts << opts[:refspecs].join(' ') if opts[:refspecs] command('fetch', arr_opts) end From 07076dad0f036e4211ec75470feeaeaabd829b44 Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Thu, 22 Oct 2015 11:10:30 -0700 Subject: [PATCH 02/18] Fix symbol/string for options in git describe --- lib/git/lib.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 7aed984c..2b98aa18 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -95,7 +95,7 @@ def clone(repository, name, opts = {}) # :candidates # :long # :always - # :math + # :match # # @param [String|NilClass] committish target commit sha or object name # @param [{Symbol=>Object}] opts the given options @@ -112,12 +112,13 @@ def describe(committish=nil, opts={}) arr_opts << '--always' if opts[:always] arr_opts << '--exact-match' if opts[:exact_match] || opts[:"exact-match"] - arr_opts << '--dirty' if opts['dirty'] == true - arr_opts << "--dirty=#{opts['dirty']}" if opts['dirty'].is_a?(String) + opts[:dirty] = opts['dirty'] if opts['dirty'] + arr_opts << '--dirty' if opts[:dirty] == true + arr_opts << "--dirty=#{opts[:dirty]}" if opts[:dirty].is_a?(String) - arr_opts << "--abbrev=#{opts['abbrev']}" if opts[:abbrev] - arr_opts << "--candidates=#{opts['candidates']}" if opts[:candidates] - arr_opts << "--match=#{opts['match']}" if opts[:match] + arr_opts << "--abbrev=#{opts[:abbrev]}" if opts[:abbrev] + arr_opts << "--candidates=#{opts[:candidates]}" if opts[:candidates] + arr_opts << "--match=#{opts[:match]}" if opts[:match] arr_opts << committish if committish From a3eaab158abe1e64d46f1162c9003f4c2acaa81c Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Wed, 18 Nov 2015 15:18:58 +0100 Subject: [PATCH 03/18] Fix tabs / trailing whitespaces --- lib/git.rb | 16 ++--- lib/git/author.rb | 4 +- lib/git/base.rb | 126 +++++++++++++++++++------------------- lib/git/base/factory.rb | 28 ++++----- lib/git/branch.rb | 46 +++++++------- lib/git/branches.rb | 28 ++++----- lib/git/diff.rb | 6 +- lib/git/index.rb | 2 +- lib/git/lib.rb | 6 +- lib/git/log.rb | 48 +++++++-------- lib/git/object.rb | 130 ++++++++++++++++++++-------------------- lib/git/path.rb | 16 ++--- lib/git/remote.rb | 18 +++--- lib/git/stash.rb | 12 ++-- lib/git/stashes.rb | 20 +++---- lib/git/status.rb | 42 ++++++------- 16 files changed, 274 insertions(+), 274 deletions(-) diff --git a/lib/git.rb b/lib/git.rb index 1992dc1d..27c5712c 100644 --- a/lib/git.rb +++ b/lib/git.rb @@ -34,7 +34,7 @@ # and more. You should be able to do most fundamental git # operations with this library. # -# This module provides the basic functions to open a git +# This module provides the basic functions to open a git # reference to work with. You can open a working directory, # open a bare repository, initialize a new repo or clone an # existing remote repository. @@ -42,7 +42,7 @@ # Author:: Scott Chacon (mailto:schacon@gmail.com) # License:: MIT License module Git - + #g.config('user.name', 'Scott Chacon') # sets value #g.config('user.email', 'email@email.com') # sets value #g.config('user.name') # returns 'Scott Chacon' @@ -82,7 +82,7 @@ def global_config(name = nil, value = nil) def self.bare(git_dir, options = {}) Base.bare(git_dir, options) end - + # clones a remote repository # # options @@ -110,7 +110,7 @@ def self.export(repository, name, options = {}) repo.checkout("origin/#{options[:branch]}") if options[:branch] Dir.chdir(repo.dir.to_s) { FileUtils.rm_r '.git' } end - + # Same as g.config, but forces it to be at the global level # #g.config('user.name', 'Scott Chacon') # sets value @@ -139,8 +139,8 @@ def self.global_config(name = nil, value = nil) def self.init(working_dir = '.', options = {}) Base.init(working_dir, options) end - - # returns a Hash containing information about the references + + # returns a Hash containing information about the references # of the target repository # # @param [String|NilClass] location the target repository location or nil for '.' @@ -150,7 +150,7 @@ def self.ls_remote(location=nil) end # open an existing git working directory - # + # # this will most likely be the most common way to create # a git reference, referring to a working directory. # if not provided in the options, the library will assume @@ -162,5 +162,5 @@ def self.ls_remote(location=nil) def self.open(working_dir, options = {}) Base.open(working_dir, options) end - + end diff --git a/lib/git/author.rb b/lib/git/author.rb index 86d33047..cbd2479d 100644 --- a/lib/git/author.rb +++ b/lib/git/author.rb @@ -1,7 +1,7 @@ module Git class Author attr_accessor :name, :email, :date - + def initialize(author_string) if m = /(.*?) <(.*?)> (\d+) (.*)/.match(author_string) @name = m[1] @@ -9,6 +9,6 @@ def initialize(author_string) @date = Time.at(m[3].to_i) end end - + end end diff --git a/lib/git/base.rb b/lib/git/base.rb index ad3e52ec..966d29fa 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -1,7 +1,7 @@ require 'git/base/factory' module Git - + class Base include Git::Base::Factory @@ -10,7 +10,7 @@ class Base def self.bare(git_dir, opts = {}) self.new({:repository => git_dir}.merge(opts)) end - + # clones a git repository locally # # repository - http://repo.or.cz/w/sinatra.git @@ -20,15 +20,15 @@ def self.bare(git_dir, opts = {}) # :repository # # :bare - # or + # or # :working_directory # :index_file # def self.clone(repository, name, opts = {}) - # run git-clone + # run git-clone self.new(Git::Lib.new.clone(repository, name, opts)) end - + # Returns (and initialize if needed) a Git::Config instance # # @return [Git::Config] the current config instance. @@ -44,17 +44,17 @@ def self.config # :repository # def self.init(working_dir, opts = {}) - opts[:working_directory] ||= working_dir + opts[:working_directory] ||= working_dir opts[:repository] ||= File.join(opts[:working_directory], '.git') - + FileUtils.mkdir_p(opts[:working_directory]) if opts[:working_directory] && !File.directory?(opts[:working_directory]) - + init_opts = { :bare => opts[:bare] } opts.delete(:working_directory) if opts[:bare] - + # Submodules have a .git *file* not a .git folder. # This file's contents point to the location of # where the git refs are held (In the parent repo) @@ -65,16 +65,16 @@ def self.init(working_dir, opts = {}) end Git::Lib.new(opts).init(init_opts) - + self.new(opts) end - + # opens a new Git Project from a working directory # you can specify non-standard git_dir and index file in the options def self.open(working_dir, opts={}) self.new({:working_directory => working_dir}.merge(opts)) end - + def initialize(options = {}) if working_dir = options[:working_directory] options[:repository] ||= File.join(working_dir, '.git') @@ -86,17 +86,17 @@ def initialize(options = {}) else @logger = nil end - + @working_directory = options[:working_directory] ? Git::WorkingDirectory.new(options[:working_directory]) : nil - @repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil + @repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil @index = options[:index] ? Git::Index.new(options[:index], false) : nil end - + # changes current working directory for a block # to the git working directory # # example - # @git.chdir do + # @git.chdir do # # write files # @git.add # @git.commit('message') @@ -106,7 +106,7 @@ def chdir # :yields: the Git::Path yield dir.path end end - + #g.config('user.name', 'Scott Chacon') # sets value #g.config('user.email', 'email@email.com') # sets value #g.config('user.name') # returns 'Scott Chacon' @@ -123,14 +123,14 @@ def config(name = nil, value = nil) lib.config_list end end - + # returns a reference to the working directory # @git.dir.path # @git.dir.writeable? def dir @working_directory end - + # returns reference to the git index file def index @index @@ -141,24 +141,24 @@ def index def repo @repository end - + # returns the repository size in bytes def repo_size Dir.chdir(repo.path) do return `du -s`.chomp.split.first.to_i end end - + def set_index(index_file, check = true) @lib = nil @index = Git::Index.new(index_file.to_s, check) end - + def set_working(work_dir, check = true) @lib = nil @working_directory = Git::WorkingDirectory.new(work_dir.to_s, check) end - + # returns +true+ if the branch exists locally def is_local_branch?(branch) branch_names = self.branches.local.map {|b| b.name} @@ -177,15 +177,15 @@ def is_branch?(branch) branch_names.include?(branch) end - # this is a convenience method for accessing the class that wraps all the + # this is a convenience method for accessing the class that wraps all the # actual 'git' forked system calls. At some point I hope to replace the Git::Lib # class with one that uses native methods or libgit C bindings def lib @lib ||= Git::Lib.new(self, @logger) end - + # will run a grep for 'string' on the HEAD of the git repository - # + # # to be more surgical in your grep, you can call grep() off a specific # git object. for example: # @@ -206,7 +206,7 @@ def lib def grep(string, path_limiter = nil, opts = {}) self.object('HEAD').grep(string, path_limiter, opts) end - + # updates the repository index using the working directory content # # @git.add('path/to/file') @@ -282,7 +282,7 @@ def revert(commitish = nil, opts = {}) end # commits all pending changes in the index file to the git repository - # + # # options: # :all # :allow_empty @@ -292,10 +292,10 @@ def revert(commitish = nil, opts = {}) def commit(message, opts = {}) self.lib.commit(message, opts) end - + # commits all pending changes in the index file to the git repository, # but automatically adds all modified files without having to explicitly - # calling @git.add() on them. + # calling @git.add() on them. def commit_all(message, opts = {}) opts = {:add_all => true}.merge(opts) self.lib.commit(message, opts) @@ -305,7 +305,7 @@ def commit_all(message, opts = {}) def checkout(branch = 'master', opts = {}) self.lib.checkout(branch, opts) end - + # checks out an old version of a file def checkout_file(version, file) self.lib.checkout_file(version,file) @@ -328,7 +328,7 @@ def push(remote = 'origin', branch = 'master', opts = {}) self.lib.push(remote, branch, opts) end - + # merges one or more branches into the current working branch # # you can specify more than one branch to merge by passing an array of branches @@ -348,9 +348,9 @@ def each_conflict(&block) # :yields: file, your_version, their_version # @git.pull('upstream', 'develope') # pulls from upstream/develop # def pull(remote='origin', branch='master') - self.lib.pull(remote, branch) + self.lib.pull(remote, branch) end - + # returns an array of Git:Remote objects def remotes self.lib.remotes.map { |r| Git::Remote.new(self, r) } @@ -358,7 +358,7 @@ def remotes # adds a new remote to this repository # url can be a git url or a Git::Base object if it's a local reference - # + # # @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git') # @git.fetch('scotts_git') # @git.merge('scotts_git/master') @@ -396,37 +396,37 @@ def tags # :f -> true # :m | :message -> String # :s -> true - # + # def add_tag(name, *opts) self.lib.tag(name, *opts) self.tag(name) end - - # deletes a tag - def delete_tag(name) + + # deletes a tag + def delete_tag(name) self.lib.tag(name, {:d => true}) end - + # creates an archive file of the given tree-ish def archive(treeish, file = nil, opts = {}) self.object(treeish).archive(file, opts) end - + # repacks the repository def repack self.lib.repack end - + def gc self.lib.gc end - + def apply(file) if File.exist?(file) self.lib.apply(file) end end - + def apply_mail(file) self.lib.apply_mail(file) if File.exist?(file) end @@ -439,9 +439,9 @@ def apply_mail(file) def show(objectish=nil, path=nil) self.lib.show(objectish, path) end - + ## LOWER LEVEL INDEX OPERATIONS ## - + def with_index(new_index) # :yields: new_index old_index = @index set_index(new_index, false) @@ -449,10 +449,10 @@ def with_index(new_index) # :yields: new_index set_index(old_index) return_value end - + def with_temp_index &blk # Workaround for JRUBY, since they handle the TempFile path different. - # MUST be improved to be safer and OS independent. + # MUST be improved to be safer and OS independent. if RUBY_PLATFORM == 'java' temp_path = "/tmp/temp-index-#{(0...15).map{ ('a'..'z').to_a[rand(26)] }.join}" else @@ -464,29 +464,29 @@ def with_temp_index &blk with_index(temp_path, &blk) end - + def checkout_index(opts = {}) self.lib.checkout_index(opts) end - + def read_tree(treeish, opts = {}) self.lib.read_tree(treeish, opts) end - + def write_tree self.lib.write_tree end - + def write_and_commit_tree(opts = {}) tree = write_tree commit_tree(tree, opts) end - + def update_ref(branch, commit) branch(branch).update_ref(commit) end - - + + def ls_files(location=nil) self.lib.ls_files(location) end @@ -494,14 +494,14 @@ def ls_files(location=nil) def with_working(work_dir) # :yields: the Git::WorkingDirectory return_value = false old_working = @working_directory - set_working(work_dir) + set_working(work_dir) Dir.chdir work_dir do return_value = yield @working_directory end set_working(old_working) return_value end - + def with_temp_working &blk tempfile = Tempfile.new("temp-workdir") temp_dir = tempfile.path @@ -510,8 +510,8 @@ def with_temp_working &blk Dir.mkdir(temp_dir, 0700) with_working(temp_dir, &blk) end - - + + # runs git rev-parse to convert the objectish to a full sha # # @git.revparse("HEAD^^") @@ -521,11 +521,11 @@ def with_temp_working &blk def revparse(objectish) self.lib.revparse(objectish) end - + def ls_tree(objectish) self.lib.ls_tree(objectish) end - + def cat_file(objectish) self.lib.object_contents(objectish) end @@ -534,7 +534,7 @@ def cat_file(objectish) def current_branch self.lib.branch_current end - + end - + end diff --git a/lib/git/base/factory.rb b/lib/git/base/factory.rb index b97bfab5..bc03d0bf 100644 --- a/lib/git/base/factory.rb +++ b/lib/git/base/factory.rb @@ -3,18 +3,18 @@ module Git class Base module Factory - + # returns a Git::Branch object for branch_name def branch(branch_name = 'master') Git::Branch.new(self, branch_name) end - # returns a Git::Branches object of all the Git::Branch + # returns a Git::Branches object of all the Git::Branch # objects for this repo def branches Git::Branches.new(self) end - + def commit_tree(tree = nil, opts = {}) Git::Object::Commit.new(self, self.lib.commit_tree(tree, opts)) end @@ -23,11 +23,11 @@ def commit_tree(tree = nil, opts = {}) def diff(objectish = 'HEAD', obj2 = nil) Git::Diff.new(self, objectish, obj2) end - + def gblob(objectish) Git::Object.new(self, objectish, 'blob') end - + def gcommit(objectish) Git::Object.new(self, objectish, 'commit') end @@ -35,24 +35,24 @@ def gcommit(objectish) def gtree(objectish) Git::Object.new(self, objectish, 'tree') end - + # returns a Git::Log object with count commits def log(count = 30) Git::Log.new(self, count) end - + # returns a Git::Object of the appropriate type - # you can also call @git.gtree('tree'), but that's + # you can also call @git.gtree('tree'), but that's # just for readability. If you call @git.gtree('HEAD') it will - # still return a Git::Object::Commit object. + # still return a Git::Object::Commit object. # - # @git.object calls a factory method that will run a rev-parse - # on the objectish and determine the type of the object and return - # an appropriate object for that type + # @git.object calls a factory method that will run a rev-parse + # on the objectish and determine the type of the object and return + # an appropriate object for that type def object(objectish) Git::Object.new(self, objectish) end - + # returns a Git::Remote object def remote(remote_name = 'origin') Git::Remote.new(self, remote_name) @@ -62,7 +62,7 @@ def remote(remote_name = 'origin') def status Git::Status.new(self) end - + # returns a Git::Tag object def tag(tag_name) Git::Object.new(self, tag_name, 'tag', true) diff --git a/lib/git/branch.rb b/lib/git/branch.rb index 4f69e0cd..8ce1bc15 100644 --- a/lib/git/branch.rb +++ b/lib/git/branch.rb @@ -3,9 +3,9 @@ module Git class Branch < Path - + attr_accessor :full, :remote, :name - + def initialize(base, name) @full = name @base = base @@ -13,25 +13,25 @@ def initialize(base, name) @stashes = nil @remote, @name = parse_name(name) end - + def gcommit @gcommit ||= @base.gcommit(@full) @gcommit end - + def stashes @stashes ||= Git::Stashes.new(@base) end - + def checkout check_if_create @base.checkout(@full) end - + def archive(file, opts = {}) @base.lib.archive(@full, file, opts) end - + # g.branch('new_branch').in_branch do # # create new file # # do other stuff @@ -47,22 +47,22 @@ def in_branch (message = 'in branch work') end @base.checkout(old_current) end - + def create check_if_create end - + def delete @base.lib.branch_delete(@name) end - + def current determine_current end - + def merge(branch = nil, message = nil) if branch - in_branch do + in_branch do @base.merge(branch, message) false end @@ -72,29 +72,29 @@ def merge(branch = nil, message = nil) @base.merge(@name) end end - + def update_ref(commit) @base.lib.update_ref(@full, commit) end - + def to_a [@full] end - + def to_s @full end - - private + + private def check_if_create @base.lib.branch_new(@name) rescue nil end - + def determine_current @base.lib.branch_current == @name end - + # Given a full branch name return an Array containing the remote and branch names. # # Removes 'remotes' from the beggining of the name (if present). @@ -105,10 +105,10 @@ def determine_current # parse_name('master') #=> [nil, 'master'] # parse_name('origin/master') #=> ['origin', 'master'] # parse_name('remotes/origin/master') #=> ['origin', 'master'] - # parse_name('origin/master/v2') #=> ['origin', 'master/v2'] + # parse_name('origin/master/v2') #=> ['origin', 'master/v2'] # # param [String] name branch full name. - # return [] an Array containing the remote and branch names. + # return [] an Array containing the remote and branch names. def parse_name(name) if name.match(/^(?:remotes)?\/([^\/]+)\/(.+)/) return [Git::Remote.new(@base, $1), $2] @@ -116,7 +116,7 @@ def parse_name(name) return [nil, name] end - + end - + end diff --git a/lib/git/branches.rb b/lib/git/branches.rb index fc871db8..1995bc48 100644 --- a/lib/git/branches.rb +++ b/lib/git/branches.rb @@ -1,15 +1,15 @@ module Git - + # object that holds all the available branches class Branches include Enumerable - + def initialize(base) @branches = {} - + @base = base - + @base.lib.branches_all.each do |b| @branches[b[0]] = Git::Branch.new(@base, b[0]) end @@ -18,21 +18,21 @@ def initialize(base) def local self.select { |b| !b.remote } end - + def remote self.select { |b| b.remote } end - + # array like methods def size @branches.size - end - + end + def each(&block) @branches.values.each(&block) end - + # Returns the target branch # # Example: @@ -50,14 +50,14 @@ def [](branch_name) @branches.values.inject(@branches) do |branches, branch| branches[branch.full] ||= branch - # This is how Git (version 1.7.9.5) works. - # Lets you ignore the 'remotes' if its at the beginning of the branch full name (even if is not a real remote branch). + # This is how Git (version 1.7.9.5) works. + # Lets you ignore the 'remotes' if its at the beginning of the branch full name (even if is not a real remote branch). branches[branch.full.sub('remotes/', '')] ||= branch if branch.full =~ /^remotes\/.+/ - + branches end[branch_name.to_s] end - + def to_s out = '' @branches.each do |k, b| @@ -65,7 +65,7 @@ def to_s end out end - + end end diff --git a/lib/git/diff.rb b/lib/git/diff.rb index 19da0e92..52abe3d6 100644 --- a/lib/git/diff.rb +++ b/lib/git/diff.rb @@ -128,9 +128,9 @@ def process_full_diff final = {} current_file = nil full_diff_utf8_encoded = @full_diff.encode("UTF-8", "binary", { - :invalid => :replace, - :undef => :replace - }) + :invalid => :replace, + :undef => :replace + }) full_diff_utf8_encoded.split("\n").each do |line| if m = /^diff --git a\/(.*?) b\/(.*?)/.match(line) current_file = m[1] diff --git a/lib/git/index.rb b/lib/git/index.rb index c27820dc..9cd9c323 100644 --- a/lib/git/index.rb +++ b/lib/git/index.rb @@ -1,5 +1,5 @@ module Git class Index < Git::Path - + end end diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 2b98aa18..dd64e20d 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -880,9 +880,9 @@ def meets_required_version? def command_lines(cmd, opts = [], chdir = true, redirect = '') cmd_op = command(cmd, opts, chdir) op = cmd_op.encode("UTF-8", "binary", { - :invalid => :replace, - :undef => :replace - }) + :invalid => :replace, + :undef => :replace + }) op.split("\n") end diff --git a/lib/git/log.rb b/lib/git/log.rb index 160d2a00..38fc9d1a 100644 --- a/lib/git/log.rb +++ b/lib/git/log.rb @@ -1,14 +1,14 @@ module Git - + # object that holds the last X commits on given branch class Log include Enumerable - + def initialize(base, count = 30) dirty_log @base = base @count = count - + @commits = nil @author = nil @grep = nil @@ -31,60 +31,60 @@ def author(regex) @author = regex return self end - + def grep(regex) dirty_log @grep = regex return self end - + def path(path) dirty_log @path = path return self end - + def skip(num) dirty_log @skip = num return self end - + def since(date) dirty_log @since = date return self end - + def until(date) dirty_log @until = date return self end - + def between(sha1, sha2 = nil) dirty_log @between = [sha1, sha2] return self end - + def to_s self.map { |c| c.to_s }.join("\n") end - + # forces git log to run - + def size check_log @commits.size rescue nil end - + def each(&block) check_log @commits.each(&block) end - + def first check_log @commits.first rescue nil @@ -100,29 +100,29 @@ def [](index) @commits[index] rescue nil end - - private - + + private + def dirty_log @dirty_flag = true end - + def check_log if @dirty_flag run_log @dirty_flag = false end end - + # actually run the 'git log' command - def run_log - log = @base.lib.full_log_commits(:count => @count, :object => @object, - :path_limiter => @path, :since => @since, + def run_log + log = @base.lib.full_log_commits(:count => @count, :object => @object, + :path_limiter => @path, :since => @since, :author => @author, :grep => @grep, :skip => @skip, :until => @until, :between => @between) @commits = log.map { |c| Git::Object::Commit.new(@base, c['sha'], c) } end - + end - + end diff --git a/lib/git/object.rb b/lib/git/object.rb index 30258e92..10f8bb03 100644 --- a/lib/git/object.rb +++ b/lib/git/object.rb @@ -1,16 +1,16 @@ module Git - - class GitTagNameDoesNotExist< StandardError + + class GitTagNameDoesNotExist< StandardError end - + # represents a git object class Object - + class AbstractObject attr_accessor :objectish, :type, :mode attr_writer :size - + def initialize(base, objectish) @base = base @objectish = objectish.to_s @@ -23,11 +23,11 @@ def initialize(base, objectish) def sha @sha ||= @base.lib.revparse(@objectish) end - + def size @size ||= @base.lib.object_size(@objectish) end - + # Get the object's contents. # If no block is given, the contents are cached in memory and returned as a string. # If a block is given, it yields an IO object (via IO::popen) which could be used to @@ -41,108 +41,108 @@ def contents(&block) @contents ||= @base.lib.object_contents(@objectish) end end - + def contents_array self.contents.split("\n") end - + def to_s @objectish end - + def grep(string, path_limiter = nil, opts = {}) opts = {:object => sha, :path_limiter => path_limiter}.merge(opts) @base.lib.grep(string, opts) end - + def diff(objectish) Git::Diff.new(@base, @objectish, objectish) end - + def log(count = 30) Git::Log.new(@base, count).object(@objectish) end - + # creates an archive of this object (tree) def archive(file = nil, opts = {}) @base.lib.archive(@objectish, file, opts) end - + def tree?; false; end - + def blob?; false; end - + def commit?; false; end def tag?; false; end - + end - - + + class Blob < AbstractObject - + def initialize(base, sha, mode = nil) super(base, sha) @mode = mode end - + def blob? true end end - + class Tree < AbstractObject - + def initialize(base, sha, mode = nil) super(base, sha) @mode = mode @trees = nil @blobs = nil end - + def children blobs.merge(subtrees) end - + def blobs @blobs ||= check_tree[:blobs] end alias_method :files, :blobs - + def trees @trees ||= check_tree[:trees] end alias_method :subtrees, :trees alias_method :subdirectories, :trees - + def full_tree @base.lib.full_tree(@objectish) end - + def depth @base.lib.tree_depth(@objectish) end - + def tree? true end - + private # actually run the git command def check_tree @trees = {} @blobs = {} - + data = @base.lib.ls_tree(@objectish) - data['tree'].each do |key, tree| - @trees[key] = Git::Object::Tree.new(@base, tree[:sha], tree[:mode]) + data['tree'].each do |key, tree| + @trees[key] = Git::Object::Tree.new(@base, tree[:sha], tree[:mode]) end - - data['blob'].each do |key, blob| - @blobs[key] = Git::Object::Blob.new(@base, blob[:sha], blob[:mode]) + + data['blob'].each do |key, blob| + @blobs[key] = Git::Object::Blob.new(@base, blob[:sha], blob[:mode]) end { @@ -150,11 +150,11 @@ def check_tree :blobs => @blobs } end - + end - + class Commit < AbstractObject - + def initialize(base, sha, init = nil) super(base, sha) @tree = nil @@ -166,48 +166,48 @@ def initialize(base, sha, init = nil) set_commit(init) end end - + def message check_commit @message end - + def name @base.lib.namerev(sha) end - + def gtree check_commit Tree.new(@base, @tree) end - + def parent parents.first end - + # array of all parent commits def parents check_commit - @parents + @parents end - + # git author - def author + def author check_commit @author end - + def author_date author.date end - + # git author def committer check_commit @committer end - - def committer_date + + def committer_date committer.date end alias_method :date, :committer_date @@ -215,7 +215,7 @@ def committer_date def diff_parent diff(parent) end - + def set_commit(data) @sha ||= data['sha'] @committer = Git::Author.new(data['committer']) @@ -224,26 +224,26 @@ def set_commit(data) @parents = data['parent'].map{ |sha| Git::Object::Commit.new(@base, sha) } @message = data['message'].chomp end - + def commit? true end private - + # see if this object has been initialized and do so if not def check_commit return if @tree - + data = @base.lib.commit_data(@objectish) set_commit(data) end - + end - + class Tag < AbstractObject attr_accessor :name - + def initialize(base, sha, name) super(base, sha) @name = name @@ -259,7 +259,7 @@ def message check_tag() return @message end - + def tag? true end @@ -274,7 +274,7 @@ def tagger def check_tag return if @loaded - if !self.annotated? + if !self.annotated? @message = @tagger = nil else tdata = @base.lib.tag_data(@name) @@ -284,9 +284,9 @@ def check_tag @loaded = true end - + end - + # if we're calling this, we don't know what type it is yet # so this is our little factory method def self.new(base, objectish, type = nil, is_tag = false) @@ -297,16 +297,16 @@ def self.new(base, objectish, type = nil, is_tag = false) end return Git::Object::Tag.new(base, sha, objectish) end - + type ||= base.lib.object_type(objectish) klass = case type - when /blob/ then Blob + when /blob/ then Blob when /commit/ then Commit when /tree/ then Tree end klass.new(base, objectish) end - + end end diff --git a/lib/git/path.rb b/lib/git/path.rb index 4b20d9a7..effe495b 100644 --- a/lib/git/path.rb +++ b/lib/git/path.rb @@ -1,19 +1,19 @@ module Git - + class Path - + attr_accessor :path - + def initialize(path, check_path=true) path = File.expand_path(path) - + if check_path && !File.exist?(path) raise ArgumentError, 'path does not exist', [path] end - + @path = path end - + def readable? File.readable?(@path) end @@ -21,11 +21,11 @@ def readable? def writable? File.writable?(@path) end - + def to_s @path end - + end end diff --git a/lib/git/remote.rb b/lib/git/remote.rb index 73556a7c..ded0b3b3 100644 --- a/lib/git/remote.rb +++ b/lib/git/remote.rb @@ -1,8 +1,8 @@ module Git class Remote < Path - + attr_accessor :name, :url, :fetch_opts - + def initialize(base, name) @base = base config = @base.lib.config_remote(name) @@ -10,27 +10,27 @@ def initialize(base, name) @url = config['url'] @fetch_opts = config['fetch'] end - + def fetch(opts={}) @base.fetch(@name, opts) end - + # merge this remote locally def merge(branch = 'master') @base.merge("#{@name}/#{branch}") end - + def branch(branch = 'master') Git::Branch.new(@base, "#{@name}/#{branch}") end - + def remove - @base.lib.remote_remove(@name) + @base.lib.remote_remove(@name) end - + def to_s @name end - + end end diff --git a/lib/git/stash.rb b/lib/git/stash.rb index 97de906c..dc6f86d1 100644 --- a/lib/git/stash.rb +++ b/lib/git/stash.rb @@ -1,27 +1,27 @@ module Git class Stash - + def initialize(base, message, existing=false) @base = base @message = message save unless existing end - + def save @saved = @base.lib.stash_save(@message) end - + def saved? @saved end - + def message @message end - + def to_s message end - + end end \ No newline at end of file diff --git a/lib/git/stashes.rb b/lib/git/stashes.rb index 8bb71af5..372e16b2 100644 --- a/lib/git/stashes.rb +++ b/lib/git/stashes.rb @@ -1,28 +1,28 @@ module Git - + # object that holds all the available stashes class Stashes include Enumerable - + def initialize(base) @stashes = [] - + @base = base - + @base.lib.stashes_all.each do |id, message| @stashes.unshift(Git::Stash.new(@base, message, true)) end end - + def save(message) s = Git::Stash.new(@base, message) @stashes.unshift(s) if s.saved? end - + def apply(index=nil) @base.lib.stash_apply(index) end - + def clear @base.lib.stash_clear @stashes = [] @@ -31,14 +31,14 @@ def clear def size @stashes.size end - + def each(&block) @stashes.each(&block) end - + def [](index) @stashes[index.to_i] end - + end end diff --git a/lib/git/status.rb b/lib/git/status.rb index d59bc777..65e35bbe 100644 --- a/lib/git/status.rb +++ b/lib/git/status.rb @@ -1,17 +1,17 @@ module Git - + class Status include Enumerable - + def initialize(base) @base = base construct_status end - + def changed @files.select { |k, f| f.type == 'M' } end - + def added @files.select { |k, f| f.type == 'A' } end @@ -19,11 +19,11 @@ def added def deleted @files.select { |k, f| f.type == 'D' } end - + def untracked @files.select { |k, f| f.untracked } end - + def pretty out = '' self.each do |file| @@ -43,17 +43,17 @@ def pretty_file(file) \tuntrac #{file.untracked.to_s} FILE end - + # enumerable method - + def [](file) @files[file] end - + def each(&block) @files.values.each(&block) end - + class StatusFile attr_accessor :path, :type, :stage, :untracked attr_accessor :mode_index, :mode_repo @@ -70,7 +70,7 @@ def initialize(base, hash) @sha_repo = hash[:sha_repo] @untracked = hash[:untracked] end - + def blob(type = :index) if type == :repo @base.object(@sha_repo) @@ -78,16 +78,16 @@ def blob(type = :index) @base.object(@sha_index) rescue @base.object(@sha_repo) end end - - + + end - + private - + def construct_status @files = @base.lib.ls_files ignore = @base.lib.ignored_files - + # find untracked in working dir Dir.chdir(@base.dir.path) do Dir.glob('**/*', File::FNM_DOTMATCH) do |file| @@ -96,22 +96,22 @@ def construct_status @files[file] = {:path => file, :untracked => true} end end - + # find modified in tree @base.lib.diff_files.each do |path, data| @files[path] ? @files[path].merge!(data) : @files[path] = data end - + # find added but not committed - new files @base.lib.diff_index('HEAD').each do |path, data| @files[path] ? @files[path].merge!(data) : @files[path] = data end - + @files.each do |k, file_hash| @files[k] = StatusFile.new(@base, file_hash) end end - + end - + end From 405faf006a88071b7d4941097801505c11eded3c Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Mon, 27 Jun 2016 14:18:24 +0200 Subject: [PATCH 04/18] Add 'git clone --mirror' equivalent --- lib/git/base.rb | 5 ++--- lib/git/lib.rb | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/git/base.rb b/lib/git/base.rb index 966d29fa..aadecb31 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -17,9 +17,8 @@ def self.bare(git_dir, opts = {}) # name - sinatra # # options: - # :repository - # - # :bare + # :repository + # :bare or :mirror # or # :working_directory # :index_file diff --git a/lib/git/lib.rb b/lib/git/lib.rb index dd64e20d..ef9901ec 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -42,11 +42,12 @@ def init(opts={}) # tries to clone the given repo # - # returns {:repository} (if bare) + # returns {:repository} (if bare or mirror) # {:working_directory} otherwise # # accepts options: # :bare:: no working directory + # :mirror:: similar, but maps all refs, not only branches # :branch:: name of branch to track (rather than 'master') # :depth:: the number of commits back to pull # :origin:: name of remote (same as remote) @@ -62,6 +63,7 @@ def clone(repository, name, opts = {}) arr_opts = [] arr_opts << '--bare' if opts[:bare] + arr_opts << '--mirror' if opts[:mirror] arr_opts << '--branch' << opts[:branch] if opts[:branch] arr_opts << '--depth' << opts[:depth].to_i if opts[:depth] && opts[:depth].to_i > 0 arr_opts << '--config' << opts[:config] if opts[:config] @@ -75,7 +77,7 @@ def clone(repository, name, opts = {}) command('clone', arr_opts) - opts[:bare] ? {:repository => clone_dir} : {:working_directory => clone_dir} + ( opts[:bare] || opts[:mirror] ) ? {:repository => clone_dir} : {:working_directory => clone_dir} end From a4789d8730d389ed11e8f6e549f4db697ba4b042 Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Wed, 6 Jul 2016 04:43:48 -0700 Subject: [PATCH 05/18] Provide mirror option for remote add --- lib/git/base.rb | 1 + lib/git/lib.rb | 1 + tests/units/test_remotes.rb | 8 ++++++++ 3 files changed, 10 insertions(+) diff --git a/lib/git/base.rb b/lib/git/base.rb index aadecb31..734d9c80 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -365,6 +365,7 @@ def remotes # Options: # :fetch => true # :track => + # :mirror => fetch or push def add_remote(name, url, opts = {}) url = url.repo.path if url.is_a?(Git::Base) self.lib.remote_add(name, url, opts) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index ef9901ec..80b0a318 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -684,6 +684,7 @@ def remote_add(name, url, opts = {}) arr_opts = ['add'] arr_opts << '-f' if opts[:with_fetch] || opts[:fetch] arr_opts << '-t' << opts[:track] if opts[:track] + arr_opts << "--mirror=#{opts[:mirror]}" if opts[:mirror] arr_opts << '--' arr_opts << name arr_opts << url diff --git a/tests/units/test_remotes.rb b/tests/units/test_remotes.rb index 0f73fda3..6cf3da61 100644 --- a/tests/units/test_remotes.rb +++ b/tests/units/test_remotes.rb @@ -26,6 +26,14 @@ def test_add_remote assert(local.branches.map{|b| b.full}.include?('master')) #We actually a new branch ('test_track') on the remote and track that one intead. assert(local.remotes.map{|b| b.name}.include?('testremote3')) + + local.add_remote('testremote4', remote, :mirror => 'fetch') + + assert(local.config('remote.testremote4.fetch') == '+refs/*:refs/*') + + local.add_remote('testremote5', remote, :mirror => 'push') + + assert(local.config('remote.testremote5.mirror') == 'true') end end From 64b192be698e9929e47da6d99db93b4c28bf0eef Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Tue, 20 Sep 2016 14:57:46 -0700 Subject: [PATCH 06/18] Provide log 'up_to' option There was no option to specify a log from a revision other than HEAD since between expects a range. --- lib/git/lib.rb | 1 + lib/git/log.rb | 9 ++++++++- tests/units/test_log.rb | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 80b0a318..a173abfe 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1000,6 +1000,7 @@ def log_common_options(opts) arr_opts << "--grep=#{opts[:grep]}" if opts[:grep].is_a? String arr_opts << "--author=#{opts[:author]}" if opts[:author].is_a? String arr_opts << "#{opts[:between][0].to_s}..#{opts[:between][1].to_s}" if (opts[:between] && opts[:between].size == 2) + arr_opts << "#{opts[:up_to].to_s}" if opts[:up_to] arr_opts end diff --git a/lib/git/log.rb b/lib/git/log.rb index 38fc9d1a..587e5558 100644 --- a/lib/git/log.rb +++ b/lib/git/log.rb @@ -18,6 +18,7 @@ def initialize(base, count = 30) @skip = nil @until = nil @between = nil + @up_to = nil end def object(objectish) @@ -68,6 +69,12 @@ def between(sha1, sha2 = nil) return self end + def up_to(sha) + dirty_log + @up_to = sha + return self + end + def to_s self.map { |c| c.to_s }.join("\n") end @@ -119,7 +126,7 @@ def run_log log = @base.lib.full_log_commits(:count => @count, :object => @object, :path_limiter => @path, :since => @since, :author => @author, :grep => @grep, :skip => @skip, - :until => @until, :between => @between) + :until => @until, :between => @between, :up_to => @up_to) @commits = log.map { |c| Git::Object::Commit.new(@base, c['sha'], c) } end diff --git a/tests/units/test_log.rb b/tests/units/test_log.rb index 96457eb1..b2e44fdb 100644 --- a/tests/units/test_log.rb +++ b/tests/units/test_log.rb @@ -64,6 +64,11 @@ def test_get_log_since_file assert_equal(1, l.size) end + def test_get_log_up_to + l = @git.log.up_to('test') + assert_equal(30, l.size) + end + def test_get_log_path log = @git.log.path('example.txt') assert_equal(30, log.size) From 7df9d79d5b63e527cc20fe357b61ec441581e020 Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Thu, 22 Dec 2016 12:11:58 -0800 Subject: [PATCH 07/18] Provide merge_base --- lib/git/base.rb | 5 +++++ lib/git/lib.rb | 5 +++++ tests/units/test_log.rb | 2 +- tests/units/test_merge.rb | 5 +++-- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/git/base.rb b/lib/git/base.rb index 734d9c80..0bb36f93 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -335,6 +335,11 @@ def merge(branch, message = 'merge') self.lib.merge(branch, message) end + # find the common denominator between two-commits/branches + def merge_base(commits) + self.lib.merge_base(commits) + end + # iterates over the files which are unmerged def each_conflict(&block) # :yields: file, your_version, their_version self.lib.conflicts(&block) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index a173abfe..9417d56a 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -661,6 +661,11 @@ def merge(branch, message = nil) command('merge', arr_opts) end + def merge_base(commits) + arr_opts = commits + command('merge-base', arr_opts) + end + def unmerged unmerged = [] command_lines('diff', ["--cached"]).each do |line| diff --git a/tests/units/test_log.rb b/tests/units/test_log.rb index b2e44fdb..51a738d1 100644 --- a/tests/units/test_log.rb +++ b/tests/units/test_log.rb @@ -9,7 +9,7 @@ def setup @git = Git.open(@wdir) end - def test_get_fisrt_and_last_entries + def test_get_first_and_last_entries log = @git.log assert(log.first.is_a?(Git::Object::Commit)) assert_equal('5e53019b3238362144c2766f02a2c00d91fcc023', log.first.objectish) diff --git a/tests/units/test_merge.rb b/tests/units/test_merge.rb index a0d74c3b..b09af6c8 100644 --- a/tests/units/test_merge.rb +++ b/tests/units/test_merge.rb @@ -72,6 +72,7 @@ def test_branch_and_merge_multiple in_temp_dir do |path| g = Git.clone(@wbare, 'branch_merge_test') Dir.chdir('branch_merge_test') do + init_commit = g.revparse("HEAD") g.branch('new_branch').in_branch('test') do assert_equal('new_branch', g.current_branch) @@ -89,6 +90,8 @@ def test_branch_and_merge_multiple true end + assert(g.merge_base(['new_branch', 'new_branch2']) == init_commit) + assert(!g.status['new_file_1']) # still in master branch assert(!g.status['new_file_3']) # still in master branch @@ -96,9 +99,7 @@ def test_branch_and_merge_multiple assert(g.status['new_file_1']) # file has been merged in assert(g.status['new_file_3']) # file has been merged in - end end end - end \ No newline at end of file From 392b053eecd54cf597ba48a840865770123508df Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Thu, 12 Jan 2017 08:10:09 -0800 Subject: [PATCH 08/18] Prevent error if no entry in ls_remote Otherwise it would fail with: /home/broussel/.rvm/gems/ruby-2.2.1/bundler/gems/ruby-git-7df9d79d5b63/lib/git/lib.rb:417:in `block (2 levels) in ls_remote': undefined method `split' for nil:NilClass (NoMethodError) from /home/broussel/.rvm/gems/ruby-2.2.1/bundler/gems/ruby-git-7df9d79d5b63/lib/git/lib.rb:415:in `each' from /home/broussel/.rvm/gems/ruby-2.2.1/bundler/gems/ruby-git-7df9d79d5b63/lib/git/lib.rb:415:in `block in ls_remote' from /home/broussel/.rvm/gems/ruby-2.2.1/bundler/gems/ruby-git-7df9d79d5b63/lib/git/lib.rb:414:in `tap' from /home/broussel/.rvm/gems/ruby-2.2.1/bundler/gems/ruby-git-7df9d79d5b63/lib/git/lib.rb:414:in `ls_remote' from /home/broussel/.rvm/gems/ruby-2.2.1/bundler/gems/ruby-git-7df9d79d5b63/lib/git.rb:149:in `ls_remote' --- lib/git/lib.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 9417d56a..b7411e42 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -414,6 +414,7 @@ def ls_remote(location=nil) Hash.new{ |h,k| h[k] = {} }.tap do |hsh| command_lines('ls-remote', [location], false).each do |line| (sha, info) = line.split("\t") + next if not info (ref, type, name) = info.split('/', 3) type ||= 'head' type = 'branches' if type == 'heads' From bbda71574411ac3805df66dba1173da35b4c9155 Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Mon, 1 May 2017 16:23:01 -0700 Subject: [PATCH 09/18] Provide git clone --reference option --- lib/git/lib.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index b7411e42..50af263b 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -68,6 +68,7 @@ def clone(repository, name, opts = {}) arr_opts << '--depth' << opts[:depth].to_i if opts[:depth] && opts[:depth].to_i > 0 arr_opts << '--config' << opts[:config] if opts[:config] arr_opts << '--origin' << opts[:remote] || opts[:origin] if opts[:remote] || opts[:origin] + arr_opts << '--reference' << opts[:reference] if opts[:reference] arr_opts << '--recursive' if opts[:recursive] arr_opts << '--' From 22a6343ccd321d7c2002a5a613408313e22c87c0 Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Tue, 12 Dec 2017 06:43:12 -0800 Subject: [PATCH 10/18] Discard stderr Some unexpected errors sometime makes it into the output. For instance, on git describe warning: tag 'v2.10' is really '17.05.0' here v2.10 Instead of having the standard error leaked into the output, just discard it. --- lib/git/lib.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 50af263b..a9f63da2 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1025,9 +1025,12 @@ def log_path_options(opts) end def run_command(git_cmd, &block) - return IO.popen(git_cmd, &block) if block_given? + return IO.popen(git_cmd, :err=>"/dev/null", &block) if block_given? - `#{git_cmd}`.chomp + io = IO.popen(git_cmd, :err=>"/dev/null") + output = io.read.chomp + io.close + output end def escape(s) From dcde6359334f062035bda182b80632077cc2a95d Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Mon, 19 Feb 2018 18:58:39 -0800 Subject: [PATCH 11/18] Prevent redirection from stderr to stdout --- lib/git/lib.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index a9f63da2..a7eadf23 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -942,7 +942,7 @@ def command(cmd, opts = [], chdir = true, redirect = '', &block) global_opts = global_opts.flatten.map {|s| escape(s) }.join(' ') - git_cmd = "#{Git::Base.config.binary_path} #{global_opts} #{cmd} #{opts} #{redirect} 2>&1" + git_cmd = "#{Git::Base.config.binary_path} #{global_opts} #{cmd} #{opts} #{redirect}" output = nil From 844deb4aabe626764300c2cc8a590072577c015d Mon Sep 17 00:00:00 2001 From: Huy Bui Date: Tue, 10 Jul 2018 21:39:20 +0700 Subject: [PATCH 12/18] Fix git-sync does not kill child git process when git-sync timeout Resolves: FARM-1821 Change-Id: I845ed0022973d47b3ae25b8a95349ea644efef5d --- git.gemspec | 1 + lib/git/lib.rb | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/git.gemspec b/git.gemspec index 5e90626e..292dc90c 100644 --- a/git.gemspec +++ b/git.gemspec @@ -16,6 +16,7 @@ Gem::Specification.new do |s| s.add_development_dependency 'rake' s.add_development_dependency 'rdoc' s.add_development_dependency 'test-unit', '>=2', '< 4' + s.add_dependency 'sys-proctable', '~> 1.2', '>= 1.2.1' s.extra_rdoc_files = ['README.md'] s.rdoc_options = ['--charset=UTF-8'] diff --git a/lib/git/lib.rb b/lib/git/lib.rb index a7eadf23..e7089e14 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1,4 +1,6 @@ require 'tempfile' +require 'sys/proctable' +include Sys module Git @@ -1024,10 +1026,31 @@ def log_path_options(opts) arr_opts end + def kill_orphan_process(list_process, parent_pid) + list_process.each do |current_process| + if current_process.ppid == parent_pid + # Kill its child process first + kill_orphan_process(list_process, current_process.pid) + end + end + begin + Process.kill("TERM", parent_pid) + rescue Errno::ESRCH + end + end + def run_command(git_cmd, &block) - return IO.popen(git_cmd, :err=>"/dev/null", &block) if block_given? + return IO.popen(git_cmd, :err => "/dev/null", &block) if block_given? + git_pid = 0 + at_exit do + if git_pid > 0 + process_output = ProcTable.ps + kill_orphan_process(process_output, git_pid) + end + end - io = IO.popen(git_cmd, :err=>"/dev/null") + io = IO.popen(git_cmd, :err => "/dev/null") + git_pid = io.pid output = io.read.chomp io.close output From 36ffa2edd19ad2f50f3d74c95c747a0b30c39029 Mon Sep 17 00:00:00 2001 From: Anh Tran Date: Mon, 27 Aug 2018 17:39:24 +0700 Subject: [PATCH 13/18] Provide git log --all option Resolves: FARM-1860 Change-Id: I43acd1a6582881d1768f66763b1beb0b11b54fa0 --- lib/git/lib.rb | 1 + lib/git/log.rb | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index e7089e14..23aaae58 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -144,6 +144,7 @@ def full_log_commits(opts={}) arr_opts = log_common_options(opts) arr_opts << '--pretty=raw' + arr_opts << '--all' if opts[:all] arr_opts << "--skip=#{opts[:skip]}" if opts[:skip] arr_opts += log_path_options(opts) diff --git a/lib/git/log.rb b/lib/git/log.rb index 587e5558..19eb2154 100644 --- a/lib/git/log.rb +++ b/lib/git/log.rb @@ -19,6 +19,7 @@ def initialize(base, count = 30) @until = nil @between = nil @up_to = nil + @all = nil end def object(objectish) @@ -79,6 +80,11 @@ def to_s self.map { |c| c.to_s }.join("\n") end + def all + dirty_log + @all = true + return self + end # forces git log to run @@ -126,7 +132,7 @@ def run_log log = @base.lib.full_log_commits(:count => @count, :object => @object, :path_limiter => @path, :since => @since, :author => @author, :grep => @grep, :skip => @skip, - :until => @until, :between => @between, :up_to => @up_to) + :until => @until, :between => @between, :up_to => @up_to, :all => @all) @commits = log.map { |c| Git::Object::Commit.new(@base, c['sha'], c) } end From 0e216b9e038880a85d84e556d5d28e6847ee38ce Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Mon, 8 Apr 2019 06:42:37 -0700 Subject: [PATCH 14/18] Do not check for orphans on every git call Resolves: FARM-2721 Change-Id: I624965e250108709394cafb9330bb01e84580e80 --- lib/git/lib.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 23aaae58..dfd3c2aa 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1054,6 +1054,7 @@ def run_command(git_cmd, &block) git_pid = io.pid output = io.read.chomp io.close + git_pid = 0 output end From b7da88bc2e1598825cb4dcc284db0461c55d35ec Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Tue, 8 May 2018 06:51:40 -0700 Subject: [PATCH 15/18] Provide a simple fsck command Resolves: FARM-2794 Change-Id: I63b08a29fe269b2811017dcab1eeec37aa2baed1 --- lib/git/lib.rb | 10 ++++++++++ tests/units/test_lib.rb | 23 ++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index dfd3c2aa..8d5851b7 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -795,6 +795,16 @@ def gc command('gc', ['--prune', '--aggressive', '--auto']) end + def fsck + begin + command('fsck') + rescue + return false + end + + true + end + # reads a tree into the current index file def read_tree(treeish, opts = {}) arr_opts = [] diff --git a/tests/units/test_lib.rb b/tests/units/test_lib.rb index 403a2877..27ec29c9 100644 --- a/tests/units/test_lib.rb +++ b/tests/units/test_lib.rb @@ -227,5 +227,26 @@ def test_show assert(/^commit 935badc874edd62a8629aaf103418092c73f0a56.+\+nothing!$/m.match(@lib.show('gitsearch1'))) assert(/^hello.+nothing!$/m.match(@lib.show('gitsearch1', 'scott/text.txt'))) end - + + def test_fsck + ret = @lib.fsck + assert_equal(ret, true) + + # Corrupted + @wdir_corrupted = File.expand_path(File.join(@test_dir, 'corrupted')) + FileUtils.cp_r(@wdir, @wdir_corrupted) + # Remove first objects dir to corrupt the repo + obj_dir = File.join(@wdir_corrupted, '.git', 'objects') + Dir.foreach(obj_dir) do |filename| + next if filename == '.' + next if filename == '..' + FileUtils.rm_r(File.join(obj_dir, filename)) + break + end + + lib_corrupted = Git.open(@wdir_corrupted).lib + ret = lib_corrupted.fsck + assert_equal(ret, false) + end + end From 8db0498e638fd7cb50c268a56557617def088259 Mon Sep 17 00:00:00 2001 From: vptnhan Date: Wed, 2 Oct 2019 09:00:45 +0700 Subject: [PATCH 16/18] Support ls-remote and symbolic-ref Resolves: FARM-2639 Change-Id: Ic10115f22044e7ac3a1445c96a0f931bc5427996 --- lib/git/base.rb | 8 ++++++++ lib/git/lib.rb | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/git/base.rb b/lib/git/base.rb index 0bb36f93..c499bfbd 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -496,6 +496,14 @@ def ls_files(location=nil) self.lib.ls_files(location) end + def ls_remote(opts=nil) + self.lib.ls_remote_refs(opts) + end + + def symbolic_ref(opts) + self.lib.symbolic_ref(opts) + end + def with_working(work_dir) # :yields: the Git::WorkingDirectory return_value = false old_working = @working_directory diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 8d5851b7..3e22a6e9 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -428,6 +428,16 @@ def ls_remote(location=nil) end end + def ls_remote_refs(opts=nil) + opts ||= ['.'] + command_lines('ls-remote', opts, false) + end + + def symbolic_ref(opts, dir=nil) + @git_dir = dir if dir + command_lines('symbolic-ref', opts, false) + end + def ignored_files command_lines('ls-files', ['--others', '-i', '--exclude-standard']) end From c68b42aabc581cd893e9b883235f6e62dc0a8825 Mon Sep 17 00:00:00 2001 From: Bertrand Roussel Date: Tue, 3 Dec 2019 23:15:31 -0800 Subject: [PATCH 17/18] Fix exception if exitstatus is nil Resolves: FARM-3344 Change-Id: I381db30a5c8d715927f153b19287e7f7d2fc2640 --- lib/git/lib.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 3e22a6e9..a6f5e931 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -986,7 +986,7 @@ def command(cmd, opts = [], chdir = true, redirect = '', &block) @logger.debug(output) end - if exitstatus > 1 || (exitstatus == 1 && output != '') + if (exitstatus == nil) || (exitstatus > 1) || (exitstatus == 1 && output != '') raise Git::GitExecuteError.new(git_cmd + ':' + output.to_s) end From 13aa75998988e12b56bff429dc2b6f68da168420 Mon Sep 17 00:00:00 2001 From: Chien Pham Date: Wed, 25 Aug 2021 16:40:15 +0700 Subject: [PATCH 18/18] Manifest-utils: Highlight the Git Error in RED Resolves: FARM-5365 Change-Id: Iaea71d7f98a979458e93070fb571abadbb68cd2f --- lib/git/lib.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index a6f5e931..ae6427cd 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -987,7 +987,10 @@ def command(cmd, opts = [], chdir = true, redirect = '', &block) end if (exitstatus == nil) || (exitstatus > 1) || (exitstatus == 1 && output != '') - raise Git::GitExecuteError.new(git_cmd + ':' + output.to_s) + puts "========================Git execute error========================".red + gitExecuteError = Git::GitExecuteError.new(git_cmd + ':' + output.to_s) + puts gitExecuteError.to_s.red + raise gitExecuteError end return output