From ee510bb02279bedb57a60847fc2927b9f136b048 Mon Sep 17 00:00:00 2001 From: Rocco Rutte Date: Mon, 22 Oct 2007 10:06:58 +0200 Subject: [PATCH] hg-fast-export.py: Rewrite merge logic Merges were completely broken as they ended up with twice the same parent in git. Still everything besides gitk seemed to work. This because of 1) the incorrect assumption that a commit's parent is the commit exported right before it and 2) some confusion with markes being saved/loaded/used since git-fast-import doesn't allow for a ":0" mark to map hg revision 1:1 to marks. The merge "algorithm" now works like this: 1) If the commit's higher parent (highest hg rev), is not the last commit exported for a particular branch, we issue a "from" command to place it on top of it. 2) If the commit's lower parent exists, we issue a "merge" for it. This is much simpler and seems to produce correct merges in git. And while I'm at it, make output less confusing by prepending the target branch name to each line. The "twice the same parent" bug was discovered by Michele Ballabio on the git list. Signed-off-by: Rocco Rutte --- hg-fast-export.py | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/hg-fast-export.py b/hg-fast-export.py index 91caf7d..c85e84e 100755 --- a/hg-fast-export.py +++ b/hg-fast-export.py @@ -22,6 +22,8 @@ def gitmode(x): return x and '100755' or '100644' def wr(msg=''): + if msg == None: + msg = '' print msg #map(lambda x: sys.stderr.write('\t[%s]\n' % x),msg.split('\n')) @@ -37,7 +39,7 @@ def get_parent_mark(parent,marks): """Get the mark for some parent. If we saw it in the current session, return :%d syntax and otherwise the SHA1 from the cache.""" - return marks.get(str(parent+1),':%d' % (parent+1)) + return marks.get(str(parent),':%d' % (parent+1)) def mismatch(f1,f2): """See if two revisions of a file are not equal.""" @@ -147,6 +149,10 @@ def export_commit(ui,repo,revision,marks,heads,last,max,count,authors,sob): wr(desc) wr() + pidx1, pidx2 = 0, 1 + if parents[0] < parents[1]: + pidx1, pidx2 = 1, 0 + src=heads.get(branch,'') link='' if src!='': @@ -154,34 +160,27 @@ def export_commit(ui,repo,revision,marks,heads,last,max,count,authors,sob): # and kill reference so we won't init it again wr('from %s' % src) heads[branch]='' - sys.stderr.write('Initializing branch [%s] to parent [%s]\n' % + sys.stderr.write('%s: Initializing to parent [%s]\n' % (branch,src)) link=src # avoid making a merge commit for incremental import elif link=='' and not heads.has_key(branch) and revision>0: # newly created branch and not the first one: connect to parent tmp=get_parent_mark(parents[0],marks) wr('from %s' % tmp) - sys.stderr.write('Link new branch [%s] to parent [%s]\n' % + sys.stderr.write('%s: Link new branch to parent [%s]\n' % (branch,tmp)) link=tmp # avoid making a merge commit for branch fork - - if parents: - l=last.get(branch,revision) - for p in parents: - # 1) as this commit implicitely is the child of the most recent - # commit of this branch, ignore this parent - # 2) ignore nonexistent parents - # 3) merge otherwise - if p==l or p==revision or p<0: - continue - tmp=get_parent_mark(p,marks) - # if we fork off a branch, don't merge with our parent via 'merge' - # as we have 'from' already above - if tmp==link: - continue - sys.stderr.write('Merging branch [%s] with parent [%s] from [r%d]\n' % - (branch,tmp,p)) - wr('merge %s' % tmp) + elif last.get(branch,revision) != parents[pidx1] and parents[pidx1] > 0 and revision > 0: + pm=get_parent_mark(parents[pidx1],marks) + sys.stderr.write('%s: Placing commit [r%d] in branch [%s] on top of [r%d]\n' % + (branch,revision,branch,parents[pidx1])); + wr('from %s' % pm) + + if parents[pidx2] > 0: + pm=get_parent_mark(parents[pidx2],marks) + sys.stderr.write('%s: Merging with parent [%s] from [r%d]\n' % + (branch,pm,parents[pidx2])) + wr('merge %s' % pm) last[branch]=revision heads[branch]='' @@ -210,8 +209,8 @@ def export_commit(ui,repo,revision,marks,heads,last,max,count,authors,sob): added,changed,removed=f[1],f[0],f[2] type='simple delta' - sys.stderr.write('Exporting %s revision %d/%d with %d/%d/%d added/changed/removed files\n' % - (type,revision+1,max,len(added),len(changed),len(removed))) + sys.stderr.write('%s: Exporting %s revision %d/%d with %d/%d/%d added/changed/removed files\n' % + (branch,type,revision+1,max,len(added),len(changed),len(removed))) map(lambda r: wr('D %s' % r),removed) export_file_contents(ctx,man,added+changed) @@ -288,10 +287,13 @@ def verify_heads(ui,repo,cache,force): return True +def mangle_mark(mark): + return str(int(mark)-1) + def hg2git(repourl,m,marksfile,headsfile,tipfile,authors={},sob=False,force=False): _max=int(m) - marks_cache=load_cache(marksfile) + marks_cache=load_cache(marksfile,mangle_mark) heads_cache=load_cache(headsfile) state_cache=load_cache(tipfile) -- 2.11.4.GIT