Skip to content

Instantly share code, notes, and snippets.

@rstacruz
Created June 6, 2012 07:51
Show Gist options
  • Select an option

  • Save rstacruz/2880525 to your computer and use it in GitHub Desktop.

Select an option

Save rstacruz/2880525 to your computer and use it in GitHub Desktop.

Revisions

  1. rstacruz revised this gist Jun 10, 2012. 1 changed file with 152 additions and 0 deletions.
    152 changes: 152 additions & 0 deletions bingit-clog
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,152 @@
    #!/usr/bin/env ruby
    # Usage:
    # git clog # prints
    # git clog -w # writes
    #
    # https://gist.github.com/2880525
    #
    # Put me in a bin path with the filename `git-clog`, thank you.

    module Clog
    extend self

    # Returns the latest tag (assumed to be the current version).
    def version
    v = `git tag | tail -n 1`.strip
    v.empty? ? nil : v
    end

    # Returns the history file of the repo.
    def history_file
    Dir['*HISTORY*'].first || Dir['*CHANGE*'].first
    end

    # Returns a list of git tags.
    def tags
    `git tag`.strip.split("\n")
    end

    # Returns the first parent commit SHA1.
    def tail
    `git rev-list HEAD | tail -n 1`.strip
    end

    # List of possible ranges
    def all_ranges
    arr = Array.new
    ['HEAD', tags.reverse, tail].flatten.each_cons(2) { |to, from| arr << [to, from] }
    arr
    end

    # Returns a list of changesets for the given tags.
    # @return Array of hashes.
    def changesets(range=:all)
    case range
    when :latest
    [ { name: 'HEAD', changes: categories(changes(version, 'HEAD')) } ]
    when :all
    all_ranges.map do |(to, from)|
    { name: to, changes: categories(changes(from, to)) }
    end
    end
    end

    # Returns an array of commit messages.
    def changes(from=version, to=nil)
    log = `git log --pretty="format:%s" #{from||tail}..#{to}`
    log.strip.split("\n").sort
    end

    # From a list of commit messages -> categories
    def categories(list=changes)
    cats = Hash.new { |h, k| h[k] = Array.new }

    list.each { |line|
    case line
    when /^Merge branch/i then nil
    when /^Add(?:ed)? (.*)$/i then cats['Added'] << $1
    when /^Fix(?:ed)? (.*)$/i then cats['Fixed'] << $1
    when /^Change(?:d)? (.*)$/i then cats['Changed'] << $1
    when /^(?:Remove|Delete)(?:d)? (.*)$/i then cats['Removed'] << $1
    when /^\+ (.*)$/i then cats['Added'] << $1
    when /^\! (.*)$/ then cats['Fixed'] << $1
    when /^\- (.*)$/i then cats['Removed'] << $1
    when /^\~ (.*)$/i then cats['Changed'] << $1
    when /^\. (.*)$/i then cats['Misc'] << $1
    else cats['Changed'] << line
    end
    }

    cats
    end

    def log(sets)
    sets.map do |set|
    # Heading name
    h = set[:name]
    h = "Latest version - #{Time.now.strftime('%b %d, %Y')}" if h == 'HEAD'

    h + "\n" + '-'*h.size + "\n\n" +
    set[:changes].map { |category, list|
    "### #{category}:\n" +
    list.map { |item| " * #{item}" }.join("\n")
    }.join("\n\n")
    end.join("\n\n")
    end

    def log_old
    h = "Since #{version || 'the beginning'} - #{Time.now.strftime('%b %d, %Y')}"
    "#{h}\n#{'-'*h.size}\n\n" +
    categories.map { |category, list|
    "### #{category}:\n" +
    list.map { |item| " * #{item}" }.join("\n")
    }.join("\n\n")
    end
    end

    options = {
    :all => (ARGV.delete('-a') || ARGV.delete('--all'))
    }

    if ARGV == ['--help'] || ARGV == ['-h']
    puts "Usage: git clog [-a] [-w]"
    puts
    puts " -a, --all: See the changelog since time immemorial"
    puts " -w, --write: Write to a history file"
    exit
    end

    unless File.directory?('.git')
    puts "Try this command inside a repo's root path."
    exit
    end

    sets = if options[:all]
    Clog.changesets(:all)
    else
    Clog.changesets(:latest)
    end

    if ARGV == []
    puts Clog.log(sets)
    $stderr << "\nUse 'git clog -w' to write.\n"

    elsif ARGV == ['-w'] || ARGV == ['--write']
    # Create the history file
    system 'touch HISTORY.md' if Clog.history_file.nil?

    # Concat
    history = File.open(Clog.history_file) { |f| f.read }
    output = Clog.log(sets)
    output += "\n\n#{'-'*80}\n\n" + history unless history.empty?

    # Write
    File.open(Clog.history_file, 'w') { |f| f.write output }

    if ENV['EDITOR']
    exec "#{ENV['EDITOR']} #{Clog.history_file}"
    else
    puts "Done writing to #{Clog.history_file}."
    end
    end

  2. rstacruz created this gist Jun 6, 2012.
    150 changes: 150 additions & 0 deletions bin/git-clog
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,150 @@
    #!/usr/bin/env ruby
    # Usage:
    # git clog # prints
    # git clog -w # writes
    #
    # https://gist.github.com/2880525

    module Clog
    extend self

    # Returns the latest tag (assumed to be the current version).
    def version
    v = `git tag | tail -n 1`.strip
    v.empty? ? nil : v
    end

    # Returns the history file of the repo.
    def history_file
    Dir['*HISTORY*'].first || Dir['*CHANGE*'].first
    end

    # Returns a list of git tags.
    def tags
    `git tag`.strip.split("\n")
    end

    # Returns the first parent commit SHA1.
    def tail
    `git rev-list HEAD | tail -n 1`.strip
    end

    # List of possible ranges
    def all_ranges
    arr = Array.new
    ['HEAD', tags.reverse, tail].flatten.each_cons(2) { |to, from| arr << [to, from] }
    arr
    end

    # Returns a list of changesets for the given tags.
    # @return Array of hashes.
    def changesets(range=:all)
    case range
    when :latest
    [ { name: 'HEAD', changes: categories(changes(version, 'HEAD')) } ]
    when :all
    all_ranges.map do |(to, from)|
    { name: to, changes: categories(changes(from, to)) }
    end
    end
    end

    # Returns an array of commit messages.
    def changes(from=version, to=nil)
    log = `git log --pretty="format:%s" #{from||tail}..#{to}`
    log.strip.split("\n").sort
    end

    # From a list of commit messages -> categories
    def categories(list=changes)
    cats = Hash.new { |h, k| h[k] = Array.new }

    list.each { |line|
    case line
    when /^Merge branch/i then nil
    when /^Add(?:ed)? (.*)$/i then cats['Added'] << $1
    when /^Fix(?:ed)? (.*)$/i then cats['Fixed'] << $1
    when /^Change(?:d)? (.*)$/i then cats['Changed'] << $1
    when /^(?:Remove|Delete)(?:d)? (.*)$/i then cats['Removed'] << $1
    when /^\+ (.*)$/i then cats['Added'] << $1
    when /^\! (.*)$/ then cats['Fixed'] << $1
    when /^\- (.*)$/i then cats['Removed'] << $1
    when /^\~ (.*)$/i then cats['Changed'] << $1
    when /^\. (.*)$/i then cats['Misc'] << $1
    else cats['Changed'] << line
    end
    }

    cats
    end

    def log(sets)
    sets.map do |set|
    # Heading name
    h = set[:name]
    h = "Latest version - #{Time.now.strftime('%b %d, %Y')}" if h == 'HEAD'

    h + "\n" + '-'*h.size + "\n\n" +
    set[:changes].map { |category, list|
    "### #{category}:\n" +
    list.map { |item| " * #{item}" }.join("\n")
    }.join("\n\n")
    end.join("\n\n")
    end

    def log_old
    h = "Since #{version || 'the beginning'} - #{Time.now.strftime('%b %d, %Y')}"
    "#{h}\n#{'-'*h.size}\n\n" +
    categories.map { |category, list|
    "### #{category}:\n" +
    list.map { |item| " * #{item}" }.join("\n")
    }.join("\n\n")
    end
    end

    options = {
    :all => (ARGV.delete('-a') || ARGV.delete('--all'))
    }

    if ARGV == ['--help'] || ARGV == ['-h']
    puts "Usage: git clog [-a] [-w]"
    puts
    puts " -a, --all: See the changelog since time immemorial"
    puts " -w, --write: Write to a history file"
    exit
    end

    unless File.directory?('.git')
    puts "Try this command inside a repo's root path."
    exit
    end

    sets = if options[:all]
    Clog.changesets(:all)
    else
    Clog.changesets(:latest)
    end

    if ARGV == []
    puts Clog.log(sets)
    $stderr << "\nUse 'git clog -w' to write.\n"

    elsif ARGV == ['-w'] || ARGV == ['--write']
    # Create the history file
    system 'touch HISTORY.md' if Clog.history_file.nil?

    # Concat
    history = File.open(Clog.history_file) { |f| f.read }
    output = Clog.log(sets)
    output += "\n\n#{'-'*80}\n\n" + history unless history.empty?

    # Write
    File.open(Clog.history_file, 'w') { |f| f.write output }

    if ENV['EDITOR']
    exec "#{ENV['EDITOR']} #{Clog.history_file}"
    else
    puts "Done writing to #{Clog.history_file}."
    end
    end