Created
April 6, 2021 09:08
-
-
Save seawolf/2e703db30ca017e722abb17520bd2e48 to your computer and use it in GitHub Desktop.
Dedupe a list of Git commits, from/to rebase-todo format, fixing-up duplicates into the first.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'fileutils' | |
FILE = '.git/rebase-merge/git-rebase-todo' | |
FILE_BACKUP = '.git/rebase-merge/git-rebase-todo.backup' | |
FILE_TEMPORARY = '.git/rebase-merge/git-rebase-todo.edited' | |
=begin | |
Dedupe a list of Git commits, from/to rebase-todo format, fixing-up duplicates into the first. | |
Turns this: | |
pick ab1232aa first commit | |
pick cb4180bb second commit | |
pick 828baccc third commit | |
pick cb4180bb second commit | |
pick ab1232aa first commit | |
pick 828baccc third commit | |
pick 91baffdd fourth commit | |
pick ab1232aa first commit | |
Into this: | |
pick ab1232aa first commit | |
fixup ab1232aa first commit | |
fixup ab1232aa first commit | |
pick cb4180bb second commit | |
fixup cb4180bb second commit | |
pick 828baccc third commit | |
fixup 828baccc third commit | |
pick 91baffdd fourth commit | |
=end | |
module GitDeDupe | |
class CommitListFile | |
def initialize(path) | |
@list = File.read(file).split("\n") | |
end | |
def to_commit_list | |
return CommitList.new(list) | |
end | |
private | |
attr_reader :list | |
end | |
class CommitList | |
def initialize(list) | |
@list = .map {|str| Commit.new(str) } | |
end | |
def to_rebase_commands | |
str = "" | |
grouped_commits.inject(nil) do |last_commit, commit| | |
str << "#{commit.operation(last_commit)} #{commit.sha} #{commit.message}\n" | |
commit | |
end | |
str | |
end | |
private | |
def grouped_commits | |
@list | |
.group_by(&:message) | |
.values | |
.flatten | |
end | |
end | |
class Commit | |
attr_reader :sha, :message | |
def initialize(str) | |
# "pick ab1232aa first commit" | |
@operation = str[0..3] | |
@sha = str[5..12] | |
@message = str[14..-1] | |
end | |
def operation(last_commit = nil) | |
return 'fixup' if fixup_for?(last_commit) | |
@operation | |
end | |
def fixup_for?(last_commit) | |
return false if last_commit.nil? | |
last_commit.message == message | |
end | |
end | |
end | |
# clean-up previous runs | |
FileUtils.rm(FILE_TEMPORARY) if File.exist?(FILE_TEMPORARY) | |
# don't destroy any backup from previous runs, use them! | |
if File.exist?(FILE_BACKUP) | |
FileUtils.cp(FILE_BACKUP, FILE) | |
else | |
FileUtils.cp(FILE, FILE_BACKUP) | |
end | |
# process input | |
file = GitDeDupe::CommitListFile.new(FILE) | |
commits = file.to_commit_list | |
list = commits.to_rebase_commands | |
# write output | |
File.open(FILE_TEMPORARY, 'w') do |f| | |
f.puts list | |
end | |
# clean-up | |
FileUtils.mv(FILE_TEMPORARY, FILE) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment