mirror of
https://github.com/frej/fast-export.git
synced 2026-01-23 22:59:02 +01:00
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 <pdmef@gmx.net>
This commit is contained in:
@@ -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
|
||||
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:
|
||||
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)
|
||||
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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user