Class: GitCommit
- Inherits:
- 
      Object
      
        - Object
- GitCommit
 
- Defined in:
- lib/commit/git_commit.rb,
 lib/commit/helper.rb,
 lib/commit/options.rb
Overview
Originally written in bash by Mike Slinn 2005-09-05 Converted to Ruby and added MAX_SIZE 2024-12-11 See docs.github.com/en/repositories/working-with-files/managing-large-files/configuring-git-large-file-storage See docs.github.com/en/repositories/working-with-files/managing-large-files/about-large-files-on-github
Constant Summary collapse
- QUIET =
- 0
- NORMAL =
- 1
- VERBOSE =
- 2
- ANNOYING =
- 3
- STFU =
- 4
Instance Method Summary collapse
- 
  
    
      #add_recursively(name)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Needs absolute path or the path relative to the current directory, not just the name of the directory. 
- #commit_push(msg = '-') ⇒ Object
- #discover_branch ⇒ Object
- 
  
    
      #escape(string)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Handles single quotes, spaces and square braces in the given string. 
- #file_add(filename) ⇒ Object
- #git_project? ⇒ Boolean
- #help(msg = nil) ⇒ Object
- 
  
    
      #initialize(default_branch: 'master')  ⇒ GitCommit 
    
    
  
  
  
    constructor
  
  
  
  
  
  
  
    A new instance of GitCommit. 
- 
  
    
      #large_file?(filename)  ⇒ Boolean 
    
    
  
  
  
  
  
  
  
  
  
    Assumes .gitignore is never large. 
- #large_files ⇒ Object
- #main ⇒ Object
- #needs_newline(filename) ⇒ Object
- #parse_options ⇒ Object
- #process_tag ⇒ Object
- 
  
    
      #recursive_add  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Exclude big files, git add all others. 
- #run(command, verbose: true, do_not_execute: false) ⇒ Object
- #scan_directory(path) ⇒ Object
Constructor Details
#initialize(default_branch: 'master') ⇒ GitCommit
Returns a new instance of GitCommit.
| 27 28 29 30 31 32 | # File 'lib/commit/git_commit.rb', line 27 def initialize(default_branch: 'master') @branch = default_branch @commit_size = 0 @gitignore_dirty = false @nh = ActiveSupport::NumberHelper end | 
Instance Method Details
#add_recursively(name) ⇒ Object
Needs absolute path or the path relative to the current directory, not just the name of the directory
| 10 11 12 13 14 15 16 17 18 19 | # File 'lib/commit/helper.rb', line 10 def add_recursively(name) Dir.entries(name).each do |entry| path = "#{name}/#{entry}" if File.directory(entry) scan_directory path else file_add path end end end | 
#commit_push(msg = '-') ⇒ Object
| 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # File 'lib/commit/git_commit.rb', line 34 def commit_push(msg = '-') puts msg.yellow if msg msg = @options[:commit_message] if @options[:commit_message] discover_branch puts "Committing with message '#{msg}'".green unless @options[:verbosity] == QUIET run "git commit -m '#{msg}' 2>&1 | sed -e '/^X11/d' -e '/^Warning:/d'", verbose: @options[:verbosity] >= VERBOSE # @repo.push 'origin', ['refs/heads/master'] # Needs a callback to handle authentication puts "Pushing to origin #{@branch}".green unless @options[:verbosity] == QUIET run "git push origin #{@branch} --tags 3>&1 1>&2 2>&3 | sed -e '/^X11/d' -e '/^Warning:/d'", verbose: @options[:verbosity] >= VERBOSE @change_count = 0 @commit_size = 0 end | 
#discover_branch ⇒ Object
| 49 50 51 52 53 54 55 56 57 | # File 'lib/commit/git_commit.rb', line 49 def discover_branch if @repo.branches.entries.empty? # puts "\nYour git repository is empty. Please add at least one file before committing.".red # exit 4 run "git branch -M #{@branch}" else @branch = @repo.head.name.sub(%r{^refs/heads/}, '') end end | 
#escape(string) ⇒ Object
Handles single quotes, spaces and square braces in the given string
| 22 23 24 25 26 27 | # File 'lib/commit/helper.rb', line 22 def escape(string) string.gsub("'", "\\\\'") .gsub(' ', '\\ ') .gsub('[', '\\[') .gsub(']', '\\]') end | 
#file_add(filename) ⇒ Object
| 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | # File 'lib/commit/helper.rb', line 30 def file_add(filename) file_size = File.exist?(filename) ? File.size(filename) : 0 if large_file?(filename) msg = <<~MESSAGE Not adding '#{filename}' because the git file size limit is #{@nh.to_human MAX_SIZE}, however the file is #{@nh.to_human file_size}. The file will be added to .gitignore. MESSAGE puts msg.yellow unless @options[:verbosity] == QUIET newline = needs_newline('.gitignore') ? "\n" : '' File.write('.gitignore', "#{newline}#{filename}\n", mode: 'a') @gitignore_dirty = true elsif filename == '.gitignore' @gitignore_dirty = true else if @commit_size + file_size >= MAX_SIZE / 2.0 # Defeat formatter commit_push 'A portion of the files to be committed is being pushed now because they are large.' end puts "Adding '#{escape filename}'".green unless @options[:verbosity] == QUIET run ['git', 'add', escape(filename)], verbose: @options[:verbosity] >= VERBOSE end @change_count += 1 @commit_size += file_size end | 
#git_project? ⇒ Boolean
| 59 60 61 | # File 'lib/commit/git_commit.rb', line 59 def git_project? run 'git rev-parse 2> /dev/null', verbose: false end | 
#help(msg = nil) ⇒ Object
| 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # File 'lib/commit/options.rb', line 5 def help(msg = nil) printf "Error: #{msg}\n\n".yellow unless msg.nil? msg = <<~HELP commit v#{Commit::VERSION} Runs git commit without prompting for a message. Files larger than #{@nh.to_human MAX_SIZE} are added to .gitignore instead of being committed. Usage: commit [options] Where options are: -a "tag message" -m "commit message" -v 0 # Minimum verbosity -v 1 # Default verbosity -v 2 # Maximum verbosity Examples: commit # The default commit message is just a single dash (-) commit -v 0 commit -m "This is a commit message" commit -v 0 -m "This is a commit message" commit -a 0.1.2 This gem is further described in https://mslinn.com/git/1050-commit.html HELP puts msg.yellow exit 1 end | 
#large_file?(filename) ⇒ Boolean
Assumes .gitignore is never large
| 58 59 60 | # File 'lib/commit/helper.rb', line 58 def large_file?(filename) File.size(filename) > MAX_SIZE if File.exist?(filename) end | 
#large_files ⇒ Object
| 63 64 65 66 67 68 69 70 71 72 73 74 | # File 'lib/commit/git_commit.rb', line 63 def large_files large = [] @repo.status do |path, flags| puts "#{path} #{flags}" if @options[:verbosity] >= NORMAL if File(path).dir? scan_dir path elsif large_file?(filename) large << path.gsub(' ', '\ ').gsub('[', '\[').gsub(']', '\]') end end large end | 
#main ⇒ Object
| 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | # File 'lib/commit/git_commit.rb', line 76 def main @options = repo_dir = ARGV.empty? ? Dir.pwd : ARGV[0] Dir.chdir(repo_dir) unless ARGV.empty? if git_project? process_tag # Exits if a tag was created @repo = Rugged::Repository.new repo_dir recursive_add commit_push if @commit_size.positive? else puts "Error: '#{repo_dir}' does not contain a git project".red exit 3 end end | 
#needs_newline(filename) ⇒ Object
| 62 63 64 65 66 67 | # File 'lib/commit/helper.rb', line 62 def needs_newline(filename) return false unless File.exist? filename file_contents = File.read filename file_contents.nil? || file_contents.empty? || !file_contents.end_with?("\n") end | 
#parse_options ⇒ Object
| 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | # File 'lib/commit/options.rb', line 34 def = { message: '-', verbosity: 1 } OptionParser.new do |parser| parser.program_name = File.basename __FILE__ @parser = parser parser.on('-a', '--tag TAG_MESSAGE', 'Specify tag message') parser.on('-m', '--message COMMIT_MESSAGE', 'Specify commit message') parser.on('-v', '--verbosity VERBOSITY', Integer, 'Verbosity (0..2)') parser.on_tail('-h', '--help', 'Show this message') do help end end.order!(into: ) help "Invalid verbosity value (#{[:verbosity]})." if [:verbosity].negative? || [:verbosity] > 2 if ARGV.length > 1 help <<~END_MSG Incorrect syntax. After removing the options, the remaining command line was: #{ARGV.join ' '} END_MSG end end | 
#process_tag ⇒ Object
| 91 92 93 94 95 96 97 98 | # File 'lib/commit/git_commit.rb', line 91 def process_tag tag = @options[:tag] return unless tag run "git tag -a #{tag} -m 'v#{tag}'", verbose: @options[:verbosity] >= VERBOSE run 'git push origin --tags', verbose: @options[:verbosity] >= VERBOSE exit end | 
#recursive_add ⇒ Object
Exclude big files, git add all others
| 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | # File 'lib/commit/helper.rb', line 77 def recursive_add @change_count = 0 run ['git', 'add', '--all'], verbose: @options[:verbosity] >= VERBOSE @repo.status do |path, flags| next if flags.include? :ignored if File.directory? path scan_directory path else file_add path end end if @gitignore_dirty puts 'Changing .gitignore'.green unless @options[:verbosity] == QUIET run 'git add .gitignore', verbose: @options[:verbosity] >= 2 @change_count += 1 end return unless @change_count.zero? puts 'No changes were detected to this git repository.'.green if @options[:verbosity] >= VERBOSE exit end | 
#run(command, verbose: true, do_not_execute: false) ⇒ Object
| 101 102 103 104 105 106 107 108 109 | # File 'lib/commit/git_commit.rb', line 101 def run(command, verbose: true, do_not_execute: false) if command.instance_of?(Array) puts command.join(' ') if verbose Kernel.system(*command) unless do_not_execute else puts command if verbose `#{command}`.chomp unless do_not_execute end end | 
#scan_directory(path) ⇒ Object
| 100 101 102 103 104 105 106 107 108 109 | # File 'lib/commit/helper.rb', line 100 def scan_directory(path) Dir.children(path) do |name| child_path = "#{path}/#{name}" if File.directory? child_path scan_directory child_path else file_add child_path end end end |