Skip to content
This repository was archived by the owner on May 16, 2024. It is now read-only.

Commit 47d330d

Browse files
johannescfrej
authored andcommitted
Add support for mercurial subrepos
This adds a new command line option (--subrepo-map) that will map mercurial subrepos to git submodules. The --subrepo-map takes a mapping file as an argument that will be used to map a subrepo folder to a git submodule. For more information see the README-SUBMODULES.md. This commit is inspired by the changes made by daolis in PR#38 that was never merged. Closes: frej#51 Closes: frej#147
1 parent b51c58d commit 47d330d

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

README-SUBMODULES.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# How to convert Mercurial Repositories with subrepos
2+
3+
## Introduction
4+
5+
Subrepositories must first be converted in order for the conversion of
6+
the super repository to know how hg commits map to git commits in the
7+
sub repositories. When all subrepositories have been converted, a
8+
mapping file that maps the mercurial subrepository path to a converted
9+
git submodule path must be created. The format for this file is:
10+
11+
"<mercurial subrepo path>"="<git submodule path>"
12+
"<mercurial subrepo path2>"="<git submodule path2>"
13+
...
14+
15+
The path of this mapping file is then provided with the --subrepo-map
16+
command line option.
17+
18+
## Example
19+
20+
Example mercurial repo folder structure (~/mercurial):
21+
src/...
22+
subrepo/subrepo1
23+
subrepo/subrepo2
24+
25+
### Setup
26+
Create an empty new folder where all the converted git modules will be imported:
27+
mkdir ~/imported-gits
28+
cd ~/imported-gits
29+
30+
### Convert all submodules to git:
31+
mkdir submodule1
32+
cd submodule1
33+
git init
34+
hg-fast-export.sh -r ~/mercurial/subrepo1
35+
cd ..
36+
mkdir submodule2
37+
cd submodule2
38+
git init
39+
hg-fast-export.sh -r ~/mercurial/subrepo2
40+
41+
### Create mapping file
42+
cd ~/imported-gits
43+
cat > submodule-mappings << EOF
44+
"subrepo/subrepo1"="../submodule1"
45+
"subrepo/subrepo2"="../submodule2"
46+
EOF
47+
48+
### Convert main repository
49+
cd ~/imported-gits
50+
mkdir git-main-repo
51+
cd git-main-repo
52+
git init
53+
hg-fast-export.sh -r ~/mercurial --subrepo-map=../submodule-mappings
54+
55+
### Result
56+
The resulting repository will now contain the subrepo/subrepo1 and
57+
subrepo/subrepo1 submodules. The created .gitmodules file will look
58+
like:
59+
60+
[submodule "subrepo/subrepo1"]
61+
path = subrepo/subrepo1
62+
url = ../submodule1
63+
[submodule "subrepo/subrepo2"]
64+
path = subrepo/subrepo2
65+
url = ../submodule2

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ can be modified by any filter. `file_ctx` is the filecontext from the
171171
mercurial python library. After all filters have been run, the values
172172
are used to add the file to the git commit.
173173

174+
Submodules
175+
----------
176+
See README-SUBMODULES.md for how to convert subrepositories into git
177+
submodules.
178+
174179
Notes/Limitations
175180
-----------------
176181

hg-fast-export.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
# write some progress message every this many file contents written
2929
cfg_export_boundary=1000
3030

31+
subrepo_cache={}
32+
submodule_mappings=None
33+
3134
def gitmode(flags):
3235
return 'l' in flags and '120000' or 'x' in flags and '100755' or '100644'
3336

@@ -128,6 +131,48 @@ def export_file_contents(ctx,manifest,files,hgtags,encoding='',plugins={}):
128131
count=0
129132
max=len(files)
130133
for file in files:
134+
if submodule_mappings and ctx.substate and file==".hgsubstate":
135+
# Remove all submodules as we don't detect deleted submodules properly
136+
# in any other way. We will add the ones not deleted back again below.
137+
for module in submodule_mappings.keys():
138+
wr('D %s' % module)
139+
140+
# Read .hgsubstate file in order to find the revision of each subrepo
141+
data=ctx.filectx(file).data()
142+
subHashes={}
143+
for line in data.split('\n'):
144+
if line.strip()=="":
145+
continue
146+
cols=line.split(' ')
147+
subHashes[cols[1]]=cols[0]
148+
149+
gitmodules=""
150+
# Create the .gitmodules file and all submodules
151+
for name in ctx.substate:
152+
gitRepoLocation=submodule_mappings[name] + "/.git"
153+
154+
# Populate the cache to map mercurial revision to git revision
155+
if not name in subrepo_cache:
156+
subrepo_cache[name]=(load_cache(gitRepoLocation+"/hg2git-mapping"),
157+
load_cache(gitRepoLocation+"/hg2git-marks",
158+
lambda s: int(s)-1))
159+
160+
(mapping_cache, marks_cache)=subrepo_cache[name]
161+
if subHashes[name] in mapping_cache:
162+
revnum=mapping_cache[subHashes[name]]
163+
gitSha=marks_cache[int(revnum)]
164+
wr('M 160000 %s %s' % (gitSha, name))
165+
sys.stderr.write("Adding submodule %s, revision %s->%s\n"
166+
% (name,subHashes[name],gitSha))
167+
gitmodules+='[submodule "%s"]\n\tpath = %s\n\turl = %s\n' % (name, name, submodule_mappings[name])
168+
else:
169+
sys.stderr.write("Warning: Could not find hg revision %s for %s in git %s\n" % (subHashes[name],name,gitRepoLocation))
170+
171+
if len(gitmodules):
172+
wr('M 100644 inline .gitmodules')
173+
wr('data %d' % (len(gitmodules)+1))
174+
wr(gitmodules)
175+
131176
# Skip .hgtags files. They only get us in trouble.
132177
if not hgtags and file == ".hgtags":
133178
sys.stderr.write('Skip %s\n' % (file))
@@ -443,6 +488,15 @@ def check_cache(filename, contents):
443488
(revnode,_,_,_,_,_,_,_)=get_changeset(ui,repo,rev,authors)
444489
mapping_cache[revnode.encode('hex_codec')] = str(rev)
445490

491+
if submodule_mappings:
492+
# Make sure that all submodules are registered in the submodule-mappings file
493+
for rev in range(0,max):
494+
ctx=revsymbol(repo,str(rev))
495+
if ctx.substate:
496+
for key in ctx.substate:
497+
if key not in submodule_mappings:
498+
sys.stderr.write("Error: %s not found in submodule-mappings\n" % (key))
499+
return 1
446500

447501
c=0
448502
brmap={}
@@ -515,6 +569,8 @@ def bail(parser,opt):
515569
help="Additional search path for plugins ")
516570
parser.add_option("--plugin", action="append", type="string", dest="plugins",
517571
help="Add a plugin with the given init string <name=init>")
572+
parser.add_option("--subrepo-map", type="string", dest="subrepo_map",
573+
help="Provide a mapping file between the subrepository name and the submodule name")
518574

519575
(options,args)=parser.parse_args()
520576

@@ -527,6 +583,14 @@ def bail(parser,opt):
527583
if options.statusfile==None: bail(parser,'--status')
528584
if options.repourl==None: bail(parser,'--repo')
529585

586+
if options.subrepo_map:
587+
if not os.path.exists(options.subrepo_map):
588+
sys.stderr.write('Subrepo mapping file not found %s\n'
589+
% options.subrepo_map)
590+
sys.exit(1)
591+
submodule_mappings=load_mapping('subrepo mappings',
592+
options.subrepo_map,False)
593+
530594
a={}
531595
if options.authorfile!=None:
532596
a=load_mapping('authors', options.authorfile, options.raw_mappings)

0 commit comments

Comments
 (0)