diff options
author | Jason S. McMullan <jason.mcmullan@netronome.com> | 2008-12-11 09:05:05 -0500 |
---|---|---|
committer | Jason S. McMullan <jason.mcmullan@netronome.com> | 2008-12-11 09:05:05 -0500 |
commit | b4833029a44d47b16c12ae3af2acda754e28314f (patch) | |
tree | cbe84739da82d7d259dc2ceba60af7f40ad77d6a | |
parent | 1ab60e492b406ae5dba5f115c605486aa2564caa (diff) | |
download | hg-fast-export-b4833029a44d47b16c12ae3af2acda754e28314f.tar.gz |
hg export: Support tag movement
HG tag movement is now supported with this patch.
This patch creates a .git/hg2git-mapping file, which maps
HG revision numbers to HG hashes. Combined with the
.git/hg2git-marks file, which maps HG revisions to GIT hashes,
we can now reprocess all tags at the end of each hg export
operation.
-rwxr-xr-x | hg-fast-export.py | 43 | ||||
-rwxr-xr-x | hg-fast-export.sh | 5 | ||||
-rwxr-xr-x | hg-reset.py | 10 | ||||
-rwxr-xr-x | hg-reset.sh | 2 |
4 files changed, 40 insertions, 20 deletions
diff --git a/hg-fast-export.py b/hg-fast-export.py index ff32dbc..dd9f179 100755 --- a/hg-fast-export.py +++ b/hg-fast-export.py @@ -117,6 +117,10 @@ def export_file_contents(ctx,manifest,files): count=0 max=len(files) for file in files: + # Skip .hgtags files. They only get us in trouble. + if file == ".hgtags": + sys.stderr.write('Skip %s\n' % (file)) + continue d=ctx.filectx(file).data() wr('M %s inline %s' % (gitmode(manifest.flags(file)),file)) wr('data %d' % len(d)) # had some trouble with size() @@ -153,7 +157,7 @@ def sanitize_name(name,what="branch"): sys.stderr.write('Warning: sanitized %s [%s] to [%s]\n' % (what,name,n)) return n -def export_commit(ui,repo,revision,marks,heads,last,max,count,authors,sob,brmap): +def export_commit(ui,repo,revision,marks,mapping,heads,last,max,count,authors,sob,brmap): def get_branchname(name): if brmap.has_key(name): return brmap[name] @@ -246,17 +250,20 @@ def export_commit(ui,repo,revision,marks,heads,last,max,count,authors,sob,brmap) return checkpoint(count) -def export_tags(ui,repo,marks_cache,start,end,count,authors): +def export_tags(ui,repo,marks_cache,mapping_cache,count,authors): l=repo.tagslist() for tag,node in l: tag=sanitize_name(tag,"tag") # ignore latest revision if tag=='tip': continue - rev=repo.changelog.rev(node) - # ignore those tags not in our import range - if rev<start or rev>=end: continue + # ignore tags to nodes that are missing (ie, 'in the future') + if node.encode('hex_codec') not in mapping_cache: + sys.stderr.write('Tag %s refers to unseen node %s\n' % (tag, node.encode('hex_codec'))) + continue + + rev=int(mapping_cache[node.encode('hex_codec')]) - ref=get_parent_mark(rev,marks_cache) + ref=marks_cache.get(str(rev),':%d' % (rev)) if ref==None: sys.stderr.write('Failed to find reference for creating tag' ' %s at r%d\n' % (tag,rev)) @@ -319,10 +326,11 @@ def verify_heads(ui,repo,cache,force): def mangle_mark(mark): return str(int(mark)-1) -def hg2git(repourl,m,marksfile,headsfile,tipfile,authors={},sob=False,force=False): +def hg2git(repourl,m,marksfile,mappingfile,headsfile,tipfile,authors={},sob=False,force=False): _max=int(m) marks_cache=load_cache(marksfile,mangle_mark) + mapping_cache=load_cache(mappingfile) heads_cache=load_cache(headsfile) state_cache=load_cache(tipfile) @@ -341,19 +349,25 @@ def hg2git(repourl,m,marksfile,headsfile,tipfile,authors={},sob=False,force=Fals if _max<0 or max>tip: max=tip + for rev in range(0,max): + (revnode,_,_,_,_,_,_,_)=get_changeset(ui,repo,rev,authors) + mapping_cache[revnode.encode('hex_codec')] = str(rev) + + c=0 last={} brmap={} for rev in range(min,max): - c=export_commit(ui,repo,rev,marks_cache,heads_cache,last,max,c,authors,sob,brmap) - - c=export_tags(ui,repo,marks_cache,min,max,c,authors) - - sys.stderr.write('Issued %d commands\n' % c) + c=export_commit(ui,repo,rev,marks_cache,mapping_cache,heads_cache,last,max,c,authors,sob,brmap) state_cache['tip']=max state_cache['repo']=repourl save_cache(tipfile,state_cache) + save_cache(mappingfile,mapping_cache) + + c=export_tags(ui,repo,marks_cache,mapping_cache,c,authors) + + sys.stderr.write('Issued %d commands\n' % c) return 0 @@ -367,6 +381,8 @@ if __name__=='__main__': parser.add_option("-m","--max",type="int",dest="max", help="Maximum hg revision to import") + parser.add_option("--mapping",dest="mappingfile", + help="File to read last run's hg-to-git SHA1 mapping") parser.add_option("--marks",dest="marksfile", help="File to read git-fast-import's marks from") parser.add_option("--heads",dest="headsfile", @@ -390,6 +406,7 @@ if __name__=='__main__': if options.max!=None: m=options.max if options.marksfile==None: bail(parser,'--marks') + if options.mappingfile==None: bail(parser,'--mapping') if options.headsfile==None: bail(parser,'--heads') if options.statusfile==None: bail(parser,'--status') if options.repourl==None: bail(parser,'--repo') @@ -401,5 +418,5 @@ if __name__=='__main__': if options.default_branch!=None: set_default_branch(options.default_branch) - sys.exit(hg2git(options.repourl,m,options.marksfile,options.headsfile, + sys.exit(hg2git(options.repourl,m,options.marksfile,options.mappingfile,options.headsfile, options.statusfile,authors=a,sob=options.sob,force=options.force)) diff --git a/hg-fast-export.sh b/hg-fast-export.sh index 0f6b170..5cfc575 100755 --- a/hg-fast-export.sh +++ b/hg-fast-export.sh @@ -6,6 +6,7 @@ ROOT="`dirname $0`" REPO="" PFX="hg2git" +SFX_MAPPING="mapping" SFX_MARKS="marks" SFX_HEADS="heads" SFX_STATE="state" @@ -67,11 +68,11 @@ fi GIT_DIR="$GIT_DIR" $PYTHON "$ROOT/hg-fast-export.py" \ --repo "$REPO" \ --marks "$GIT_DIR/$PFX-$SFX_MARKS" \ + --mapping "$GIT_DIR/$PFX-$SFX_MAPPING" \ --heads "$GIT_DIR/$PFX-$SFX_HEADS" \ --status "$GIT_DIR/$PFX-$SFX_STATE" \ "$@" \ -| git fast-import $QUIET --export-marks="$GIT_DIR/$PFX-$SFX_MARKS.tmp" \ -|| die 'Git fast-import failed' +| git fast-import $QUIET --export-marks="$GIT_DIR/$PFX-$SFX_MARKS.tmp" # move recent marks cache out of the way... if [ -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then diff --git a/hg-reset.py b/hg-reset.py index cc361f0..73eac02 100755 --- a/hg-reset.py +++ b/hg-reset.py @@ -35,7 +35,7 @@ def heads(ui,repo,start=None,stop=None,max=None): return [(repo.changelog.node(r),str(r)) for r in heads] -def get_branches(ui,repo,heads_cache,marks_cache,max): +def get_branches(ui,repo,heads_cache,marks_cache,mapping_cache,max): h=heads(ui,repo,max=max) stale=dict.fromkeys(heads_cache) changed=[] @@ -53,12 +53,12 @@ def get_branches(ui,repo,heads_cache,marks_cache,max): unchanged.sort() return stale,changed,unchanged -def get_tags(ui,repo,marks_cache,max): +def get_tags(ui,repo,marks_cache,mapping_cache,max): l=repo.tagslist() good,bad=[],[] for tag,node in l: if tag=='tip': continue - rev=repo.changelog.rev(node) + rev=int(mapping_cache[node.encode('hex_codec')]) cache_sha1=marks_cache.get(str(int(rev)+1)) _,_,user,(_,_),_,desc,branch,_=get_changeset(ui,repo,rev) if int(rev)>int(max): @@ -110,8 +110,8 @@ if __name__=='__main__': ui,repo=setup_repo(options.repourl) - stale,changed,unchanged=get_branches(ui,repo,heads_cache,marks_cache,options.revision+1) - good,bad=get_tags(ui,repo,marks_cache,options.revision+1) + stale,changed,unchanged=get_branches(ui,repo,heads_cache,marks_cache,mapping_cache,options.revision+1) + good,bad=get_tags(ui,repo,marks_cache,mapping_cache,options.revision+1) print "Possibly stale branches:" map(lambda b: sys.stdout.write('\t%s\n' % b),stale.keys()) diff --git a/hg-reset.sh b/hg-reset.sh index 8d1730c..1823738 100755 --- a/hg-reset.sh +++ b/hg-reset.sh @@ -7,6 +7,7 @@ ROOT="`dirname $0`" REPO="" PFX="hg2git" SFX_MARKS="marks" +SFX_MAPPING="mapping" SFX_HEADS="heads" SFX_STATE="state" QUIET="" @@ -58,6 +59,7 @@ fi GIT_DIR="$GIT_DIR" $PYTHON "$ROOT/hg-reset.py" \ --repo "$REPO" \ --marks "$GIT_DIR/$PFX-$SFX_MARKS" \ + --mapping "$GIT_DIR/$PFX-$SFX_MAPPING" \ --heads "$GIT_DIR/$PFX-$SFX_HEADS" \ --status "$GIT_DIR/$PFX-$SFX_STATE" \ "$@" |