#!/usr/bin/python # This will output a Git "grafts" file to use when a (set of) downstream branch(es) # is to switch from merging with one upstream branch to another upstream branch, without # keeping the full history of both upstream branches in the repository. # If the upstream branches contain the same history information (semantically speaking), # such as when they represent different conversions from an old CVS/SVN repository, then # this script will find an alignment between them. # The resulting grafts file will map past merges in the downstream branch to the new # upstream branch, as if the old upstream branch never existed. # If this works well, a "git filter-branch" should burn in the grafts so that they can # be removed. (This is a history-changing operation.) # See also: # http://thread.gmane.org/gmane.comp.version-control.git/136377 # recommended usage: #./make-grafts.py | sort | uniq > .git/info/grafts # set input file names upstream1 = "em-log" upstream2 = "em-new-log" mergecommits = "aq-merges" # produce files: # git checkout upstream1 # git log --since=2009-01-01 --format="%H %f">../emc/em-log # git checkout upstream2 # git log --since=2009-01-01 --format="%H %f">../emc/em-new-log # export BRANCHES='topic/b1 topic/b2 john jane master' # git log --since=2009-01-01 --author="David Reitter" --format="%H %P" $BRANCHES >../emc/aq-merges; git log --since=2009-01-01 --merges --format="%H %P" $BRANCHES >>../emc/aq-merges ################# import re import sys r1msgs = {} r1revids = {} # checkout emacs # git log --since=2009-01-01 --format="%H %f">../emc/em-log file = open(upstream1, 'r') for l in file: m = re.match("([a-f0-9]*) (.*)", l) if m: r1msgs[m.group(1)] = m.group(2) r1revids[m.group(2)] = m.group(1) file.close() r2msgs = {} r2revids = {} # checkout emacs23 # git log --since=2009-01-01 --format="%H %f" >../emc/em-new-log file = open(upstream2, 'r') for l in file: m = re.match("([a-f0-9]*) (.*)", l) if m: r2msgs[m.group(1)] = m.group(2) r2revids[m.group(2)] = m.group(1) file.close() # checkout master # export BRANCHES='23.1.undone Aquamacs22 dr-after-merge dr/dev dr/experimental dr/suedit master topic/NSAlertDialogs topic/dialogs topic/face-remapping topic/mac-support topic/menu-bar topic/minibuffer topic/option-key-remap topic/printing topic/python-mode topic/reconf topic/smart-spacing topic/spelling topic/tabbar topic/tmm topic/toolbar' # git log --since=2009-01-01 --author="David Reitter" --merges --format="%H %P" $BRANCHES >../emc/aq-merges # it's better to use all commits so we don't miss anything # git log --since=2009-01-01 --author="David Reitter" --format="%H %P" $BRANCHES >../emc/aq-merges; git log --since=2009-01-01 --merges --format="%H %P" $BRANCHES >>../emc/aq-merges def replace (revid): if revid in r1msgs: r1m = r1msgs[revid] if r1m in r2revids: r2r = r2revids[r1m] if r2r: return r2r else: print >> sys.stderr, "can't get mapping for revid "+revid+ r1m else: print >> sys.stderr, "can't find message of revid "+revid return revid # checkout master # file = open(mergecommits, 'r') for l in file: revids = l.rstrip().split(" ") if revids: # test: # revids2 = revids # for r in revids[1:]: # r2 = replace(r) # if r != r2: # revids2 = revids2 + [r2] # correct alternative revids2 = [revids[0]] + map(replace, revids[1:]) if revids != revids2: # make graft entry to write the merge such that it # looks like the merge came from the other branch print " ".join(revids2) else: print >> sys.stderr, "no remappings found for parents of merge revid "+" ".join(revids) file.close()