##// END OF EJS Templates
convert: handle .gitmodules with non-tab whitespaces...
Durham Goode -
r25698:307370c2 default
parent child Browse files
Show More
@@ -1,385 +1,386 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 # The default value (50) is based on the default for 'git diff'.
97 # The default value (50) is based on the default for 'git diff'.
98 similarity = ui.configint('convert', 'git.similarity', default=50)
98 similarity = ui.configint('convert', 'git.similarity', default=50)
99 if similarity < 0 or similarity > 100:
99 if similarity < 0 or similarity > 100:
100 raise util.Abort(_('similarity must be between 0 and 100'))
100 raise util.Abort(_('similarity must be between 0 and 100'))
101 if similarity > 0:
101 if similarity > 0:
102 self.simopt = '-C%d%%' % similarity
102 self.simopt = '-C%d%%' % similarity
103 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder',
103 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder',
104 False)
104 False)
105 if findcopiesharder:
105 if findcopiesharder:
106 self.simopt += ' --find-copies-harder'
106 self.simopt += ' --find-copies-harder'
107 else:
107 else:
108 self.simopt = ''
108 self.simopt = ''
109
109
110 checktool('git', 'git')
110 checktool('git', 'git')
111
111
112 self.path = path
112 self.path = path
113 self.submodules = []
113 self.submodules = []
114
114
115 self.catfilepipe = self.gitpipe('git cat-file --batch')
115 self.catfilepipe = self.gitpipe('git cat-file --batch')
116
116
117 def after(self):
117 def after(self):
118 for f in self.catfilepipe:
118 for f in self.catfilepipe:
119 f.close()
119 f.close()
120
120
121 def getheads(self):
121 def getheads(self):
122 if not self.rev:
122 if not self.rev:
123 heads, ret = self.gitread('git rev-parse --branches --remotes')
123 heads, ret = self.gitread('git rev-parse --branches --remotes')
124 heads = heads.splitlines()
124 heads = heads.splitlines()
125 else:
125 else:
126 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
126 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
127 heads = [heads[:-1]]
127 heads = [heads[:-1]]
128 if ret:
128 if ret:
129 raise util.Abort(_('cannot retrieve git heads'))
129 raise util.Abort(_('cannot retrieve git heads'))
130 return heads
130 return heads
131
131
132 def catfile(self, rev, type):
132 def catfile(self, rev, type):
133 if rev == hex(nullid):
133 if rev == hex(nullid):
134 raise IOError
134 raise IOError
135 self.catfilepipe[0].write(rev+'\n')
135 self.catfilepipe[0].write(rev+'\n')
136 self.catfilepipe[0].flush()
136 self.catfilepipe[0].flush()
137 info = self.catfilepipe[1].readline().split()
137 info = self.catfilepipe[1].readline().split()
138 if info[1] != type:
138 if info[1] != type:
139 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
139 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
140 size = int(info[2])
140 size = int(info[2])
141 data = self.catfilepipe[1].read(size)
141 data = self.catfilepipe[1].read(size)
142 if len(data) < size:
142 if len(data) < size:
143 raise util.Abort(_('cannot read %r object at %s: unexpected size')
143 raise util.Abort(_('cannot read %r object at %s: unexpected size')
144 % (type, rev))
144 % (type, rev))
145 # read the trailing newline
145 # read the trailing newline
146 self.catfilepipe[1].read(1)
146 self.catfilepipe[1].read(1)
147 return data
147 return data
148
148
149 def getfile(self, name, rev):
149 def getfile(self, name, rev):
150 if rev == hex(nullid):
150 if rev == hex(nullid):
151 return None, None
151 return None, None
152 if name == '.hgsub':
152 if name == '.hgsub':
153 data = '\n'.join([m.hgsub() for m in self.submoditer()])
153 data = '\n'.join([m.hgsub() for m in self.submoditer()])
154 mode = ''
154 mode = ''
155 elif name == '.hgsubstate':
155 elif name == '.hgsubstate':
156 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
156 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
157 mode = ''
157 mode = ''
158 else:
158 else:
159 data = self.catfile(rev, "blob")
159 data = self.catfile(rev, "blob")
160 mode = self.modecache[(name, rev)]
160 mode = self.modecache[(name, rev)]
161 return data, mode
161 return data, mode
162
162
163 def submoditer(self):
163 def submoditer(self):
164 null = hex(nullid)
164 null = hex(nullid)
165 for m in sorted(self.submodules, key=lambda p: p.path):
165 for m in sorted(self.submodules, key=lambda p: p.path):
166 if m.node != null:
166 if m.node != null:
167 yield m
167 yield m
168
168
169 def parsegitmodules(self, content):
169 def parsegitmodules(self, content):
170 """Parse the formatted .gitmodules file, example file format:
170 """Parse the formatted .gitmodules file, example file format:
171 [submodule "sub"]\n
171 [submodule "sub"]\n
172 \tpath = sub\n
172 \tpath = sub\n
173 \turl = git://giturl\n
173 \turl = git://giturl\n
174 """
174 """
175 self.submodules = []
175 self.submodules = []
176 c = config.config()
176 c = config.config()
177 # Each item in .gitmodules starts with \t that cant be parsed
177 # Each item in .gitmodules starts with whitespace that cant be parsed
178 c.parse('.gitmodules', content.replace('\t',''))
178 c.parse('.gitmodules', '\n'.join(line.strip() for line in
179 content.split('\n')))
179 for sec in c.sections():
180 for sec in c.sections():
180 s = c[sec]
181 s = c[sec]
181 if 'url' in s and 'path' in s:
182 if 'url' in s and 'path' in s:
182 self.submodules.append(submodule(s['path'], '', s['url']))
183 self.submodules.append(submodule(s['path'], '', s['url']))
183
184
184 def retrievegitmodules(self, version):
185 def retrievegitmodules(self, version):
185 modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
186 modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
186 if ret:
187 if ret:
187 raise util.Abort(_('cannot read submodules config file in %s') %
188 raise util.Abort(_('cannot read submodules config file in %s') %
188 version)
189 version)
189 self.parsegitmodules(modules)
190 self.parsegitmodules(modules)
190 for m in self.submodules:
191 for m in self.submodules:
191 node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
192 node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
192 if ret:
193 if ret:
193 continue
194 continue
194 m.node = node.strip()
195 m.node = node.strip()
195
196
196 def getchanges(self, version, full):
197 def getchanges(self, version, full):
197 if full:
198 if full:
198 raise util.Abort(_("convert from git do not support --full"))
199 raise util.Abort(_("convert from git do not support --full"))
199 self.modecache = {}
200 self.modecache = {}
200 fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % (
201 fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % (
201 self.simopt, version))
202 self.simopt, version))
202 changes = []
203 changes = []
203 copies = {}
204 copies = {}
204 seen = set()
205 seen = set()
205 entry = None
206 entry = None
206 subexists = [False]
207 subexists = [False]
207 subdeleted = [False]
208 subdeleted = [False]
208 difftree = fh.read().split('\x00')
209 difftree = fh.read().split('\x00')
209 lcount = len(difftree)
210 lcount = len(difftree)
210 i = 0
211 i = 0
211
212
212 def add(entry, f, isdest):
213 def add(entry, f, isdest):
213 seen.add(f)
214 seen.add(f)
214 h = entry[3]
215 h = entry[3]
215 p = (entry[1] == "100755")
216 p = (entry[1] == "100755")
216 s = (entry[1] == "120000")
217 s = (entry[1] == "120000")
217 renamesource = (not isdest and entry[4][0] == 'R')
218 renamesource = (not isdest and entry[4][0] == 'R')
218
219
219 if f == '.gitmodules':
220 if f == '.gitmodules':
220 subexists[0] = True
221 subexists[0] = True
221 if entry[4] == 'D' or renamesource:
222 if entry[4] == 'D' or renamesource:
222 subdeleted[0] = True
223 subdeleted[0] = True
223 changes.append(('.hgsub', hex(nullid)))
224 changes.append(('.hgsub', hex(nullid)))
224 else:
225 else:
225 changes.append(('.hgsub', ''))
226 changes.append(('.hgsub', ''))
226 elif entry[1] == '160000' or entry[0] == ':160000':
227 elif entry[1] == '160000' or entry[0] == ':160000':
227 subexists[0] = True
228 subexists[0] = True
228 else:
229 else:
229 if renamesource:
230 if renamesource:
230 h = hex(nullid)
231 h = hex(nullid)
231 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
232 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
232 changes.append((f, h))
233 changes.append((f, h))
233
234
234 while i < lcount:
235 while i < lcount:
235 l = difftree[i]
236 l = difftree[i]
236 i += 1
237 i += 1
237 if not entry:
238 if not entry:
238 if not l.startswith(':'):
239 if not l.startswith(':'):
239 continue
240 continue
240 entry = l.split()
241 entry = l.split()
241 continue
242 continue
242 f = l
243 f = l
243 if f not in seen:
244 if f not in seen:
244 add(entry, f, False)
245 add(entry, f, False)
245 # A file can be copied multiple times, or modified and copied
246 # A file can be copied multiple times, or modified and copied
246 # simultaneously. So f can be repeated even if fdest isn't.
247 # simultaneously. So f can be repeated even if fdest isn't.
247 if entry[4][0] in 'RC':
248 if entry[4][0] in 'RC':
248 # rename or copy: next line is the destination
249 # rename or copy: next line is the destination
249 fdest = difftree[i]
250 fdest = difftree[i]
250 i += 1
251 i += 1
251 if fdest not in seen:
252 if fdest not in seen:
252 add(entry, fdest, True)
253 add(entry, fdest, True)
253 # .gitmodules isn't imported at all, so it being copied to
254 # .gitmodules isn't imported at all, so it being copied to
254 # and fro doesn't really make sense
255 # and fro doesn't really make sense
255 if f != '.gitmodules' and fdest != '.gitmodules':
256 if f != '.gitmodules' and fdest != '.gitmodules':
256 copies[fdest] = f
257 copies[fdest] = f
257 entry = None
258 entry = None
258 if fh.close():
259 if fh.close():
259 raise util.Abort(_('cannot read changes in %s') % version)
260 raise util.Abort(_('cannot read changes in %s') % version)
260
261
261 if subexists[0]:
262 if subexists[0]:
262 if subdeleted[0]:
263 if subdeleted[0]:
263 changes.append(('.hgsubstate', hex(nullid)))
264 changes.append(('.hgsubstate', hex(nullid)))
264 else:
265 else:
265 self.retrievegitmodules(version)
266 self.retrievegitmodules(version)
266 changes.append(('.hgsubstate', ''))
267 changes.append(('.hgsubstate', ''))
267 return (changes, copies, set())
268 return (changes, copies, set())
268
269
269 def getcommit(self, version):
270 def getcommit(self, version):
270 c = self.catfile(version, "commit") # read the commit hash
271 c = self.catfile(version, "commit") # read the commit hash
271 end = c.find("\n\n")
272 end = c.find("\n\n")
272 message = c[end + 2:]
273 message = c[end + 2:]
273 message = self.recode(message)
274 message = self.recode(message)
274 l = c[:end].splitlines()
275 l = c[:end].splitlines()
275 parents = []
276 parents = []
276 author = committer = None
277 author = committer = None
277 for e in l[1:]:
278 for e in l[1:]:
278 n, v = e.split(" ", 1)
279 n, v = e.split(" ", 1)
279 if n == "author":
280 if n == "author":
280 p = v.split()
281 p = v.split()
281 tm, tz = p[-2:]
282 tm, tz = p[-2:]
282 author = " ".join(p[:-2])
283 author = " ".join(p[:-2])
283 if author[0] == "<": author = author[1:-1]
284 if author[0] == "<": author = author[1:-1]
284 author = self.recode(author)
285 author = self.recode(author)
285 if n == "committer":
286 if n == "committer":
286 p = v.split()
287 p = v.split()
287 tm, tz = p[-2:]
288 tm, tz = p[-2:]
288 committer = " ".join(p[:-2])
289 committer = " ".join(p[:-2])
289 if committer[0] == "<": committer = committer[1:-1]
290 if committer[0] == "<": committer = committer[1:-1]
290 committer = self.recode(committer)
291 committer = self.recode(committer)
291 if n == "parent":
292 if n == "parent":
292 parents.append(v)
293 parents.append(v)
293
294
294 if committer and committer != author:
295 if committer and committer != author:
295 message += "\ncommitter: %s\n" % committer
296 message += "\ncommitter: %s\n" % committer
296 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
297 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
297 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
298 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
298 date = tm + " " + str(tz)
299 date = tm + " " + str(tz)
299
300
300 c = commit(parents=parents, date=date, author=author, desc=message,
301 c = commit(parents=parents, date=date, author=author, desc=message,
301 rev=version)
302 rev=version)
302 return c
303 return c
303
304
304 def numcommits(self):
305 def numcommits(self):
305 return len([None for _ in self.gitopen('git rev-list --all')])
306 return len([None for _ in self.gitopen('git rev-list --all')])
306
307
307 def gettags(self):
308 def gettags(self):
308 tags = {}
309 tags = {}
309 alltags = {}
310 alltags = {}
310 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
311 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
311 err=subprocess.STDOUT)
312 err=subprocess.STDOUT)
312 prefix = 'refs/tags/'
313 prefix = 'refs/tags/'
313
314
314 # Build complete list of tags, both annotated and bare ones
315 # Build complete list of tags, both annotated and bare ones
315 for line in fh:
316 for line in fh:
316 line = line.strip()
317 line = line.strip()
317 if line.startswith("error:") or line.startswith("fatal:"):
318 if line.startswith("error:") or line.startswith("fatal:"):
318 raise util.Abort(_('cannot read tags from %s') % self.path)
319 raise util.Abort(_('cannot read tags from %s') % self.path)
319 node, tag = line.split(None, 1)
320 node, tag = line.split(None, 1)
320 if not tag.startswith(prefix):
321 if not tag.startswith(prefix):
321 continue
322 continue
322 alltags[tag[len(prefix):]] = node
323 alltags[tag[len(prefix):]] = node
323 if fh.close():
324 if fh.close():
324 raise util.Abort(_('cannot read tags from %s') % self.path)
325 raise util.Abort(_('cannot read tags from %s') % self.path)
325
326
326 # Filter out tag objects for annotated tag refs
327 # Filter out tag objects for annotated tag refs
327 for tag in alltags:
328 for tag in alltags:
328 if tag.endswith('^{}'):
329 if tag.endswith('^{}'):
329 tags[tag[:-3]] = alltags[tag]
330 tags[tag[:-3]] = alltags[tag]
330 else:
331 else:
331 if tag + '^{}' in alltags:
332 if tag + '^{}' in alltags:
332 continue
333 continue
333 else:
334 else:
334 tags[tag] = alltags[tag]
335 tags[tag] = alltags[tag]
335
336
336 return tags
337 return tags
337
338
338 def getchangedfiles(self, version, i):
339 def getchangedfiles(self, version, i):
339 changes = []
340 changes = []
340 if i is None:
341 if i is None:
341 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
342 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
342 for l in fh:
343 for l in fh:
343 if "\t" not in l:
344 if "\t" not in l:
344 continue
345 continue
345 m, f = l[:-1].split("\t")
346 m, f = l[:-1].split("\t")
346 changes.append(f)
347 changes.append(f)
347 else:
348 else:
348 fh = self.gitopen('git diff-tree --name-only --root -r %s '
349 fh = self.gitopen('git diff-tree --name-only --root -r %s '
349 '"%s^%s" --' % (version, version, i + 1))
350 '"%s^%s" --' % (version, version, i + 1))
350 changes = [f.rstrip('\n') for f in fh]
351 changes = [f.rstrip('\n') for f in fh]
351 if fh.close():
352 if fh.close():
352 raise util.Abort(_('cannot read changes in %s') % version)
353 raise util.Abort(_('cannot read changes in %s') % version)
353
354
354 return changes
355 return changes
355
356
356 def getbookmarks(self):
357 def getbookmarks(self):
357 bookmarks = {}
358 bookmarks = {}
358
359
359 # Interesting references in git are prefixed
360 # Interesting references in git are prefixed
360 prefix = 'refs/heads/'
361 prefix = 'refs/heads/'
361 prefixlen = len(prefix)
362 prefixlen = len(prefix)
362
363
363 # factor two commands
364 # factor two commands
364 gitcmd = { 'remote/': 'git ls-remote --heads origin',
365 gitcmd = { 'remote/': 'git ls-remote --heads origin',
365 '': 'git show-ref'}
366 '': 'git show-ref'}
366
367
367 # Origin heads
368 # Origin heads
368 for reftype in gitcmd:
369 for reftype in gitcmd:
369 try:
370 try:
370 fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
371 fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
371 for line in fh:
372 for line in fh:
372 line = line.strip()
373 line = line.strip()
373 rev, name = line.split(None, 1)
374 rev, name = line.split(None, 1)
374 if not name.startswith(prefix):
375 if not name.startswith(prefix):
375 continue
376 continue
376 name = '%s%s' % (reftype, name[prefixlen:])
377 name = '%s%s' % (reftype, name[prefixlen:])
377 bookmarks[name] = rev
378 bookmarks[name] = rev
378 except Exception:
379 except Exception:
379 pass
380 pass
380
381
381 return bookmarks
382 return bookmarks
382
383
383 def checkrevformat(self, revstr, mapname='splicemap'):
384 def checkrevformat(self, revstr, mapname='splicemap'):
384 """ git revision string is a 40 byte hex """
385 """ git revision string is a 40 byte hex """
385 self.checkhexformat(revstr, mapname)
386 self.checkhexformat(revstr, mapname)
@@ -1,589 +1,614 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 convert --datesort git-repo2 fullrepo \
173 $ hg convert --datesort git-repo2 fullrepo \
174 > --config extensions.progress= --config progress.assume-tty=1 \
174 > --config extensions.progress= --config progress.assume-tty=1 \
175 > --config progress.delay=0 --config progress.changedelay=0 \
175 > --config progress.delay=0 --config progress.changedelay=0 \
176 > --config progress.refresh=0 --config progress.width=60
176 > --config progress.refresh=0 --config progress.width=60
177 \r (no-eol) (esc)
177 \r (no-eol) (esc)
178 scanning [===> ] 1/9\r (no-eol) (esc)
178 scanning [===> ] 1/9\r (no-eol) (esc)
179 scanning [========> ] 2/9\r (no-eol) (esc)
179 scanning [========> ] 2/9\r (no-eol) (esc)
180 scanning [=============> ] 3/9\r (no-eol) (esc)
180 scanning [=============> ] 3/9\r (no-eol) (esc)
181 scanning [==================> ] 4/9\r (no-eol) (esc)
181 scanning [==================> ] 4/9\r (no-eol) (esc)
182 scanning [=======================> ] 5/9\r (no-eol) (esc)
182 scanning [=======================> ] 5/9\r (no-eol) (esc)
183 scanning [============================> ] 6/9\r (no-eol) (esc)
183 scanning [============================> ] 6/9\r (no-eol) (esc)
184 scanning [=================================> ] 7/9\r (no-eol) (esc)
184 scanning [=================================> ] 7/9\r (no-eol) (esc)
185 scanning [======================================> ] 8/9\r (no-eol) (esc)
185 scanning [======================================> ] 8/9\r (no-eol) (esc)
186 scanning [===========================================>] 9/9\r (no-eol) (esc)
186 scanning [===========================================>] 9/9\r (no-eol) (esc)
187 \r (no-eol) (esc)
187 \r (no-eol) (esc)
188 \r (no-eol) (esc)
188 \r (no-eol) (esc)
189 converting [ ] 0/9\r (no-eol) (esc)
189 converting [ ] 0/9\r (no-eol) (esc)
190 getting files [======================================>] 1/1\r (no-eol) (esc)
190 getting files [======================================>] 1/1\r (no-eol) (esc)
191 \r (no-eol) (esc)
191 \r (no-eol) (esc)
192 \r (no-eol) (esc)
192 \r (no-eol) (esc)
193 converting [===> ] 1/9\r (no-eol) (esc)
193 converting [===> ] 1/9\r (no-eol) (esc)
194 getting files [======================================>] 1/1\r (no-eol) (esc)
194 getting files [======================================>] 1/1\r (no-eol) (esc)
195 \r (no-eol) (esc)
195 \r (no-eol) (esc)
196 \r (no-eol) (esc)
196 \r (no-eol) (esc)
197 converting [========> ] 2/9\r (no-eol) (esc)
197 converting [========> ] 2/9\r (no-eol) (esc)
198 getting files [======================================>] 1/1\r (no-eol) (esc)
198 getting files [======================================>] 1/1\r (no-eol) (esc)
199 \r (no-eol) (esc)
199 \r (no-eol) (esc)
200 \r (no-eol) (esc)
200 \r (no-eol) (esc)
201 converting [=============> ] 3/9\r (no-eol) (esc)
201 converting [=============> ] 3/9\r (no-eol) (esc)
202 getting files [======================================>] 1/1\r (no-eol) (esc)
202 getting files [======================================>] 1/1\r (no-eol) (esc)
203 \r (no-eol) (esc)
203 \r (no-eol) (esc)
204 \r (no-eol) (esc)
204 \r (no-eol) (esc)
205 converting [=================> ] 4/9\r (no-eol) (esc)
205 converting [=================> ] 4/9\r (no-eol) (esc)
206 getting files [======================================>] 1/1\r (no-eol) (esc)
206 getting files [======================================>] 1/1\r (no-eol) (esc)
207 \r (no-eol) (esc)
207 \r (no-eol) (esc)
208 \r (no-eol) (esc)
208 \r (no-eol) (esc)
209 converting [======================> ] 5/9\r (no-eol) (esc)
209 converting [======================> ] 5/9\r (no-eol) (esc)
210 getting files [===> ] 1/8\r (no-eol) (esc)
210 getting files [===> ] 1/8\r (no-eol) (esc)
211 getting files [========> ] 2/8\r (no-eol) (esc)
211 getting files [========> ] 2/8\r (no-eol) (esc)
212 getting files [=============> ] 3/8\r (no-eol) (esc)
212 getting files [=============> ] 3/8\r (no-eol) (esc)
213 getting files [==================> ] 4/8\r (no-eol) (esc)
213 getting files [==================> ] 4/8\r (no-eol) (esc)
214 getting files [=======================> ] 5/8\r (no-eol) (esc)
214 getting files [=======================> ] 5/8\r (no-eol) (esc)
215 getting files [============================> ] 6/8\r (no-eol) (esc)
215 getting files [============================> ] 6/8\r (no-eol) (esc)
216 getting files [=================================> ] 7/8\r (no-eol) (esc)
216 getting files [=================================> ] 7/8\r (no-eol) (esc)
217 getting files [======================================>] 8/8\r (no-eol) (esc)
217 getting files [======================================>] 8/8\r (no-eol) (esc)
218 \r (no-eol) (esc)
218 \r (no-eol) (esc)
219 \r (no-eol) (esc)
219 \r (no-eol) (esc)
220 converting [===========================> ] 6/9\r (no-eol) (esc)
220 converting [===========================> ] 6/9\r (no-eol) (esc)
221 getting files [======================================>] 1/1\r (no-eol) (esc)
221 getting files [======================================>] 1/1\r (no-eol) (esc)
222 \r (no-eol) (esc)
222 \r (no-eol) (esc)
223 \r (no-eol) (esc)
223 \r (no-eol) (esc)
224 converting [===============================> ] 7/9\r (no-eol) (esc)
224 converting [===============================> ] 7/9\r (no-eol) (esc)
225 getting files [======================================>] 1/1\r (no-eol) (esc)
225 getting files [======================================>] 1/1\r (no-eol) (esc)
226 \r (no-eol) (esc)
226 \r (no-eol) (esc)
227 \r (no-eol) (esc)
227 \r (no-eol) (esc)
228 converting [====================================> ] 8/9\r (no-eol) (esc)
228 converting [====================================> ] 8/9\r (no-eol) (esc)
229 getting files [==================> ] 1/2\r (no-eol) (esc)
229 getting files [==================> ] 1/2\r (no-eol) (esc)
230 getting files [======================================>] 2/2\r (no-eol) (esc)
230 getting files [======================================>] 2/2\r (no-eol) (esc)
231 \r (no-eol) (esc)
231 \r (no-eol) (esc)
232 initializing destination fullrepo repository
232 initializing destination fullrepo repository
233 scanning source...
233 scanning source...
234 sorting...
234 sorting...
235 converting...
235 converting...
236 8 add foo
236 8 add foo
237 7 change foo
237 7 change foo
238 6 add quux
238 6 add quux
239 5 add bar
239 5 add bar
240 4 add baz
240 4 add baz
241 3 Octopus merge
241 3 Octopus merge
242 2 change bar
242 2 change bar
243 1 change foo
243 1 change foo
244 0 Discard change to foo
244 0 Discard change to foo
245 updating bookmarks
245 updating bookmarks
246 $ hg up -q -R fullrepo
246 $ hg up -q -R fullrepo
247 $ glog -R fullrepo
247 $ glog -R fullrepo
248 @ 9 "Discard change to foo" files: foo
248 @ 9 "Discard change to foo" files: foo
249 |\
249 |\
250 | o 8 "change foo" files: foo
250 | o 8 "change foo" files: foo
251 | |
251 | |
252 o | 7 "change bar" files: bar
252 o | 7 "change bar" files: bar
253 |/
253 |/
254 o 6 "(octopus merge fixup)" files:
254 o 6 "(octopus merge fixup)" files:
255 |\
255 |\
256 | o 5 "Octopus merge" files: baz
256 | o 5 "Octopus merge" files: baz
257 | |\
257 | |\
258 o | | 4 "add baz" files: baz
258 o | | 4 "add baz" files: baz
259 | | |
259 | | |
260 +---o 3 "add bar" files: bar
260 +---o 3 "add bar" files: bar
261 | |
261 | |
262 o | 2 "add quux" files: quux
262 o | 2 "add quux" files: quux
263 | |
263 | |
264 | o 1 "change foo" files: foo
264 | o 1 "change foo" files: foo
265 |/
265 |/
266 o 0 "add foo" files: foo
266 o 0 "add foo" files: foo
267
267
268 $ hg -R fullrepo manifest --debug
268 $ hg -R fullrepo manifest --debug
269 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
269 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
270 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
270 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
271 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
271 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
272 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
272 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
273 $ splitrepo 'octopus merge' 'foo bar baz'
273 $ splitrepo 'octopus merge' 'foo bar baz'
274 % foo bar baz: octopus merge
274 % foo bar baz: octopus merge
275 @ 8 "Discard change to foo" files: foo
275 @ 8 "Discard change to foo" files: foo
276 |\
276 |\
277 | o 7 "change foo" files: foo
277 | o 7 "change foo" files: foo
278 | |
278 | |
279 o | 6 "change bar" files: bar
279 o | 6 "change bar" files: bar
280 |/
280 |/
281 o 5 "(octopus merge fixup)" files:
281 o 5 "(octopus merge fixup)" files:
282 |\
282 |\
283 | o 4 "Octopus merge" files: baz
283 | o 4 "Octopus merge" files: baz
284 | |\
284 | |\
285 o | | 3 "add baz" files: baz
285 o | | 3 "add baz" files: baz
286 | | |
286 | | |
287 +---o 2 "add bar" files: bar
287 +---o 2 "add bar" files: bar
288 | |
288 | |
289 | o 1 "change foo" files: foo
289 | o 1 "change foo" files: foo
290 |/
290 |/
291 o 0 "add foo" files: foo
291 o 0 "add foo" files: foo
292
292
293 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
293 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
294 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
294 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
295 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
295 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
296 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
296 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
297 % foo baz quux: only some parents of an octopus merge; "discard" a head
297 % foo baz quux: only some parents of an octopus merge; "discard" a head
298 @ 6 "Discard change to foo" files: foo
298 @ 6 "Discard change to foo" files: foo
299 |
299 |
300 o 5 "change foo" files: foo
300 o 5 "change foo" files: foo
301 |
301 |
302 o 4 "Octopus merge" files:
302 o 4 "Octopus merge" files:
303 |\
303 |\
304 | o 3 "add baz" files: baz
304 | o 3 "add baz" files: baz
305 | |
305 | |
306 | o 2 "add quux" files: quux
306 | o 2 "add quux" files: quux
307 | |
307 | |
308 o | 1 "change foo" files: foo
308 o | 1 "change foo" files: foo
309 |/
309 |/
310 o 0 "add foo" files: foo
310 o 0 "add foo" files: foo
311
311
312 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
312 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
313 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
313 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
314 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
314 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
315
315
316 test importing git renames and copies
316 test importing git renames and copies
317
317
318 $ cd git-repo2
318 $ cd git-repo2
319 $ git mv foo foo-renamed
319 $ git mv foo foo-renamed
320 since bar is not touched in this commit, this copy will not be detected
320 since bar is not touched in this commit, this copy will not be detected
321 $ cp bar bar-copied
321 $ cp bar bar-copied
322 $ cp baz baz-copied
322 $ cp baz baz-copied
323 $ cp baz baz-copied2
323 $ cp baz baz-copied2
324 $ echo baz2 >> baz
324 $ echo baz2 >> baz
325 $ git add bar-copied baz-copied baz-copied2
325 $ git add bar-copied baz-copied baz-copied2
326 $ commit -a -m 'rename and copy'
326 $ commit -a -m 'rename and copy'
327 $ cd ..
327 $ cd ..
328
328
329 input validation
329 input validation
330 $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo
330 $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo
331 abort: convert.git.similarity is not an integer ('foo')
331 abort: convert.git.similarity is not an integer ('foo')
332 [255]
332 [255]
333 $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo
333 $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo
334 abort: similarity must be between 0 and 100
334 abort: similarity must be between 0 and 100
335 [255]
335 [255]
336 $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo
336 $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo
337 abort: similarity must be between 0 and 100
337 abort: similarity must be between 0 and 100
338 [255]
338 [255]
339
339
340 $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo
340 $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo
341 $ hg -R fullrepo status -C --change master
341 $ hg -R fullrepo status -C --change master
342 M baz
342 M baz
343 A bar-copied
343 A bar-copied
344 A baz-copied
344 A baz-copied
345 baz
345 baz
346 A baz-copied2
346 A baz-copied2
347 baz
347 baz
348 A foo-renamed
348 A foo-renamed
349 foo
349 foo
350 R foo
350 R foo
351
351
352 $ cd git-repo2
352 $ cd git-repo2
353 $ echo bar2 >> bar
353 $ echo bar2 >> bar
354 $ commit -a -m 'change bar'
354 $ commit -a -m 'change bar'
355 $ cp bar bar-copied2
355 $ cp bar bar-copied2
356 $ git add bar-copied2
356 $ git add bar-copied2
357 $ commit -a -m 'copy with no changes'
357 $ commit -a -m 'copy with no changes'
358 $ cd ..
358 $ cd ..
359
359
360 $ hg -q convert --config convert.git.similarity=100 \
360 $ hg -q convert --config convert.git.similarity=100 \
361 > --config convert.git.findcopiesharder=1 --datesort git-repo2 fullrepo
361 > --config convert.git.findcopiesharder=1 --datesort git-repo2 fullrepo
362 $ hg -R fullrepo status -C --change master
362 $ hg -R fullrepo status -C --change master
363 A bar-copied2
363 A bar-copied2
364 bar
364 bar
365
365
366 test binary conversion (issue1359)
366 test binary conversion (issue1359)
367
367
368 $ count=19
368 $ count=19
369 $ mkdir git-repo3
369 $ mkdir git-repo3
370 $ cd git-repo3
370 $ cd git-repo3
371 $ git init-db >/dev/null 2>/dev/null
371 $ git init-db >/dev/null 2>/dev/null
372 $ $PYTHON -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
372 $ $PYTHON -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
373 $ git add b
373 $ git add b
374 $ commit -a -m addbinary
374 $ commit -a -m addbinary
375 $ cd ..
375 $ cd ..
376
376
377 convert binary file
377 convert binary file
378
378
379 $ hg convert git-repo3 git-repo3-hg
379 $ hg convert git-repo3 git-repo3-hg
380 initializing destination git-repo3-hg repository
380 initializing destination git-repo3-hg repository
381 scanning source...
381 scanning source...
382 sorting...
382 sorting...
383 converting...
383 converting...
384 0 addbinary
384 0 addbinary
385 updating bookmarks
385 updating bookmarks
386 $ cd git-repo3-hg
386 $ cd git-repo3-hg
387 $ hg up -C
387 $ hg up -C
388 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
388 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
389 $ $PYTHON -c 'print len(file("b", "rb").read())'
389 $ $PYTHON -c 'print len(file("b", "rb").read())'
390 4096
390 4096
391 $ cd ..
391 $ cd ..
392
392
393 test author vs committer
393 test author vs committer
394
394
395 $ mkdir git-repo4
395 $ mkdir git-repo4
396 $ cd git-repo4
396 $ cd git-repo4
397 $ git init-db >/dev/null 2>/dev/null
397 $ git init-db >/dev/null 2>/dev/null
398 $ echo >> foo
398 $ echo >> foo
399 $ git add foo
399 $ git add foo
400 $ commit -a -m addfoo
400 $ commit -a -m addfoo
401 $ echo >> foo
401 $ echo >> foo
402 $ GIT_AUTHOR_NAME="nottest"
402 $ GIT_AUTHOR_NAME="nottest"
403 $ commit -a -m addfoo2
403 $ commit -a -m addfoo2
404 $ cd ..
404 $ cd ..
405
405
406 convert author committer
406 convert author committer
407
407
408 $ hg convert git-repo4 git-repo4-hg
408 $ hg convert git-repo4 git-repo4-hg
409 initializing destination git-repo4-hg repository
409 initializing destination git-repo4-hg repository
410 scanning source...
410 scanning source...
411 sorting...
411 sorting...
412 converting...
412 converting...
413 1 addfoo
413 1 addfoo
414 0 addfoo2
414 0 addfoo2
415 updating bookmarks
415 updating bookmarks
416 $ hg -R git-repo4-hg log -v
416 $ hg -R git-repo4-hg log -v
417 changeset: 1:d63e967f93da
417 changeset: 1:d63e967f93da
418 bookmark: master
418 bookmark: master
419 tag: tip
419 tag: tip
420 user: nottest <test@example.org>
420 user: nottest <test@example.org>
421 date: Mon Jan 01 00:00:21 2007 +0000
421 date: Mon Jan 01 00:00:21 2007 +0000
422 files: foo
422 files: foo
423 description:
423 description:
424 addfoo2
424 addfoo2
425
425
426 committer: test <test@example.org>
426 committer: test <test@example.org>
427
427
428
428
429 changeset: 0:0735477b0224
429 changeset: 0:0735477b0224
430 user: test <test@example.org>
430 user: test <test@example.org>
431 date: Mon Jan 01 00:00:20 2007 +0000
431 date: Mon Jan 01 00:00:20 2007 +0000
432 files: foo
432 files: foo
433 description:
433 description:
434 addfoo
434 addfoo
435
435
436
436
437
437
438 --sourceorder should fail
438 --sourceorder should fail
439
439
440 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
440 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
441 initializing destination git-repo4-sourcesort-hg repository
441 initializing destination git-repo4-sourcesort-hg repository
442 abort: --sourcesort is not supported by this data source
442 abort: --sourcesort is not supported by this data source
443 [255]
443 [255]
444
444
445 test sub modules
445 test sub modules
446
446
447 $ mkdir git-repo5
447 $ mkdir git-repo5
448 $ cd git-repo5
448 $ cd git-repo5
449 $ git init-db >/dev/null 2>/dev/null
449 $ git init-db >/dev/null 2>/dev/null
450 $ echo 'sub' >> foo
450 $ echo 'sub' >> foo
451 $ git add foo
451 $ git add foo
452 $ commit -a -m 'addfoo'
452 $ commit -a -m 'addfoo'
453 $ BASE=`pwd`
453 $ BASE=`pwd`
454 $ cd ..
454 $ cd ..
455 $ mkdir git-repo6
455 $ mkdir git-repo6
456 $ cd git-repo6
456 $ cd git-repo6
457 $ git init-db >/dev/null 2>/dev/null
457 $ git init-db >/dev/null 2>/dev/null
458 $ git submodule add ${BASE} >/dev/null 2>/dev/null
458 $ git submodule add ${BASE} >/dev/null 2>/dev/null
459 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
459 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
460
461 test non-tab whitespace .gitmodules
462
463 $ cat >> .gitmodules <<EOF
464 > [submodule "git-repo5"]
465 > path = git-repo5
466 > url = $TESTTMP/git-repo5
467 > EOF
468 $ git commit -a -m "weird white space submodule"
469 [master *] weird white space submodule (glob)
470 Author: nottest <test@example.org>
471 1 file changed, 3 insertions(+)
472 $ cd ..
473 $ hg convert git-repo6 hg-repo6
474 initializing destination hg-repo6 repository
475 scanning source...
476 sorting...
477 converting...
478 1 addsubmodule
479 0 weird white space submodule
480 updating bookmarks
481
482 $ rm -rf hg-repo6
483 $ cd git-repo6
484 $ git reset --hard 'HEAD^' > /dev/null
460 $ cd ..
485 $ cd ..
461
486
462 test invalid splicemap1
487 test invalid splicemap1
463
488
464 $ cat > splicemap <<EOF
489 $ cat > splicemap <<EOF
465 > $VALIDID1
490 > $VALIDID1
466 > EOF
491 > EOF
467 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap1-hg
492 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap1-hg
468 initializing destination git-repo2-splicemap1-hg repository
493 initializing destination git-repo2-splicemap1-hg repository
469 abort: syntax error in splicemap(1): child parent1[,parent2] expected
494 abort: syntax error in splicemap(1): child parent1[,parent2] expected
470 [255]
495 [255]
471
496
472 test invalid splicemap2
497 test invalid splicemap2
473
498
474 $ cat > splicemap <<EOF
499 $ cat > splicemap <<EOF
475 > $VALIDID1 $VALIDID2, $VALIDID2, $VALIDID2
500 > $VALIDID1 $VALIDID2, $VALIDID2, $VALIDID2
476 > EOF
501 > EOF
477 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap2-hg
502 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap2-hg
478 initializing destination git-repo2-splicemap2-hg repository
503 initializing destination git-repo2-splicemap2-hg repository
479 abort: syntax error in splicemap(1): child parent1[,parent2] expected
504 abort: syntax error in splicemap(1): child parent1[,parent2] expected
480 [255]
505 [255]
481
506
482 test invalid splicemap3
507 test invalid splicemap3
483
508
484 $ cat > splicemap <<EOF
509 $ cat > splicemap <<EOF
485 > $INVALIDID1 $INVALIDID2
510 > $INVALIDID1 $INVALIDID2
486 > EOF
511 > EOF
487 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap3-hg
512 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap3-hg
488 initializing destination git-repo2-splicemap3-hg repository
513 initializing destination git-repo2-splicemap3-hg repository
489 abort: splicemap entry afd12345af is not a valid revision identifier
514 abort: splicemap entry afd12345af is not a valid revision identifier
490 [255]
515 [255]
491
516
492 convert sub modules
517 convert sub modules
493 $ hg convert git-repo6 git-repo6-hg
518 $ hg convert git-repo6 git-repo6-hg
494 initializing destination git-repo6-hg repository
519 initializing destination git-repo6-hg repository
495 scanning source...
520 scanning source...
496 sorting...
521 sorting...
497 converting...
522 converting...
498 0 addsubmodule
523 0 addsubmodule
499 updating bookmarks
524 updating bookmarks
500 $ hg -R git-repo6-hg log -v
525 $ hg -R git-repo6-hg log -v
501 changeset: 0:* (glob)
526 changeset: 0:* (glob)
502 bookmark: master
527 bookmark: master
503 tag: tip
528 tag: tip
504 user: nottest <test@example.org>
529 user: nottest <test@example.org>
505 date: Mon Jan 01 00:00:23 2007 +0000
530 date: Mon Jan 01 00:00:23 2007 +0000
506 files: .hgsub .hgsubstate
531 files: .hgsub .hgsubstate
507 description:
532 description:
508 addsubmodule
533 addsubmodule
509
534
510 committer: test <test@example.org>
535 committer: test <test@example.org>
511
536
512
537
513
538
514 $ cd git-repo6-hg
539 $ cd git-repo6-hg
515 $ hg up >/dev/null 2>/dev/null
540 $ hg up >/dev/null 2>/dev/null
516 $ cat .hgsubstate
541 $ cat .hgsubstate
517 * git-repo5 (glob)
542 * git-repo5 (glob)
518 $ cd git-repo5
543 $ cd git-repo5
519 $ cat foo
544 $ cat foo
520 sub
545 sub
521
546
522 $ cd ../..
547 $ cd ../..
523
548
524 make sure rename detection doesn't break removing and adding gitmodules
549 make sure rename detection doesn't break removing and adding gitmodules
525
550
526 $ cd git-repo6
551 $ cd git-repo6
527 $ git mv .gitmodules .gitmodules-renamed
552 $ git mv .gitmodules .gitmodules-renamed
528 $ commit -a -m 'rename .gitmodules'
553 $ commit -a -m 'rename .gitmodules'
529 $ git mv .gitmodules-renamed .gitmodules
554 $ git mv .gitmodules-renamed .gitmodules
530 $ commit -a -m 'rename .gitmodules back'
555 $ commit -a -m 'rename .gitmodules back'
531 $ cd ..
556 $ cd ..
532
557
533 $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg
558 $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg
534 $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n"
559 $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n"
535 rename .gitmodules
560 rename .gitmodules
536 $ hg -R git-repo6-hg status -C --change 'tip^'
561 $ hg -R git-repo6-hg status -C --change 'tip^'
537 A .gitmodules-renamed
562 A .gitmodules-renamed
538 R .hgsub
563 R .hgsub
539 R .hgsubstate
564 R .hgsubstate
540 $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n"
565 $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n"
541 rename .gitmodules back
566 rename .gitmodules back
542 $ hg -R git-repo6-hg status -C --change tip
567 $ hg -R git-repo6-hg status -C --change tip
543 A .hgsub
568 A .hgsub
544 A .hgsubstate
569 A .hgsubstate
545 R .gitmodules-renamed
570 R .gitmodules-renamed
546
571
547 convert the revision removing '.gitmodules' itself (and related
572 convert the revision removing '.gitmodules' itself (and related
548 submodules)
573 submodules)
549
574
550 $ cd git-repo6
575 $ cd git-repo6
551 $ git rm .gitmodules
576 $ git rm .gitmodules
552 rm '.gitmodules'
577 rm '.gitmodules'
553 $ git rm --cached git-repo5
578 $ git rm --cached git-repo5
554 rm 'git-repo5'
579 rm 'git-repo5'
555 $ commit -a -m 'remove .gitmodules and submodule git-repo5'
580 $ commit -a -m 'remove .gitmodules and submodule git-repo5'
556 $ cd ..
581 $ cd ..
557
582
558 $ hg convert -q git-repo6 git-repo6-hg
583 $ hg convert -q git-repo6 git-repo6-hg
559 $ hg -R git-repo6-hg tip -T "{desc|firstline}\n"
584 $ hg -R git-repo6-hg tip -T "{desc|firstline}\n"
560 remove .gitmodules and submodule git-repo5
585 remove .gitmodules and submodule git-repo5
561 $ hg -R git-repo6-hg tip -T "{file_dels}\n"
586 $ hg -R git-repo6-hg tip -T "{file_dels}\n"
562 .hgsub .hgsubstate
587 .hgsub .hgsubstate
563
588
564 damaged git repository tests:
589 damaged git repository tests:
565 In case the hard-coded hashes change, the following commands can be used to
590 In case the hard-coded hashes change, the following commands can be used to
566 list the hashes and their corresponding types in the repository:
591 list the hashes and their corresponding types in the repository:
567 cd git-repo4/.git/objects
592 cd git-repo4/.git/objects
568 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
593 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
569 cd ../../..
594 cd ../../..
570
595
571 damage git repository by renaming a commit object
596 damage git repository by renaming a commit object
572 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
597 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
573 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
598 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
574 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
599 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
575 abort: cannot read tags from git-repo4/.git
600 abort: cannot read tags from git-repo4/.git
576 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
601 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
577 damage git repository by renaming a blob object
602 damage git repository by renaming a blob object
578
603
579 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
604 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
580 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
605 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
581 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
606 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
582 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
607 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
583 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
608 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
584 damage git repository by renaming a tree object
609 damage git repository by renaming a tree object
585
610
586 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
611 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
587 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
612 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
588 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
613 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
589 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
614 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
General Comments 0
You need to be logged in to leave comments. Login now