#! /usr/bin/env ruby require 'rubygems' require 'optparse' OptionParser.new do |opts| opts.banner = < Now trying #{commit}" run!("git checkout #{commit}") return commit if run(command).first end end command = "(bundle check || bundle) && (#{command})" if File.exist?("Gemfile") puts " ---> Initial run:" if run(command).first puts " ---> Current commit is not broken" exit 1 end puts " ---> Trying to find first good commit:" max_commits = 1000 commits = `git log --pretty=format:'%h' | head -n #{max_commits}`.split("\n") unless good = find_first_good_commit(commits[1..-1], command) puts " --> No good commit found" exit 1 end # bisect to get exact match bad = commits[0] run! "git bisect reset" run! "git bisect start" run! "git checkout #{bad}" run! "git bisect bad" run! "git checkout #{good}" run! "git bisect good" success, output = run("git bisect run sh -c '#{command}'") if success # git bisect randomly stops at a commit first_bad = output.match(/([\da-f]+) is the first bad commit/)[1] run! "git checkout #{first_bad}" exit 0 else exit 1 end