Skip to content

Instantly share code, notes, and snippets.

@Bastes
Last active June 24, 2020 16:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bastes/0bb9947b5c78acf993199f3993df4169 to your computer and use it in GitHub Desktop.
Save Bastes/0bb9947b5c78acf993199f3993df4169 to your computer and use it in GitHub Desktop.
git-chain-rebase
#! /usr/bin/env ruby
# frozen_string_literal: true
raise 'requires at least the new base and 1 branch to rebase' if ARGV.length < 2
to_rebase = ARGV[0]
new_base = ARGV[1]
puts "to rebase: #{to_rebase.inspect}"
puts "new base: #{new_base.inspect}"
merge_base = `git merge-base #{to_rebase} #{new_base}`.strip
onto = ARGV[2] || merge_base
puts
puts "onto: #{onto.inspect}"
branches = `git log --abbrev-commit --decorate --format=format:'%d' #{onto}..#{to_rebase}`
.gsub(/[()]/, '')
.split(/\n|,/)
.reject { |l| l =~ %r{/} || l =~ /\A\s*\Z/ }
.map { |l| l.gsub(/HEAD *-> */, '') }
.reverse
puts
puts "branches: #{branches.join(' => ')}"
rebases = ([nil] + branches)
.each_cons(2)
.map do |previous, current|
next "git checkout #{current} && git rebase --onto #{new_base} #{onto}" unless previous
"git checkout #{current} && git rebase --onto #{previous} #{`git rev-parse #{previous}`.strip}"
end
.join ' && '
puts
puts rebases.gsub(/&& /, "&& \\\n ")
puts 'Ready to proceed? Y/n'
ready = STDIN.gets.chomp
exit 0 unless ready =~ /\Ay(?:es)?\Z/i
system(rebases)
push = "git push --force-with-lease origin #{branches.join(' ')}"
puts
puts push
puts 'Ready to proceed? Y/n'
ready = STDIN.gets.chomp
exit 0 unless ready =~ /\Ay(?:es)?\Z/i
system(push)
puts
puts 'All done :)'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment