##// END OF EJS Templates
convert: simplify git.similarity parsing
Siddharth Agarwal -
r22511:b1ec65b3 default
parent child Browse files
Show More
@@ -1,387 +1,384 b''
1 # git.py - git support for the convert extension
1 # git.py - git support for the convert extension
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import os
8 import os
9 import subprocess
9 import subprocess
10 from mercurial import util, config
10 from mercurial import util, config
11 from mercurial.node import hex, nullid
11 from mercurial.node import hex, nullid
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13
13
14 from common import NoRepo, commit, converter_source, checktool
14 from common import NoRepo, commit, converter_source, checktool
15
15
16 class submodule(object):
16 class submodule(object):
17 def __init__(self, path, node, url):
17 def __init__(self, path, node, url):
18 self.path = path
18 self.path = path
19 self.node = node
19 self.node = node
20 self.url = url
20 self.url = url
21
21
22 def hgsub(self):
22 def hgsub(self):
23 return "%s = [git]%s" % (self.path, self.url)
23 return "%s = [git]%s" % (self.path, self.url)
24
24
25 def hgsubstate(self):
25 def hgsubstate(self):
26 return "%s %s" % (self.node, self.path)
26 return "%s %s" % (self.node, self.path)
27
27
28 class convert_git(converter_source):
28 class convert_git(converter_source):
29 # Windows does not support GIT_DIR= construct while other systems
29 # Windows does not support GIT_DIR= construct while other systems
30 # cannot remove environment variable. Just assume none have
30 # cannot remove environment variable. Just assume none have
31 # both issues.
31 # both issues.
32 if util.safehasattr(os, 'unsetenv'):
32 if util.safehasattr(os, 'unsetenv'):
33 def gitopen(self, s, err=None):
33 def gitopen(self, s, err=None):
34 prevgitdir = os.environ.get('GIT_DIR')
34 prevgitdir = os.environ.get('GIT_DIR')
35 os.environ['GIT_DIR'] = self.path
35 os.environ['GIT_DIR'] = self.path
36 try:
36 try:
37 if err == subprocess.PIPE:
37 if err == subprocess.PIPE:
38 (stdin, stdout, stderr) = util.popen3(s)
38 (stdin, stdout, stderr) = util.popen3(s)
39 return stdout
39 return stdout
40 elif err == subprocess.STDOUT:
40 elif err == subprocess.STDOUT:
41 return self.popen_with_stderr(s)
41 return self.popen_with_stderr(s)
42 else:
42 else:
43 return util.popen(s, 'rb')
43 return util.popen(s, 'rb')
44 finally:
44 finally:
45 if prevgitdir is None:
45 if prevgitdir is None:
46 del os.environ['GIT_DIR']
46 del os.environ['GIT_DIR']
47 else:
47 else:
48 os.environ['GIT_DIR'] = prevgitdir
48 os.environ['GIT_DIR'] = prevgitdir
49
49
50 def gitpipe(self, s):
50 def gitpipe(self, s):
51 prevgitdir = os.environ.get('GIT_DIR')
51 prevgitdir = os.environ.get('GIT_DIR')
52 os.environ['GIT_DIR'] = self.path
52 os.environ['GIT_DIR'] = self.path
53 try:
53 try:
54 return util.popen3(s)
54 return util.popen3(s)
55 finally:
55 finally:
56 if prevgitdir is None:
56 if prevgitdir is None:
57 del os.environ['GIT_DIR']
57 del os.environ['GIT_DIR']
58 else:
58 else:
59 os.environ['GIT_DIR'] = prevgitdir
59 os.environ['GIT_DIR'] = prevgitdir
60
60
61 else:
61 else:
62 def gitopen(self, s, err=None):
62 def gitopen(self, s, err=None):
63 if err == subprocess.PIPE:
63 if err == subprocess.PIPE:
64 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
64 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
65 return so
65 return so
66 elif err == subprocess.STDOUT:
66 elif err == subprocess.STDOUT:
67 return self.popen_with_stderr(s)
67 return self.popen_with_stderr(s)
68 else:
68 else:
69 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
69 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
70
70
71 def gitpipe(self, s):
71 def gitpipe(self, s):
72 return util.popen3('GIT_DIR=%s %s' % (self.path, s))
72 return util.popen3('GIT_DIR=%s %s' % (self.path, s))
73
73
74 def popen_with_stderr(self, s):
74 def popen_with_stderr(self, s):
75 p = subprocess.Popen(s, shell=True, bufsize=-1,
75 p = subprocess.Popen(s, shell=True, bufsize=-1,
76 close_fds=util.closefds,
76 close_fds=util.closefds,
77 stdin=subprocess.PIPE,
77 stdin=subprocess.PIPE,
78 stdout=subprocess.PIPE,
78 stdout=subprocess.PIPE,
79 stderr=subprocess.STDOUT,
79 stderr=subprocess.STDOUT,
80 universal_newlines=False,
80 universal_newlines=False,
81 env=None)
81 env=None)
82 return p.stdout
82 return p.stdout
83
83
84 def gitread(self, s):
84 def gitread(self, s):
85 fh = self.gitopen(s)
85 fh = self.gitopen(s)
86 data = fh.read()
86 data = fh.read()
87 return data, fh.close()
87 return data, fh.close()
88
88
89 def __init__(self, ui, path, rev=None):
89 def __init__(self, ui, path, rev=None):
90 super(convert_git, self).__init__(ui, path, rev=rev)
90 super(convert_git, self).__init__(ui, path, rev=rev)
91
91
92 if os.path.isdir(path + "/.git"):
92 if os.path.isdir(path + "/.git"):
93 path += "/.git"
93 path += "/.git"
94 if not os.path.exists(path + "/objects"):
94 if not os.path.exists(path + "/objects"):
95 raise NoRepo(_("%s does not look like a Git repository") % path)
95 raise NoRepo(_("%s does not look like a Git repository") % path)
96
96
97 try:
97 similarity = ui.configint('convert', 'git.similarity', default=0)
98 similarity = int(ui.config('convert', 'git.similarity') or 0)
99 except ValueError:
100 raise util.Abort('convert.git.similarity must be a number')
101 if similarity < 0 or similarity > 100:
98 if similarity < 0 or similarity > 100:
102 raise util.Abort(_('similarity must be between 0 and 100'))
99 raise util.Abort(_('similarity must be between 0 and 100'))
103 if similarity > 0:
100 if similarity > 0:
104 self.simopt = '--find-copies=%d%%' % similarity
101 self.simopt = '--find-copies=%d%%' % similarity
105 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder',
102 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder',
106 False)
103 False)
107 if findcopiesharder:
104 if findcopiesharder:
108 self.simopt += ' --find-copies-harder'
105 self.simopt += ' --find-copies-harder'
109 else:
106 else:
110 self.simopt = ''
107 self.simopt = ''
111
108
112 checktool('git', 'git')
109 checktool('git', 'git')
113
110
114 self.path = path
111 self.path = path
115 self.submodules = []
112 self.submodules = []
116
113
117 self.catfilepipe = self.gitpipe('git cat-file --batch')
114 self.catfilepipe = self.gitpipe('git cat-file --batch')
118
115
119 def after(self):
116 def after(self):
120 for f in self.catfilepipe:
117 for f in self.catfilepipe:
121 f.close()
118 f.close()
122
119
123 def getheads(self):
120 def getheads(self):
124 if not self.rev:
121 if not self.rev:
125 heads, ret = self.gitread('git rev-parse --branches --remotes')
122 heads, ret = self.gitread('git rev-parse --branches --remotes')
126 heads = heads.splitlines()
123 heads = heads.splitlines()
127 else:
124 else:
128 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
125 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
129 heads = [heads[:-1]]
126 heads = [heads[:-1]]
130 if ret:
127 if ret:
131 raise util.Abort(_('cannot retrieve git heads'))
128 raise util.Abort(_('cannot retrieve git heads'))
132 return heads
129 return heads
133
130
134 def catfile(self, rev, type):
131 def catfile(self, rev, type):
135 if rev == hex(nullid):
132 if rev == hex(nullid):
136 raise IOError
133 raise IOError
137 self.catfilepipe[0].write(rev+'\n')
134 self.catfilepipe[0].write(rev+'\n')
138 self.catfilepipe[0].flush()
135 self.catfilepipe[0].flush()
139 info = self.catfilepipe[1].readline().split()
136 info = self.catfilepipe[1].readline().split()
140 if info[1] != type:
137 if info[1] != type:
141 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
138 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
142 size = int(info[2])
139 size = int(info[2])
143 data = self.catfilepipe[1].read(size)
140 data = self.catfilepipe[1].read(size)
144 if len(data) < size:
141 if len(data) < size:
145 raise util.Abort(_('cannot read %r object at %s: unexpected size')
142 raise util.Abort(_('cannot read %r object at %s: unexpected size')
146 % (type, rev))
143 % (type, rev))
147 # read the trailing newline
144 # read the trailing newline
148 self.catfilepipe[1].read(1)
145 self.catfilepipe[1].read(1)
149 return data
146 return data
150
147
151 def getfile(self, name, rev):
148 def getfile(self, name, rev):
152 if rev == hex(nullid):
149 if rev == hex(nullid):
153 return None, None
150 return None, None
154 if name == '.hgsub':
151 if name == '.hgsub':
155 data = '\n'.join([m.hgsub() for m in self.submoditer()])
152 data = '\n'.join([m.hgsub() for m in self.submoditer()])
156 mode = ''
153 mode = ''
157 elif name == '.hgsubstate':
154 elif name == '.hgsubstate':
158 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
155 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
159 mode = ''
156 mode = ''
160 else:
157 else:
161 data = self.catfile(rev, "blob")
158 data = self.catfile(rev, "blob")
162 mode = self.modecache[(name, rev)]
159 mode = self.modecache[(name, rev)]
163 return data, mode
160 return data, mode
164
161
165 def submoditer(self):
162 def submoditer(self):
166 null = hex(nullid)
163 null = hex(nullid)
167 for m in sorted(self.submodules, key=lambda p: p.path):
164 for m in sorted(self.submodules, key=lambda p: p.path):
168 if m.node != null:
165 if m.node != null:
169 yield m
166 yield m
170
167
171 def parsegitmodules(self, content):
168 def parsegitmodules(self, content):
172 """Parse the formatted .gitmodules file, example file format:
169 """Parse the formatted .gitmodules file, example file format:
173 [submodule "sub"]\n
170 [submodule "sub"]\n
174 \tpath = sub\n
171 \tpath = sub\n
175 \turl = git://giturl\n
172 \turl = git://giturl\n
176 """
173 """
177 self.submodules = []
174 self.submodules = []
178 c = config.config()
175 c = config.config()
179 # Each item in .gitmodules starts with \t that cant be parsed
176 # Each item in .gitmodules starts with \t that cant be parsed
180 c.parse('.gitmodules', content.replace('\t',''))
177 c.parse('.gitmodules', content.replace('\t',''))
181 for sec in c.sections():
178 for sec in c.sections():
182 s = c[sec]
179 s = c[sec]
183 if 'url' in s and 'path' in s:
180 if 'url' in s and 'path' in s:
184 self.submodules.append(submodule(s['path'], '', s['url']))
181 self.submodules.append(submodule(s['path'], '', s['url']))
185
182
186 def retrievegitmodules(self, version):
183 def retrievegitmodules(self, version):
187 modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
184 modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
188 if ret:
185 if ret:
189 raise util.Abort(_('cannot read submodules config file in %s') %
186 raise util.Abort(_('cannot read submodules config file in %s') %
190 version)
187 version)
191 self.parsegitmodules(modules)
188 self.parsegitmodules(modules)
192 for m in self.submodules:
189 for m in self.submodules:
193 node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
190 node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
194 if ret:
191 if ret:
195 continue
192 continue
196 m.node = node.strip()
193 m.node = node.strip()
197
194
198 def getchanges(self, version, full):
195 def getchanges(self, version, full):
199 if full:
196 if full:
200 raise util.Abort(_("convert from git do not support --full"))
197 raise util.Abort(_("convert from git do not support --full"))
201 self.modecache = {}
198 self.modecache = {}
202 fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % (
199 fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % (
203 self.simopt, version))
200 self.simopt, version))
204 changes = []
201 changes = []
205 copies = {}
202 copies = {}
206 seen = set()
203 seen = set()
207 entry = None
204 entry = None
208 subexists = [False]
205 subexists = [False]
209 subdeleted = [False]
206 subdeleted = [False]
210 difftree = fh.read().split('\x00')
207 difftree = fh.read().split('\x00')
211 lcount = len(difftree)
208 lcount = len(difftree)
212 i = 0
209 i = 0
213
210
214 def add(entry, f, isdest):
211 def add(entry, f, isdest):
215 seen.add(f)
212 seen.add(f)
216 h = entry[3]
213 h = entry[3]
217 p = (entry[1] == "100755")
214 p = (entry[1] == "100755")
218 s = (entry[1] == "120000")
215 s = (entry[1] == "120000")
219 renamesource = (not isdest and entry[4][0] == 'R')
216 renamesource = (not isdest and entry[4][0] == 'R')
220
217
221 if f == '.gitmodules':
218 if f == '.gitmodules':
222 subexists[0] = True
219 subexists[0] = True
223 if entry[4] == 'D' or renamesource:
220 if entry[4] == 'D' or renamesource:
224 subdeleted[0] = True
221 subdeleted[0] = True
225 changes.append(('.hgsub', hex(nullid)))
222 changes.append(('.hgsub', hex(nullid)))
226 else:
223 else:
227 changes.append(('.hgsub', ''))
224 changes.append(('.hgsub', ''))
228 elif entry[1] == '160000' or entry[0] == ':160000':
225 elif entry[1] == '160000' or entry[0] == ':160000':
229 subexists[0] = True
226 subexists[0] = True
230 else:
227 else:
231 if renamesource:
228 if renamesource:
232 h = hex(nullid)
229 h = hex(nullid)
233 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
230 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
234 changes.append((f, h))
231 changes.append((f, h))
235
232
236 while i < lcount:
233 while i < lcount:
237 l = difftree[i]
234 l = difftree[i]
238 i += 1
235 i += 1
239 if not entry:
236 if not entry:
240 if not l.startswith(':'):
237 if not l.startswith(':'):
241 continue
238 continue
242 entry = l.split()
239 entry = l.split()
243 continue
240 continue
244 f = l
241 f = l
245 if f not in seen:
242 if f not in seen:
246 add(entry, f, False)
243 add(entry, f, False)
247 # A file can be copied multiple times, or modified and copied
244 # A file can be copied multiple times, or modified and copied
248 # simultaneously. So f can be repeated even if fdest isn't.
245 # simultaneously. So f can be repeated even if fdest isn't.
249 if entry[4][0] in 'RC':
246 if entry[4][0] in 'RC':
250 # rename or copy: next line is the destination
247 # rename or copy: next line is the destination
251 fdest = difftree[i]
248 fdest = difftree[i]
252 i += 1
249 i += 1
253 if fdest not in seen:
250 if fdest not in seen:
254 add(entry, fdest, True)
251 add(entry, fdest, True)
255 # .gitmodules isn't imported at all, so it being copied to
252 # .gitmodules isn't imported at all, so it being copied to
256 # and fro doesn't really make sense
253 # and fro doesn't really make sense
257 if f != '.gitmodules' and fdest != '.gitmodules':
254 if f != '.gitmodules' and fdest != '.gitmodules':
258 copies[fdest] = f
255 copies[fdest] = f
259 entry = None
256 entry = None
260 if fh.close():
257 if fh.close():
261 raise util.Abort(_('cannot read changes in %s') % version)
258 raise util.Abort(_('cannot read changes in %s') % version)
262
259
263 if subexists[0]:
260 if subexists[0]:
264 if subdeleted[0]:
261 if subdeleted[0]:
265 changes.append(('.hgsubstate', hex(nullid)))
262 changes.append(('.hgsubstate', hex(nullid)))
266 else:
263 else:
267 self.retrievegitmodules(version)
264 self.retrievegitmodules(version)
268 changes.append(('.hgsubstate', ''))
265 changes.append(('.hgsubstate', ''))
269 return (changes, copies)
266 return (changes, copies)
270
267
271 def getcommit(self, version):
268 def getcommit(self, version):
272 c = self.catfile(version, "commit") # read the commit hash
269 c = self.catfile(version, "commit") # read the commit hash
273 end = c.find("\n\n")
270 end = c.find("\n\n")
274 message = c[end + 2:]
271 message = c[end + 2:]
275 message = self.recode(message)
272 message = self.recode(message)
276 l = c[:end].splitlines()
273 l = c[:end].splitlines()
277 parents = []
274 parents = []
278 author = committer = None
275 author = committer = None
279 for e in l[1:]:
276 for e in l[1:]:
280 n, v = e.split(" ", 1)
277 n, v = e.split(" ", 1)
281 if n == "author":
278 if n == "author":
282 p = v.split()
279 p = v.split()
283 tm, tz = p[-2:]
280 tm, tz = p[-2:]
284 author = " ".join(p[:-2])
281 author = " ".join(p[:-2])
285 if author[0] == "<": author = author[1:-1]
282 if author[0] == "<": author = author[1:-1]
286 author = self.recode(author)
283 author = self.recode(author)
287 if n == "committer":
284 if n == "committer":
288 p = v.split()
285 p = v.split()
289 tm, tz = p[-2:]
286 tm, tz = p[-2:]
290 committer = " ".join(p[:-2])
287 committer = " ".join(p[:-2])
291 if committer[0] == "<": committer = committer[1:-1]
288 if committer[0] == "<": committer = committer[1:-1]
292 committer = self.recode(committer)
289 committer = self.recode(committer)
293 if n == "parent":
290 if n == "parent":
294 parents.append(v)
291 parents.append(v)
295
292
296 if committer and committer != author:
293 if committer and committer != author:
297 message += "\ncommitter: %s\n" % committer
294 message += "\ncommitter: %s\n" % committer
298 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
295 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
299 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
296 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
300 date = tm + " " + str(tz)
297 date = tm + " " + str(tz)
301
298
302 c = commit(parents=parents, date=date, author=author, desc=message,
299 c = commit(parents=parents, date=date, author=author, desc=message,
303 rev=version)
300 rev=version)
304 return c
301 return c
305
302
306 def numcommits(self):
303 def numcommits(self):
307 return len([None for _ in self.gitopen('git rev-list --all')])
304 return len([None for _ in self.gitopen('git rev-list --all')])
308
305
309 def gettags(self):
306 def gettags(self):
310 tags = {}
307 tags = {}
311 alltags = {}
308 alltags = {}
312 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
309 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
313 err=subprocess.STDOUT)
310 err=subprocess.STDOUT)
314 prefix = 'refs/tags/'
311 prefix = 'refs/tags/'
315
312
316 # Build complete list of tags, both annotated and bare ones
313 # Build complete list of tags, both annotated and bare ones
317 for line in fh:
314 for line in fh:
318 line = line.strip()
315 line = line.strip()
319 if line.startswith("error:") or line.startswith("fatal:"):
316 if line.startswith("error:") or line.startswith("fatal:"):
320 raise util.Abort(_('cannot read tags from %s') % self.path)
317 raise util.Abort(_('cannot read tags from %s') % self.path)
321 node, tag = line.split(None, 1)
318 node, tag = line.split(None, 1)
322 if not tag.startswith(prefix):
319 if not tag.startswith(prefix):
323 continue
320 continue
324 alltags[tag[len(prefix):]] = node
321 alltags[tag[len(prefix):]] = node
325 if fh.close():
322 if fh.close():
326 raise util.Abort(_('cannot read tags from %s') % self.path)
323 raise util.Abort(_('cannot read tags from %s') % self.path)
327
324
328 # Filter out tag objects for annotated tag refs
325 # Filter out tag objects for annotated tag refs
329 for tag in alltags:
326 for tag in alltags:
330 if tag.endswith('^{}'):
327 if tag.endswith('^{}'):
331 tags[tag[:-3]] = alltags[tag]
328 tags[tag[:-3]] = alltags[tag]
332 else:
329 else:
333 if tag + '^{}' in alltags:
330 if tag + '^{}' in alltags:
334 continue
331 continue
335 else:
332 else:
336 tags[tag] = alltags[tag]
333 tags[tag] = alltags[tag]
337
334
338 return tags
335 return tags
339
336
340 def getchangedfiles(self, version, i):
337 def getchangedfiles(self, version, i):
341 changes = []
338 changes = []
342 if i is None:
339 if i is None:
343 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
340 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
344 for l in fh:
341 for l in fh:
345 if "\t" not in l:
342 if "\t" not in l:
346 continue
343 continue
347 m, f = l[:-1].split("\t")
344 m, f = l[:-1].split("\t")
348 changes.append(f)
345 changes.append(f)
349 else:
346 else:
350 fh = self.gitopen('git diff-tree --name-only --root -r %s '
347 fh = self.gitopen('git diff-tree --name-only --root -r %s '
351 '"%s^%s" --' % (version, version, i + 1))
348 '"%s^%s" --' % (version, version, i + 1))
352 changes = [f.rstrip('\n') for f in fh]
349 changes = [f.rstrip('\n') for f in fh]
353 if fh.close():
350 if fh.close():
354 raise util.Abort(_('cannot read changes in %s') % version)
351 raise util.Abort(_('cannot read changes in %s') % version)
355
352
356 return changes
353 return changes
357
354
358 def getbookmarks(self):
355 def getbookmarks(self):
359 bookmarks = {}
356 bookmarks = {}
360
357
361 # Interesting references in git are prefixed
358 # Interesting references in git are prefixed
362 prefix = 'refs/heads/'
359 prefix = 'refs/heads/'
363 prefixlen = len(prefix)
360 prefixlen = len(prefix)
364
361
365 # factor two commands
362 # factor two commands
366 gitcmd = { 'remote/': 'git ls-remote --heads origin',
363 gitcmd = { 'remote/': 'git ls-remote --heads origin',
367 '': 'git show-ref'}
364 '': 'git show-ref'}
368
365
369 # Origin heads
366 # Origin heads
370 for reftype in gitcmd:
367 for reftype in gitcmd:
371 try:
368 try:
372 fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
369 fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
373 for line in fh:
370 for line in fh:
374 line = line.strip()
371 line = line.strip()
375 rev, name = line.split(None, 1)
372 rev, name = line.split(None, 1)
376 if not name.startswith(prefix):
373 if not name.startswith(prefix):
377 continue
374 continue
378 name = '%s%s' % (reftype, name[prefixlen:])
375 name = '%s%s' % (reftype, name[prefixlen:])
379 bookmarks[name] = rev
376 bookmarks[name] = rev
380 except Exception:
377 except Exception:
381 pass
378 pass
382
379
383 return bookmarks
380 return bookmarks
384
381
385 def checkrevformat(self, revstr, mapname='splicemap'):
382 def checkrevformat(self, revstr, mapname='splicemap'):
386 """ git revision string is a 40 byte hex """
383 """ git revision string is a 40 byte hex """
387 self.checkhexformat(revstr, mapname)
384 self.checkhexformat(revstr, mapname)
@@ -1,515 +1,515 b''
1 #require git
1 #require git
2
2
3 $ echo "[core]" >> $HOME/.gitconfig
3 $ echo "[core]" >> $HOME/.gitconfig
4 $ echo "autocrlf = false" >> $HOME/.gitconfig
4 $ echo "autocrlf = false" >> $HOME/.gitconfig
5 $ echo "[core]" >> $HOME/.gitconfig
5 $ echo "[core]" >> $HOME/.gitconfig
6 $ echo "autocrlf = false" >> $HOME/.gitconfig
6 $ echo "autocrlf = false" >> $HOME/.gitconfig
7 $ echo "[extensions]" >> $HGRCPATH
7 $ echo "[extensions]" >> $HGRCPATH
8 $ echo "convert=" >> $HGRCPATH
8 $ echo "convert=" >> $HGRCPATH
9 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
9 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
10 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
10 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
11 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
11 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
12 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
12 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
13 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
13 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
14 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
14 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
15 $ INVALIDID1=afd12345af
15 $ INVALIDID1=afd12345af
16 $ INVALIDID2=28173x36ddd1e67bf7098d541130558ef5534a86
16 $ INVALIDID2=28173x36ddd1e67bf7098d541130558ef5534a86
17 $ VALIDID1=39b3d83f9a69a9ba4ebb111461071a0af0027357
17 $ VALIDID1=39b3d83f9a69a9ba4ebb111461071a0af0027357
18 $ VALIDID2=8dd6476bd09d9c7776355dc454dafe38efaec5da
18 $ VALIDID2=8dd6476bd09d9c7776355dc454dafe38efaec5da
19 $ count=10
19 $ count=10
20 $ commit()
20 $ commit()
21 > {
21 > {
22 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
22 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
23 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
23 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
24 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
24 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
25 > count=`expr $count + 1`
25 > count=`expr $count + 1`
26 > }
26 > }
27 $ mkdir git-repo
27 $ mkdir git-repo
28 $ cd git-repo
28 $ cd git-repo
29 $ git init-db >/dev/null 2>/dev/null
29 $ git init-db >/dev/null 2>/dev/null
30 $ echo a > a
30 $ echo a > a
31 $ mkdir d
31 $ mkdir d
32 $ echo b > d/b
32 $ echo b > d/b
33 $ git add a d
33 $ git add a d
34 $ commit -a -m t1
34 $ commit -a -m t1
35
35
36 Remove the directory, then try to replace it with a file (issue754)
36 Remove the directory, then try to replace it with a file (issue754)
37
37
38 $ git rm -f d/b
38 $ git rm -f d/b
39 rm 'd/b'
39 rm 'd/b'
40 $ commit -m t2
40 $ commit -m t2
41 $ echo d > d
41 $ echo d > d
42 $ git add d
42 $ git add d
43 $ commit -m t3
43 $ commit -m t3
44 $ echo b >> a
44 $ echo b >> a
45 $ commit -a -m t4.1
45 $ commit -a -m t4.1
46 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
46 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
47 $ echo c > a
47 $ echo c > a
48 $ echo a >> a
48 $ echo a >> a
49 $ commit -a -m t4.2
49 $ commit -a -m t4.2
50 $ git checkout master >/dev/null 2>/dev/null
50 $ git checkout master >/dev/null 2>/dev/null
51 $ git pull --no-commit . other > /dev/null 2>/dev/null
51 $ git pull --no-commit . other > /dev/null 2>/dev/null
52 $ commit -m 'Merge branch other'
52 $ commit -m 'Merge branch other'
53 $ cd ..
53 $ cd ..
54 $ hg convert --config extensions.progress= --config progress.assume-tty=1 \
54 $ hg convert --config extensions.progress= --config progress.assume-tty=1 \
55 > --config progress.delay=0 --config progress.changedelay=0 \
55 > --config progress.delay=0 --config progress.changedelay=0 \
56 > --config progress.refresh=0 --config progress.width=60 \
56 > --config progress.refresh=0 --config progress.width=60 \
57 > --datesort git-repo
57 > --datesort git-repo
58 \r (no-eol) (esc)
58 \r (no-eol) (esc)
59 scanning [======> ] 1/6\r (no-eol) (esc)
59 scanning [======> ] 1/6\r (no-eol) (esc)
60 scanning [=============> ] 2/6\r (no-eol) (esc)
60 scanning [=============> ] 2/6\r (no-eol) (esc)
61 scanning [=====================> ] 3/6\r (no-eol) (esc)
61 scanning [=====================> ] 3/6\r (no-eol) (esc)
62 scanning [============================> ] 4/6\r (no-eol) (esc)
62 scanning [============================> ] 4/6\r (no-eol) (esc)
63 scanning [===================================> ] 5/6\r (no-eol) (esc)
63 scanning [===================================> ] 5/6\r (no-eol) (esc)
64 scanning [===========================================>] 6/6\r (no-eol) (esc)
64 scanning [===========================================>] 6/6\r (no-eol) (esc)
65 \r (no-eol) (esc)
65 \r (no-eol) (esc)
66 \r (no-eol) (esc)
66 \r (no-eol) (esc)
67 converting [ ] 0/6\r (no-eol) (esc)
67 converting [ ] 0/6\r (no-eol) (esc)
68 getting files [==================> ] 1/2\r (no-eol) (esc)
68 getting files [==================> ] 1/2\r (no-eol) (esc)
69 getting files [======================================>] 2/2\r (no-eol) (esc)
69 getting files [======================================>] 2/2\r (no-eol) (esc)
70 \r (no-eol) (esc)
70 \r (no-eol) (esc)
71 \r (no-eol) (esc)
71 \r (no-eol) (esc)
72 converting [======> ] 1/6\r (no-eol) (esc)
72 converting [======> ] 1/6\r (no-eol) (esc)
73 getting files [======================================>] 1/1\r (no-eol) (esc)
73 getting files [======================================>] 1/1\r (no-eol) (esc)
74 \r (no-eol) (esc)
74 \r (no-eol) (esc)
75 \r (no-eol) (esc)
75 \r (no-eol) (esc)
76 converting [=============> ] 2/6\r (no-eol) (esc)
76 converting [=============> ] 2/6\r (no-eol) (esc)
77 getting files [======================================>] 1/1\r (no-eol) (esc)
77 getting files [======================================>] 1/1\r (no-eol) (esc)
78 \r (no-eol) (esc)
78 \r (no-eol) (esc)
79 \r (no-eol) (esc)
79 \r (no-eol) (esc)
80 converting [====================> ] 3/6\r (no-eol) (esc)
80 converting [====================> ] 3/6\r (no-eol) (esc)
81 getting files [======================================>] 1/1\r (no-eol) (esc)
81 getting files [======================================>] 1/1\r (no-eol) (esc)
82 \r (no-eol) (esc)
82 \r (no-eol) (esc)
83 \r (no-eol) (esc)
83 \r (no-eol) (esc)
84 converting [===========================> ] 4/6\r (no-eol) (esc)
84 converting [===========================> ] 4/6\r (no-eol) (esc)
85 getting files [======================================>] 1/1\r (no-eol) (esc)
85 getting files [======================================>] 1/1\r (no-eol) (esc)
86 \r (no-eol) (esc)
86 \r (no-eol) (esc)
87 \r (no-eol) (esc)
87 \r (no-eol) (esc)
88 converting [==================================> ] 5/6\r (no-eol) (esc)
88 converting [==================================> ] 5/6\r (no-eol) (esc)
89 getting files [======================================>] 1/1\r (no-eol) (esc)
89 getting files [======================================>] 1/1\r (no-eol) (esc)
90 \r (no-eol) (esc)
90 \r (no-eol) (esc)
91 assuming destination git-repo-hg
91 assuming destination git-repo-hg
92 initializing destination git-repo-hg repository
92 initializing destination git-repo-hg repository
93 scanning source...
93 scanning source...
94 sorting...
94 sorting...
95 converting...
95 converting...
96 5 t1
96 5 t1
97 4 t2
97 4 t2
98 3 t3
98 3 t3
99 2 t4.1
99 2 t4.1
100 1 t4.2
100 1 t4.2
101 0 Merge branch other
101 0 Merge branch other
102 updating bookmarks
102 updating bookmarks
103 $ hg up -q -R git-repo-hg
103 $ hg up -q -R git-repo-hg
104 $ hg -R git-repo-hg tip -v
104 $ hg -R git-repo-hg tip -v
105 changeset: 5:c78094926be2
105 changeset: 5:c78094926be2
106 bookmark: master
106 bookmark: master
107 tag: tip
107 tag: tip
108 parent: 3:f5f5cb45432b
108 parent: 3:f5f5cb45432b
109 parent: 4:4e174f80c67c
109 parent: 4:4e174f80c67c
110 user: test <test@example.org>
110 user: test <test@example.org>
111 date: Mon Jan 01 00:00:15 2007 +0000
111 date: Mon Jan 01 00:00:15 2007 +0000
112 files: a
112 files: a
113 description:
113 description:
114 Merge branch other
114 Merge branch other
115
115
116
116
117 $ count=10
117 $ count=10
118 $ mkdir git-repo2
118 $ mkdir git-repo2
119 $ cd git-repo2
119 $ cd git-repo2
120 $ git init-db >/dev/null 2>/dev/null
120 $ git init-db >/dev/null 2>/dev/null
121 $ echo foo > foo
121 $ echo foo > foo
122 $ git add foo
122 $ git add foo
123 $ commit -a -m 'add foo'
123 $ commit -a -m 'add foo'
124 $ echo >> foo
124 $ echo >> foo
125 $ commit -a -m 'change foo'
125 $ commit -a -m 'change foo'
126 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
126 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
127 $ echo quux >> quux
127 $ echo quux >> quux
128 $ git add quux
128 $ git add quux
129 $ commit -a -m 'add quux'
129 $ commit -a -m 'add quux'
130 $ echo bar > bar
130 $ echo bar > bar
131 $ git add bar
131 $ git add bar
132 $ commit -a -m 'add bar'
132 $ commit -a -m 'add bar'
133 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
133 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
134 $ echo baz > baz
134 $ echo baz > baz
135 $ git add baz
135 $ git add baz
136 $ commit -a -m 'add baz'
136 $ commit -a -m 'add baz'
137 $ git checkout master >/dev/null 2>/dev/null
137 $ git checkout master >/dev/null 2>/dev/null
138 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
138 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
139 $ commit -m 'Octopus merge'
139 $ commit -m 'Octopus merge'
140 $ echo bar >> bar
140 $ echo bar >> bar
141 $ commit -a -m 'change bar'
141 $ commit -a -m 'change bar'
142 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
142 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
143 $ echo >> foo
143 $ echo >> foo
144 $ commit -a -m 'change foo'
144 $ commit -a -m 'change foo'
145 $ git checkout master >/dev/null 2>/dev/null
145 $ git checkout master >/dev/null 2>/dev/null
146 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
146 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
147 $ commit -m 'Discard change to foo'
147 $ commit -m 'Discard change to foo'
148 $ cd ..
148 $ cd ..
149 $ glog()
149 $ glog()
150 > {
150 > {
151 > hg log -G --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
151 > hg log -G --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
152 > }
152 > }
153 $ splitrepo()
153 $ splitrepo()
154 > {
154 > {
155 > msg="$1"
155 > msg="$1"
156 > files="$2"
156 > files="$2"
157 > opts=$3
157 > opts=$3
158 > echo "% $files: $msg"
158 > echo "% $files: $msg"
159 > prefix=`echo "$files" | sed -e 's/ /-/g'`
159 > prefix=`echo "$files" | sed -e 's/ /-/g'`
160 > fmap="$prefix.fmap"
160 > fmap="$prefix.fmap"
161 > repo="$prefix.repo"
161 > repo="$prefix.repo"
162 > for i in $files; do
162 > for i in $files; do
163 > echo "include $i" >> "$fmap"
163 > echo "include $i" >> "$fmap"
164 > done
164 > done
165 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
165 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
166 > hg up -q -R "$repo"
166 > hg up -q -R "$repo"
167 > glog -R "$repo"
167 > glog -R "$repo"
168 > hg -R "$repo" manifest --debug
168 > hg -R "$repo" manifest --debug
169 > }
169 > }
170
170
171 full conversion
171 full conversion
172
172
173 $ hg -q convert --datesort git-repo2 fullrepo
173 $ hg -q convert --datesort git-repo2 fullrepo
174 $ hg up -q -R fullrepo
174 $ hg up -q -R fullrepo
175 $ glog -R fullrepo
175 $ glog -R fullrepo
176 @ 9 "Discard change to foo" files: foo
176 @ 9 "Discard change to foo" files: foo
177 |\
177 |\
178 | o 8 "change foo" files: foo
178 | o 8 "change foo" files: foo
179 | |
179 | |
180 o | 7 "change bar" files: bar
180 o | 7 "change bar" files: bar
181 |/
181 |/
182 o 6 "(octopus merge fixup)" files:
182 o 6 "(octopus merge fixup)" files:
183 |\
183 |\
184 | o 5 "Octopus merge" files: baz
184 | o 5 "Octopus merge" files: baz
185 | |\
185 | |\
186 o | | 4 "add baz" files: baz
186 o | | 4 "add baz" files: baz
187 | | |
187 | | |
188 +---o 3 "add bar" files: bar
188 +---o 3 "add bar" files: bar
189 | |
189 | |
190 o | 2 "add quux" files: quux
190 o | 2 "add quux" files: quux
191 | |
191 | |
192 | o 1 "change foo" files: foo
192 | o 1 "change foo" files: foo
193 |/
193 |/
194 o 0 "add foo" files: foo
194 o 0 "add foo" files: foo
195
195
196 $ hg -R fullrepo manifest --debug
196 $ hg -R fullrepo manifest --debug
197 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
197 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
198 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
198 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
199 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
199 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
200 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
200 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
201 $ splitrepo 'octopus merge' 'foo bar baz'
201 $ splitrepo 'octopus merge' 'foo bar baz'
202 % foo bar baz: octopus merge
202 % foo bar baz: octopus merge
203 @ 8 "Discard change to foo" files: foo
203 @ 8 "Discard change to foo" files: foo
204 |\
204 |\
205 | o 7 "change foo" files: foo
205 | o 7 "change foo" files: foo
206 | |
206 | |
207 o | 6 "change bar" files: bar
207 o | 6 "change bar" files: bar
208 |/
208 |/
209 o 5 "(octopus merge fixup)" files:
209 o 5 "(octopus merge fixup)" files:
210 |\
210 |\
211 | o 4 "Octopus merge" files: baz
211 | o 4 "Octopus merge" files: baz
212 | |\
212 | |\
213 o | | 3 "add baz" files: baz
213 o | | 3 "add baz" files: baz
214 | | |
214 | | |
215 +---o 2 "add bar" files: bar
215 +---o 2 "add bar" files: bar
216 | |
216 | |
217 | o 1 "change foo" files: foo
217 | o 1 "change foo" files: foo
218 |/
218 |/
219 o 0 "add foo" files: foo
219 o 0 "add foo" files: foo
220
220
221 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
221 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
222 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
222 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
223 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
223 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
224 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
224 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
225 % foo baz quux: only some parents of an octopus merge; "discard" a head
225 % foo baz quux: only some parents of an octopus merge; "discard" a head
226 @ 6 "Discard change to foo" files: foo
226 @ 6 "Discard change to foo" files: foo
227 |
227 |
228 o 5 "change foo" files: foo
228 o 5 "change foo" files: foo
229 |
229 |
230 o 4 "Octopus merge" files:
230 o 4 "Octopus merge" files:
231 |\
231 |\
232 | o 3 "add baz" files: baz
232 | o 3 "add baz" files: baz
233 | |
233 | |
234 | o 2 "add quux" files: quux
234 | o 2 "add quux" files: quux
235 | |
235 | |
236 o | 1 "change foo" files: foo
236 o | 1 "change foo" files: foo
237 |/
237 |/
238 o 0 "add foo" files: foo
238 o 0 "add foo" files: foo
239
239
240 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
240 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
241 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
241 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
242 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
242 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
243
243
244 test importing git renames and copies
244 test importing git renames and copies
245
245
246 $ cd git-repo2
246 $ cd git-repo2
247 $ git mv foo foo-renamed
247 $ git mv foo foo-renamed
248 since bar is not touched in this commit, this copy will not be detected
248 since bar is not touched in this commit, this copy will not be detected
249 $ cp bar bar-copied
249 $ cp bar bar-copied
250 $ cp baz baz-copied
250 $ cp baz baz-copied
251 $ cp baz baz-copied2
251 $ cp baz baz-copied2
252 $ echo baz2 >> baz
252 $ echo baz2 >> baz
253 $ git add bar-copied baz-copied baz-copied2
253 $ git add bar-copied baz-copied baz-copied2
254 $ commit -a -m 'rename and copy'
254 $ commit -a -m 'rename and copy'
255 $ cd ..
255 $ cd ..
256
256
257 input validation
257 input validation
258 $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo
258 $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo
259 abort: convert.git.similarity must be a number
259 abort: convert.git.similarity is not an integer ('foo')
260 [255]
260 [255]
261 $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo
261 $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo
262 abort: similarity must be between 0 and 100
262 abort: similarity must be between 0 and 100
263 [255]
263 [255]
264 $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo
264 $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo
265 abort: similarity must be between 0 and 100
265 abort: similarity must be between 0 and 100
266 [255]
266 [255]
267
267
268 $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo
268 $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo
269 $ hg -R fullrepo status -C --change master
269 $ hg -R fullrepo status -C --change master
270 M baz
270 M baz
271 A bar-copied
271 A bar-copied
272 A baz-copied
272 A baz-copied
273 baz
273 baz
274 A baz-copied2
274 A baz-copied2
275 baz
275 baz
276 A foo-renamed
276 A foo-renamed
277 foo
277 foo
278 R foo
278 R foo
279
279
280 $ cd git-repo2
280 $ cd git-repo2
281 $ cp bar bar-copied2
281 $ cp bar bar-copied2
282 $ git add bar-copied2
282 $ git add bar-copied2
283 $ commit -a -m 'copy with no changes'
283 $ commit -a -m 'copy with no changes'
284 $ cd ..
284 $ cd ..
285
285
286 $ hg -q convert --config convert.git.similarity=100 \
286 $ hg -q convert --config convert.git.similarity=100 \
287 > --config convert.git.findcopiesharder=1 --datesort git-repo2 fullrepo
287 > --config convert.git.findcopiesharder=1 --datesort git-repo2 fullrepo
288 $ hg -R fullrepo status -C --change master
288 $ hg -R fullrepo status -C --change master
289 A bar-copied2
289 A bar-copied2
290 bar
290 bar
291
291
292 test binary conversion (issue1359)
292 test binary conversion (issue1359)
293
293
294 $ count=19
294 $ count=19
295 $ mkdir git-repo3
295 $ mkdir git-repo3
296 $ cd git-repo3
296 $ cd git-repo3
297 $ git init-db >/dev/null 2>/dev/null
297 $ git init-db >/dev/null 2>/dev/null
298 $ python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
298 $ python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
299 $ git add b
299 $ git add b
300 $ commit -a -m addbinary
300 $ commit -a -m addbinary
301 $ cd ..
301 $ cd ..
302
302
303 convert binary file
303 convert binary file
304
304
305 $ hg convert git-repo3 git-repo3-hg
305 $ hg convert git-repo3 git-repo3-hg
306 initializing destination git-repo3-hg repository
306 initializing destination git-repo3-hg repository
307 scanning source...
307 scanning source...
308 sorting...
308 sorting...
309 converting...
309 converting...
310 0 addbinary
310 0 addbinary
311 updating bookmarks
311 updating bookmarks
312 $ cd git-repo3-hg
312 $ cd git-repo3-hg
313 $ hg up -C
313 $ hg up -C
314 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
314 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 $ python -c 'print len(file("b", "rb").read())'
315 $ python -c 'print len(file("b", "rb").read())'
316 4096
316 4096
317 $ cd ..
317 $ cd ..
318
318
319 test author vs committer
319 test author vs committer
320
320
321 $ mkdir git-repo4
321 $ mkdir git-repo4
322 $ cd git-repo4
322 $ cd git-repo4
323 $ git init-db >/dev/null 2>/dev/null
323 $ git init-db >/dev/null 2>/dev/null
324 $ echo >> foo
324 $ echo >> foo
325 $ git add foo
325 $ git add foo
326 $ commit -a -m addfoo
326 $ commit -a -m addfoo
327 $ echo >> foo
327 $ echo >> foo
328 $ GIT_AUTHOR_NAME="nottest"
328 $ GIT_AUTHOR_NAME="nottest"
329 $ commit -a -m addfoo2
329 $ commit -a -m addfoo2
330 $ cd ..
330 $ cd ..
331
331
332 convert author committer
332 convert author committer
333
333
334 $ hg convert git-repo4 git-repo4-hg
334 $ hg convert git-repo4 git-repo4-hg
335 initializing destination git-repo4-hg repository
335 initializing destination git-repo4-hg repository
336 scanning source...
336 scanning source...
337 sorting...
337 sorting...
338 converting...
338 converting...
339 1 addfoo
339 1 addfoo
340 0 addfoo2
340 0 addfoo2
341 updating bookmarks
341 updating bookmarks
342 $ hg -R git-repo4-hg log -v
342 $ hg -R git-repo4-hg log -v
343 changeset: 1:d63e967f93da
343 changeset: 1:d63e967f93da
344 bookmark: master
344 bookmark: master
345 tag: tip
345 tag: tip
346 user: nottest <test@example.org>
346 user: nottest <test@example.org>
347 date: Mon Jan 01 00:00:21 2007 +0000
347 date: Mon Jan 01 00:00:21 2007 +0000
348 files: foo
348 files: foo
349 description:
349 description:
350 addfoo2
350 addfoo2
351
351
352 committer: test <test@example.org>
352 committer: test <test@example.org>
353
353
354
354
355 changeset: 0:0735477b0224
355 changeset: 0:0735477b0224
356 user: test <test@example.org>
356 user: test <test@example.org>
357 date: Mon Jan 01 00:00:20 2007 +0000
357 date: Mon Jan 01 00:00:20 2007 +0000
358 files: foo
358 files: foo
359 description:
359 description:
360 addfoo
360 addfoo
361
361
362
362
363
363
364 --sourceorder should fail
364 --sourceorder should fail
365
365
366 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
366 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
367 initializing destination git-repo4-sourcesort-hg repository
367 initializing destination git-repo4-sourcesort-hg repository
368 abort: --sourcesort is not supported by this data source
368 abort: --sourcesort is not supported by this data source
369 [255]
369 [255]
370
370
371 test sub modules
371 test sub modules
372
372
373 $ mkdir git-repo5
373 $ mkdir git-repo5
374 $ cd git-repo5
374 $ cd git-repo5
375 $ git init-db >/dev/null 2>/dev/null
375 $ git init-db >/dev/null 2>/dev/null
376 $ echo 'sub' >> foo
376 $ echo 'sub' >> foo
377 $ git add foo
377 $ git add foo
378 $ commit -a -m 'addfoo'
378 $ commit -a -m 'addfoo'
379 $ BASE=`pwd`
379 $ BASE=`pwd`
380 $ cd ..
380 $ cd ..
381 $ mkdir git-repo6
381 $ mkdir git-repo6
382 $ cd git-repo6
382 $ cd git-repo6
383 $ git init-db >/dev/null 2>/dev/null
383 $ git init-db >/dev/null 2>/dev/null
384 $ git submodule add ${BASE} >/dev/null 2>/dev/null
384 $ git submodule add ${BASE} >/dev/null 2>/dev/null
385 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
385 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
386 $ cd ..
386 $ cd ..
387
387
388 test invalid splicemap1
388 test invalid splicemap1
389
389
390 $ cat > splicemap <<EOF
390 $ cat > splicemap <<EOF
391 > $VALIDID1
391 > $VALIDID1
392 > EOF
392 > EOF
393 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap1-hg
393 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap1-hg
394 initializing destination git-repo2-splicemap1-hg repository
394 initializing destination git-repo2-splicemap1-hg repository
395 abort: syntax error in splicemap(1): child parent1[,parent2] expected
395 abort: syntax error in splicemap(1): child parent1[,parent2] expected
396 [255]
396 [255]
397
397
398 test invalid splicemap2
398 test invalid splicemap2
399
399
400 $ cat > splicemap <<EOF
400 $ cat > splicemap <<EOF
401 > $VALIDID1 $VALIDID2, $VALIDID2, $VALIDID2
401 > $VALIDID1 $VALIDID2, $VALIDID2, $VALIDID2
402 > EOF
402 > EOF
403 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap2-hg
403 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap2-hg
404 initializing destination git-repo2-splicemap2-hg repository
404 initializing destination git-repo2-splicemap2-hg repository
405 abort: syntax error in splicemap(1): child parent1[,parent2] expected
405 abort: syntax error in splicemap(1): child parent1[,parent2] expected
406 [255]
406 [255]
407
407
408 test invalid splicemap3
408 test invalid splicemap3
409
409
410 $ cat > splicemap <<EOF
410 $ cat > splicemap <<EOF
411 > $INVALIDID1 $INVALIDID2
411 > $INVALIDID1 $INVALIDID2
412 > EOF
412 > EOF
413 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap3-hg
413 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap3-hg
414 initializing destination git-repo2-splicemap3-hg repository
414 initializing destination git-repo2-splicemap3-hg repository
415 abort: splicemap entry afd12345af is not a valid revision identifier
415 abort: splicemap entry afd12345af is not a valid revision identifier
416 [255]
416 [255]
417
417
418 convert sub modules
418 convert sub modules
419 $ hg convert git-repo6 git-repo6-hg
419 $ hg convert git-repo6 git-repo6-hg
420 initializing destination git-repo6-hg repository
420 initializing destination git-repo6-hg repository
421 scanning source...
421 scanning source...
422 sorting...
422 sorting...
423 converting...
423 converting...
424 0 addsubmodule
424 0 addsubmodule
425 updating bookmarks
425 updating bookmarks
426 $ hg -R git-repo6-hg log -v
426 $ hg -R git-repo6-hg log -v
427 changeset: 0:* (glob)
427 changeset: 0:* (glob)
428 bookmark: master
428 bookmark: master
429 tag: tip
429 tag: tip
430 user: nottest <test@example.org>
430 user: nottest <test@example.org>
431 date: Mon Jan 01 00:00:23 2007 +0000
431 date: Mon Jan 01 00:00:23 2007 +0000
432 files: .hgsub .hgsubstate
432 files: .hgsub .hgsubstate
433 description:
433 description:
434 addsubmodule
434 addsubmodule
435
435
436 committer: test <test@example.org>
436 committer: test <test@example.org>
437
437
438
438
439
439
440 $ cd git-repo6-hg
440 $ cd git-repo6-hg
441 $ hg up >/dev/null 2>/dev/null
441 $ hg up >/dev/null 2>/dev/null
442 $ cat .hgsubstate
442 $ cat .hgsubstate
443 * git-repo5 (glob)
443 * git-repo5 (glob)
444 $ cd git-repo5
444 $ cd git-repo5
445 $ cat foo
445 $ cat foo
446 sub
446 sub
447
447
448 $ cd ../..
448 $ cd ../..
449
449
450 make sure rename detection doesn't break removing and adding gitmodules
450 make sure rename detection doesn't break removing and adding gitmodules
451
451
452 $ cd git-repo6
452 $ cd git-repo6
453 $ git mv .gitmodules .gitmodules-renamed
453 $ git mv .gitmodules .gitmodules-renamed
454 $ commit -a -m 'rename .gitmodules'
454 $ commit -a -m 'rename .gitmodules'
455 $ git mv .gitmodules-renamed .gitmodules
455 $ git mv .gitmodules-renamed .gitmodules
456 $ commit -a -m 'rename .gitmodules back'
456 $ commit -a -m 'rename .gitmodules back'
457 $ cd ..
457 $ cd ..
458
458
459 $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg
459 $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg
460 $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n"
460 $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n"
461 rename .gitmodules
461 rename .gitmodules
462 $ hg -R git-repo6-hg status -C --change 'tip^'
462 $ hg -R git-repo6-hg status -C --change 'tip^'
463 A .gitmodules-renamed
463 A .gitmodules-renamed
464 R .hgsub
464 R .hgsub
465 R .hgsubstate
465 R .hgsubstate
466 $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n"
466 $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n"
467 rename .gitmodules back
467 rename .gitmodules back
468 $ hg -R git-repo6-hg status -C --change tip
468 $ hg -R git-repo6-hg status -C --change tip
469 A .hgsub
469 A .hgsub
470 A .hgsubstate
470 A .hgsubstate
471 R .gitmodules-renamed
471 R .gitmodules-renamed
472
472
473 convert the revision removing '.gitmodules' itself (and related
473 convert the revision removing '.gitmodules' itself (and related
474 submodules)
474 submodules)
475
475
476 $ cd git-repo6
476 $ cd git-repo6
477 $ git rm .gitmodules
477 $ git rm .gitmodules
478 rm '.gitmodules'
478 rm '.gitmodules'
479 $ git rm --cached git-repo5
479 $ git rm --cached git-repo5
480 rm 'git-repo5'
480 rm 'git-repo5'
481 $ commit -a -m 'remove .gitmodules and submodule git-repo5'
481 $ commit -a -m 'remove .gitmodules and submodule git-repo5'
482 $ cd ..
482 $ cd ..
483
483
484 $ hg convert -q git-repo6 git-repo6-hg
484 $ hg convert -q git-repo6 git-repo6-hg
485 $ hg -R git-repo6-hg tip -T "{desc|firstline}\n"
485 $ hg -R git-repo6-hg tip -T "{desc|firstline}\n"
486 remove .gitmodules and submodule git-repo5
486 remove .gitmodules and submodule git-repo5
487 $ hg -R git-repo6-hg tip -T "{file_dels}\n"
487 $ hg -R git-repo6-hg tip -T "{file_dels}\n"
488 .hgsub .hgsubstate
488 .hgsub .hgsubstate
489
489
490 damaged git repository tests:
490 damaged git repository tests:
491 In case the hard-coded hashes change, the following commands can be used to
491 In case the hard-coded hashes change, the following commands can be used to
492 list the hashes and their corresponding types in the repository:
492 list the hashes and their corresponding types in the repository:
493 cd git-repo4/.git/objects
493 cd git-repo4/.git/objects
494 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
494 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
495 cd ../../..
495 cd ../../..
496
496
497 damage git repository by renaming a commit object
497 damage git repository by renaming a commit object
498 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
498 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
499 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
499 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
500 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
500 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
501 abort: cannot read tags from git-repo4/.git
501 abort: cannot read tags from git-repo4/.git
502 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
502 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
503 damage git repository by renaming a blob object
503 damage git repository by renaming a blob object
504
504
505 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
505 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
506 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
506 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
507 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
507 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
508 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
508 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
509 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
509 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
510 damage git repository by renaming a tree object
510 damage git repository by renaming a tree object
511
511
512 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
512 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
513 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
513 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
514 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
514 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
515 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
515 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
General Comments 0
You need to be logged in to leave comments. Login now