module Git::Whence::CLI

Constants

SQUASH_REGEX

Public Class Methods

run(argv) click to toggle source
# File lib/git/whence.rb, line 9
def run(argv)
  options = parse_options(argv)
  commit = argv[0]
  unless system("git rev-parse --git-dir 2>&1 >/dev/null")
    warn "Not in a git directory"
    return 1
  end

  commit = expand(commit)

  if is_merge?(commit)
    warn "Commit is a merge"
    show_commit(commit, options)
    1
  else
    if merge = find_merge(commit)
      show_commit(merge, options)
      0
    else
      warn "Unable to find merge"
      show_commit(commit, options) if options[:open]
      1
    end
  end
end

Private Class Methods

expand(commit) click to toggle source
# File lib/git/whence.rb, line 37
def expand(commit)
  sh("git rev-parse #{commit}").strip
end
find_merge(commit) click to toggle source
# File lib/git/whence.rb, line 66
def find_merge(commit)
  merge_commit, merge = (
    find_merge_simple(commit, "HEAD") ||
    find_merge_simple(commit, "master") ||
    find_merge_fuzzy(commit, "master")
  )

  if merge && merge_include_commit?(merge, merge_commit)
    merge
  else
    find_squash_merge(commit) # not very exact, so do this last ... ideally ask github api
  end
end
find_merge_fuzzy(commit, branch) click to toggle source
# File lib/git/whence.rb, line 85
def find_merge_fuzzy(commit, branch)
  if similar = find_similar(commit, branch)
    find_merge_simple(similar, branch)
  end
end
find_merge_simple(commit, branch) click to toggle source
# File lib/git/whence.rb, line 104
def find_merge_simple(commit, branch)
  result = sh("git log #{commit}..#{branch} --ancestry-path --merges --pretty='%H' 2>/dev/null | tail -n 1").chomp
  [commit, result] unless result.empty?
end
find_similar(commit, branch) click to toggle source
# File lib/git/whence.rb, line 95
def find_similar(commit, branch)
  month = 30 * 24 * 60 * 60
  time, search = sh("git show -s --format='%ct %an %s' #{commit}").strip.split(" ", 2)
  time = time.to_i
  same = sh("git log #{branch} --pretty=format:'%H %an %s' --before #{time + month} --after #{time - month}")
  found = same.split("\n").map { |x| x.split(" ", 2) }.detect { |_, message| message == search }
  found && found.first
end
find_squash_merge(commit) click to toggle source
# File lib/git/whence.rb, line 91
def find_squash_merge(commit)
  commit if sh("git show -s --format='%s' #{commit}") =~ SQUASH_REGEX
end
is_merge?(commit) click to toggle source
# File lib/git/whence.rb, line 41
def is_merge?(commit)
  sh("git cat-file -p #{commit}").split("\n")[1..2].grep(/parent /).size > 1
end
merge_include_commit?(merge, commit) click to toggle source
# File lib/git/whence.rb, line 80
def merge_include_commit?(merge, commit)
  commit = sh("git show HEAD -s --format=%H").strip if commit == "HEAD"
  sh("git log #{merge.strip}^..#{merge.strip} --pretty=%H").split("\n").include?(commit)
end
origin() click to toggle source

github.com/foo/bar or git@github.com:foo/bar.git -> foo/bar

# File lib/git/whence.rb, line 60
def origin
  repo = sh("git remote get-url origin").strip # TODO: read file instead
  repo.sub!(/\.git$/, "")
  repo.split(/[:\/]/).last(2).join("/")
end
parse_options(argv) click to toggle source
# File lib/git/whence.rb, line 115
      def parse_options(argv)
        options = {}
        OptionParser.new do |opts|
          opts.banner = <<-BANNER.gsub(/^ {10}/, "")
            Find the merge and pull request a commit came from, also finding straight cherry-picks.

            Usage:
                git-whence <sha>

            Options:
          BANNER
          opts.on("-o", "--open", "Open PR in github") { options[:open] = true }
          opts.on("-h", "--help", "Show this.") { puts opts; exit }
          opts.on("-v", "--version", "Show Version"){ puts Git::Whence::VERSION; exit}
        end.parse!(argv)

        raise "just 1 commit plz" if argv.size != 1

        options
      end
sh(command) click to toggle source
# File lib/git/whence.rb, line 109
def sh(command)
  result = `#{command}`
  raise "Command failed\n#{command}\n#{result}" unless $?.success?
  result
end
show_commit(merge, options) click to toggle source
# File lib/git/whence.rb, line 45
def show_commit(merge, options)
  info = sh("git show -s --oneline #{merge}").strip
  if options[:open]
    if pr = info[/Merge pull request #(\d+) from /, 1] || info[SQUASH_REGEX, 1]
      exec "open", "https://github.com/#{origin}/pull/#{pr}"
    else
      warn "Unable to find PR number in #{info}"
      exec "open", "https://github.com/#{origin}/commit/#{merge}"
    end
  else
    puts info
  end
end