#!/usr/bin/env python """ Pick up all of the changes of a tree and reparent them elsewhere. Given some arbitrary sequence of commits, all of the changes from the sequence will be applied in the new location. This has an effect similar to rebase, but is purely content driven. Each commit is recorded with the exact state the tree was in, but repositioned on top of the current tree. This is likely the wrong tool for whatever job you're hoping to use it on. It will never have a conflict, but at the consequence of sometimes providing you with diffs that don't make a lot of sense. Read more about this here: """ import os import sys import commands import subprocess def run_cmd(cmd): exitstatus, outtext = commands.getstatusoutput(cmd) if exitstatus != 0: raise RuntimeException("Command failed.") return outtext def cleanup_log(commit, c): return c[:c.index("--" + commit + "--")] def recommit(commit_log, onto): commit, tree, an, ae, ad, cn, ce, cd, log = commit_log log = cleanup_log(commit, log) env = {'GIT_COMMITTER_NAME': cn, 'GIT_COMMITER_EMAIL': ce, 'GIT_AUTHOR_NAME': an, 'GIT_AUTHOR_EMAIL': ae, 'GIT_COMMITER_DATE': cd, 'GIT_AUTHOR_DATE': ad, 'PATH': os.getenv("PATH")} args=["git", "commit-tree", tree, '-p', onto] p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) stdout, stderr = p.communicate(log) sys.stderr.write(stderr) p.wait() if p.returncode != 0: sys.exit(p.returncode) return stdout.strip() if __name__ == '__main__': log = run_cmd('git log --reverse --pretty=format:"%H%n%T%n%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b--%H--%x00" ' + sys.argv[1]) h = run_cmd("git rev-parse HEAD") commits=[s.split("\n", 8) for s in log.split("\0\n")] done=0 for commit in commits: h = recommit(commit, h) done += 1 sys.stdout.write(" %d/%d\r" % (done, len(commits))) sys.stdout.flush() print "The newly created history is available as " + h