##// END OF EJS Templates
convert: rewrite calls to Git to use the new shelling mechanism (SEC)...
Mateusz Kwapich -
r28660:cdda7b96 stable
parent child Browse files
Show More
@@ -1,432 +1,438
1 1 # git.py - git support for the convert extension
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import os
9 9 import subprocess
10 10 from mercurial import util, config, error
11 11 from mercurial.node import hex, nullid
12 12 from mercurial.i18n import _
13 13
14 14 from common import NoRepo, commit, converter_source, checktool, commandline
15 15
16 16 class submodule(object):
17 17 def __init__(self, path, node, url):
18 18 self.path = path
19 19 self.node = node
20 20 self.url = url
21 21
22 22 def hgsub(self):
23 23 return "%s = [git]%s" % (self.path, self.url)
24 24
25 25 def hgsubstate(self):
26 26 return "%s %s" % (self.node, self.path)
27 27
28 28 class convert_git(converter_source, commandline):
29 29 # Windows does not support GIT_DIR= construct while other systems
30 30 # cannot remove environment variable. Just assume none have
31 31 # both issues.
32 32 if util.safehasattr(os, 'unsetenv'):
33 33 def gitopen(self, s, err=None):
34 34 prevgitdir = os.environ.get('GIT_DIR')
35 35 os.environ['GIT_DIR'] = self.path
36 36 try:
37 37 if err == subprocess.PIPE:
38 38 (stdin, stdout, stderr) = util.popen3(s)
39 39 return stdout
40 40 elif err == subprocess.STDOUT:
41 41 return self.popen_with_stderr(s)
42 42 else:
43 43 return util.popen(s, 'rb')
44 44 finally:
45 45 if prevgitdir is None:
46 46 del os.environ['GIT_DIR']
47 47 else:
48 48 os.environ['GIT_DIR'] = prevgitdir
49 49
50 50 def gitpipe(self, s):
51 51 prevgitdir = os.environ.get('GIT_DIR')
52 52 os.environ['GIT_DIR'] = self.path
53 53 try:
54 54 return util.popen3(s)
55 55 finally:
56 56 if prevgitdir is None:
57 57 del os.environ['GIT_DIR']
58 58 else:
59 59 os.environ['GIT_DIR'] = prevgitdir
60 60
61 61 else:
62 62 def gitopen(self, s, err=None):
63 63 if err == subprocess.PIPE:
64 64 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
65 65 return so
66 66 elif err == subprocess.STDOUT:
67 67 return self.popen_with_stderr(s)
68 68 else:
69 69 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
70 70
71 71 def gitpipe(self, s):
72 72 return util.popen3('GIT_DIR=%s %s' % (self.path, s))
73 73
74 74 def _gitcmd(self, cmd, *args, **kwargs):
75 75 return cmd('--git-dir=%s' % self.path, *args, **kwargs)
76 76
77 77 def gitrun0(self, *args, **kwargs):
78 78 return self._gitcmd(self.run0, *args, **kwargs)
79 79
80 80 def gitrun(self, *args, **kwargs):
81 81 return self._gitcmd(self.run, *args, **kwargs)
82 82
83 83 def gitrunlines0(self, *args, **kwargs):
84 84 return self._gitcmd(self.runlines0, *args, **kwargs)
85 85
86 86 def gitrunlines(self, *args, **kwargs):
87 87 return self._gitcmd(self.runlines, *args, **kwargs)
88 88
89 89 def popen_with_stderr(self, s):
90 90 p = subprocess.Popen(s, shell=True, bufsize=-1,
91 91 close_fds=util.closefds,
92 92 stdin=subprocess.PIPE,
93 93 stdout=subprocess.PIPE,
94 94 stderr=subprocess.STDOUT,
95 95 universal_newlines=False,
96 96 env=None)
97 97 return p.stdout
98 98
99 99 def gitread(self, s):
100 100 fh = self.gitopen(s)
101 101 data = fh.read()
102 102 return data, fh.close()
103 103
104 104 def __init__(self, ui, path, revs=None):
105 105 super(convert_git, self).__init__(ui, path, revs=revs)
106 106 commandline.__init__(self, ui, 'git')
107 107
108 108 if os.path.isdir(path + "/.git"):
109 109 path += "/.git"
110 110 if not os.path.exists(path + "/objects"):
111 111 raise NoRepo(_("%s does not look like a Git repository") % path)
112 112
113 113 # The default value (50) is based on the default for 'git diff'.
114 114 similarity = ui.configint('convert', 'git.similarity', default=50)
115 115 if similarity < 0 or similarity > 100:
116 116 raise error.Abort(_('similarity must be between 0 and 100'))
117 117 if similarity > 0:
118 self.simopt = '-C%d%%' % similarity
118 self.simopt = ['-C%d%%' % similarity]
119 119 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder',
120 120 False)
121 121 if findcopiesharder:
122 self.simopt += ' --find-copies-harder'
122 self.simopt.append('--find-copies-harder')
123 123 else:
124 self.simopt = ''
124 self.simopt = []
125 125
126 126 checktool('git', 'git')
127 127
128 128 self.path = path
129 129 self.submodules = []
130 130
131 131 self.catfilepipe = self.gitpipe('git cat-file --batch')
132 132
133 133 def after(self):
134 134 for f in self.catfilepipe:
135 135 f.close()
136 136
137 137 def getheads(self):
138 138 if not self.revs:
139 heads, ret = self.gitread('git rev-parse --branches --remotes')
140 heads = heads.splitlines()
141 if ret:
139 output, status = self.gitrun('rev-parse', '--branches', '--remotes')
140 heads = output.splitlines()
141 if status:
142 142 raise error.Abort(_('cannot retrieve git heads'))
143 143 else:
144 144 heads = []
145 145 for rev in self.revs:
146 rawhead, ret = self.gitread("git rev-parse --verify %s" % rev)
146 rawhead, ret = self.gitrun('rev-parse', '--verify', rev)
147 147 heads.append(rawhead[:-1])
148 148 if ret:
149 149 raise error.Abort(_('cannot retrieve git head "%s"') % rev)
150 150 return heads
151 151
152 152 def catfile(self, rev, type):
153 153 if rev == hex(nullid):
154 154 raise IOError
155 155 self.catfilepipe[0].write(rev+'\n')
156 156 self.catfilepipe[0].flush()
157 157 info = self.catfilepipe[1].readline().split()
158 158 if info[1] != type:
159 159 raise error.Abort(_('cannot read %r object at %s') % (type, rev))
160 160 size = int(info[2])
161 161 data = self.catfilepipe[1].read(size)
162 162 if len(data) < size:
163 163 raise error.Abort(_('cannot read %r object at %s: unexpected size')
164 164 % (type, rev))
165 165 # read the trailing newline
166 166 self.catfilepipe[1].read(1)
167 167 return data
168 168
169 169 def getfile(self, name, rev):
170 170 if rev == hex(nullid):
171 171 return None, None
172 172 if name == '.hgsub':
173 173 data = '\n'.join([m.hgsub() for m in self.submoditer()])
174 174 mode = ''
175 175 elif name == '.hgsubstate':
176 176 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
177 177 mode = ''
178 178 else:
179 179 data = self.catfile(rev, "blob")
180 180 mode = self.modecache[(name, rev)]
181 181 return data, mode
182 182
183 183 def submoditer(self):
184 184 null = hex(nullid)
185 185 for m in sorted(self.submodules, key=lambda p: p.path):
186 186 if m.node != null:
187 187 yield m
188 188
189 189 def parsegitmodules(self, content):
190 190 """Parse the formatted .gitmodules file, example file format:
191 191 [submodule "sub"]\n
192 192 \tpath = sub\n
193 193 \turl = git://giturl\n
194 194 """
195 195 self.submodules = []
196 196 c = config.config()
197 197 # Each item in .gitmodules starts with whitespace that cant be parsed
198 198 c.parse('.gitmodules', '\n'.join(line.strip() for line in
199 199 content.split('\n')))
200 200 for sec in c.sections():
201 201 s = c[sec]
202 202 if 'url' in s and 'path' in s:
203 203 self.submodules.append(submodule(s['path'], '', s['url']))
204 204
205 205 def retrievegitmodules(self, version):
206 modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
206 modules, ret = self.gitrun('show', '%s:%s' % (version, '.gitmodules'))
207 207 if ret:
208 208 # This can happen if a file is in the repo that has permissions
209 209 # 160000, but there is no .gitmodules file.
210 210 self.ui.warn(_("warning: cannot read submodules config file in "
211 211 "%s\n") % version)
212 212 return
213 213
214 214 try:
215 215 self.parsegitmodules(modules)
216 216 except error.ParseError:
217 217 self.ui.warn(_("warning: unable to parse .gitmodules in %s\n")
218 218 % version)
219 219 return
220 220
221 221 for m in self.submodules:
222 node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
222 node, ret = self.gitrun('rev-parse', '%s:%s' % (version, m.path))
223 223 if ret:
224 224 continue
225 225 m.node = node.strip()
226 226
227 227 def getchanges(self, version, full):
228 228 if full:
229 229 raise error.Abort(_("convert from git does not support --full"))
230 230 self.modecache = {}
231 fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % (
232 self.simopt, version))
231 cmd = ['diff-tree','-z', '--root', '-m', '-r'] + self.simopt + [version]
232 output, status = self.gitrun(*cmd)
233 if status:
234 raise error.Abort(_('cannot read changes in %s') % version)
233 235 changes = []
234 236 copies = {}
235 237 seen = set()
236 238 entry = None
237 239 subexists = [False]
238 240 subdeleted = [False]
239 difftree = fh.read().split('\x00')
241 difftree = output.split('\x00')
240 242 lcount = len(difftree)
241 243 i = 0
242 244
243 245 skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules',
244 246 False)
245 247 def add(entry, f, isdest):
246 248 seen.add(f)
247 249 h = entry[3]
248 250 p = (entry[1] == "100755")
249 251 s = (entry[1] == "120000")
250 252 renamesource = (not isdest and entry[4][0] == 'R')
251 253
252 254 if f == '.gitmodules':
253 255 if skipsubmodules:
254 256 return
255 257
256 258 subexists[0] = True
257 259 if entry[4] == 'D' or renamesource:
258 260 subdeleted[0] = True
259 261 changes.append(('.hgsub', hex(nullid)))
260 262 else:
261 263 changes.append(('.hgsub', ''))
262 264 elif entry[1] == '160000' or entry[0] == ':160000':
263 265 if not skipsubmodules:
264 266 subexists[0] = True
265 267 else:
266 268 if renamesource:
267 269 h = hex(nullid)
268 270 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
269 271 changes.append((f, h))
270 272
271 273 while i < lcount:
272 274 l = difftree[i]
273 275 i += 1
274 276 if not entry:
275 277 if not l.startswith(':'):
276 278 continue
277 279 entry = l.split()
278 280 continue
279 281 f = l
280 282 if entry[4][0] == 'C':
281 283 copysrc = f
282 284 copydest = difftree[i]
283 285 i += 1
284 286 f = copydest
285 287 copies[copydest] = copysrc
286 288 if f not in seen:
287 289 add(entry, f, False)
288 290 # A file can be copied multiple times, or modified and copied
289 291 # simultaneously. So f can be repeated even if fdest isn't.
290 292 if entry[4][0] == 'R':
291 293 # rename: next line is the destination
292 294 fdest = difftree[i]
293 295 i += 1
294 296 if fdest not in seen:
295 297 add(entry, fdest, True)
296 298 # .gitmodules isn't imported at all, so it being copied to
297 299 # and fro doesn't really make sense
298 300 if f != '.gitmodules' and fdest != '.gitmodules':
299 301 copies[fdest] = f
300 302 entry = None
301 if fh.close():
302 raise error.Abort(_('cannot read changes in %s') % version)
303 303
304 304 if subexists[0]:
305 305 if subdeleted[0]:
306 306 changes.append(('.hgsubstate', hex(nullid)))
307 307 else:
308 308 self.retrievegitmodules(version)
309 309 changes.append(('.hgsubstate', ''))
310 310 return (changes, copies, set())
311 311
312 312 def getcommit(self, version):
313 313 c = self.catfile(version, "commit") # read the commit hash
314 314 end = c.find("\n\n")
315 315 message = c[end + 2:]
316 316 message = self.recode(message)
317 317 l = c[:end].splitlines()
318 318 parents = []
319 319 author = committer = None
320 320 for e in l[1:]:
321 321 n, v = e.split(" ", 1)
322 322 if n == "author":
323 323 p = v.split()
324 324 tm, tz = p[-2:]
325 325 author = " ".join(p[:-2])
326 326 if author[0] == "<": author = author[1:-1]
327 327 author = self.recode(author)
328 328 if n == "committer":
329 329 p = v.split()
330 330 tm, tz = p[-2:]
331 331 committer = " ".join(p[:-2])
332 332 if committer[0] == "<": committer = committer[1:-1]
333 333 committer = self.recode(committer)
334 334 if n == "parent":
335 335 parents.append(v)
336 336
337 337 if committer and committer != author:
338 338 message += "\ncommitter: %s\n" % committer
339 339 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
340 340 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
341 341 date = tm + " " + str(tz)
342 342
343 343 c = commit(parents=parents, date=date, author=author, desc=message,
344 344 rev=version)
345 345 return c
346 346
347 347 def numcommits(self):
348 return len([None for _ in self.gitopen('git rev-list --all')])
348 output, ret = self.gitrunlines('rev-list', '--all')
349 if ret:
350 raise error.Abort(_('cannot retrieve number of commits in %s') \
351 % self.path)
352 return len(output)
349 353
350 354 def gettags(self):
351 355 tags = {}
352 356 alltags = {}
353 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
354 err=subprocess.STDOUT)
357 output, status = self.gitrunlines('ls-remote', '--tags', self.path)
358
359 if status:
360 raise error.Abort(_('cannot read tags from %s') % self.path)
355 361 prefix = 'refs/tags/'
356 362
357 363 # Build complete list of tags, both annotated and bare ones
358 for line in fh:
364 for line in output:
359 365 line = line.strip()
360 366 if line.startswith("error:") or line.startswith("fatal:"):
361 367 raise error.Abort(_('cannot read tags from %s') % self.path)
362 368 node, tag = line.split(None, 1)
363 369 if not tag.startswith(prefix):
364 370 continue
365 371 alltags[tag[len(prefix):]] = node
366 if fh.close():
367 raise error.Abort(_('cannot read tags from %s') % self.path)
368 372
369 373 # Filter out tag objects for annotated tag refs
370 374 for tag in alltags:
371 375 if tag.endswith('^{}'):
372 376 tags[tag[:-3]] = alltags[tag]
373 377 else:
374 378 if tag + '^{}' in alltags:
375 379 continue
376 380 else:
377 381 tags[tag] = alltags[tag]
378 382
379 383 return tags
380 384
381 385 def getchangedfiles(self, version, i):
382 386 changes = []
383 387 if i is None:
384 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
385 for l in fh:
388 output, status = self.gitrunlines('diff-tree', '--root', '-m',
389 '-r', version)
390 if status:
391 raise error.Abort(_('cannot read changes in %s') % version)
392 for l in output:
386 393 if "\t" not in l:
387 394 continue
388 395 m, f = l[:-1].split("\t")
389 396 changes.append(f)
390 397 else:
391 fh = self.gitopen('git diff-tree --name-only --root -r %s '
392 '"%s^%s" --' % (version, version, i + 1))
393 changes = [f.rstrip('\n') for f in fh]
394 if fh.close():
395 raise error.Abort(_('cannot read changes in %s') % version)
398 output, status = self.gitrunlines('diff-tree', '--name-only',
399 '--root', '-r', version,
400 '%s^%s' % (version, i + 1), '--')
401 changes = [f.rstrip('\n') for f in output]
396 402
397 403 return changes
398 404
399 405 def getbookmarks(self):
400 406 bookmarks = {}
401 407
402 408 # Handle local and remote branches
403 409 remoteprefix = self.ui.config('convert', 'git.remoteprefix', 'remote')
404 410 reftypes = [
405 411 # (git prefix, hg prefix)
406 412 ('refs/remotes/origin/', remoteprefix + '/'),
407 413 ('refs/heads/', '')
408 414 ]
409 415
410 416 exclude = set([
411 417 'refs/remotes/origin/HEAD',
412 418 ])
413 419
414 420 try:
415 fh = self.gitopen('git show-ref', err=subprocess.PIPE)
416 for line in fh:
421 output, status = self.gitrunlines('show-ref')
422 for line in output:
417 423 line = line.strip()
418 424 rev, name = line.split(None, 1)
419 425 # Process each type of branch
420 426 for gitprefix, hgprefix in reftypes:
421 427 if not name.startswith(gitprefix) or name in exclude:
422 428 continue
423 429 name = '%s%s' % (hgprefix, name[len(gitprefix):])
424 430 bookmarks[name] = rev
425 431 except Exception:
426 432 pass
427 433
428 434 return bookmarks
429 435
430 436 def checkrevformat(self, revstr, mapname='splicemap'):
431 437 """ git revision string is a 40 byte hex """
432 438 self.checkhexformat(revstr, mapname)
@@ -1,731 +1,731
1 1 #require git
2 2
3 3 $ echo "[core]" >> $HOME/.gitconfig
4 4 $ echo "autocrlf = false" >> $HOME/.gitconfig
5 5 $ echo "[core]" >> $HOME/.gitconfig
6 6 $ echo "autocrlf = false" >> $HOME/.gitconfig
7 7 $ echo "[extensions]" >> $HGRCPATH
8 8 $ echo "convert=" >> $HGRCPATH
9 9 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
10 10 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
11 11 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
12 12 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
13 13 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
14 14 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
15 15 $ INVALIDID1=afd12345af
16 16 $ INVALIDID2=28173x36ddd1e67bf7098d541130558ef5534a86
17 17 $ VALIDID1=39b3d83f9a69a9ba4ebb111461071a0af0027357
18 18 $ VALIDID2=8dd6476bd09d9c7776355dc454dafe38efaec5da
19 19 $ count=10
20 20 $ commit()
21 21 > {
22 22 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
23 23 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
24 24 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
25 25 > count=`expr $count + 1`
26 26 > }
27 27 $ mkdir git-repo
28 28 $ cd git-repo
29 29 $ git init-db >/dev/null 2>/dev/null
30 30 $ echo a > a
31 31 $ mkdir d
32 32 $ echo b > d/b
33 33 $ git add a d
34 34 $ commit -a -m t1
35 35
36 36 Remove the directory, then try to replace it with a file (issue754)
37 37
38 38 $ git rm -f d/b
39 39 rm 'd/b'
40 40 $ commit -m t2
41 41 $ echo d > d
42 42 $ git add d
43 43 $ commit -m t3
44 44 $ echo b >> a
45 45 $ commit -a -m t4.1
46 46 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
47 47 $ echo c > a
48 48 $ echo a >> a
49 49 $ commit -a -m t4.2
50 50 $ git checkout master >/dev/null 2>/dev/null
51 51 $ git pull --no-commit . other > /dev/null 2>/dev/null
52 52 $ commit -m 'Merge branch other'
53 53 $ cd ..
54 54 $ hg convert --config extensions.progress= --config progress.assume-tty=1 \
55 55 > --config progress.delay=0 --config progress.changedelay=0 \
56 56 > --config progress.refresh=0 --config progress.width=60 \
57 57 > --config progress.format='topic, bar, number' --datesort git-repo
58 58 \r (no-eol) (esc)
59 59 scanning [======> ] 1/6\r (no-eol) (esc)
60 60 scanning [=============> ] 2/6\r (no-eol) (esc)
61 61 scanning [=====================> ] 3/6\r (no-eol) (esc)
62 62 scanning [============================> ] 4/6\r (no-eol) (esc)
63 63 scanning [===================================> ] 5/6\r (no-eol) (esc)
64 64 scanning [===========================================>] 6/6\r (no-eol) (esc)
65 65 \r (no-eol) (esc)
66 66 \r (no-eol) (esc)
67 67 converting [ ] 0/6\r (no-eol) (esc)
68 68 getting files [==================> ] 1/2\r (no-eol) (esc)
69 69 getting files [======================================>] 2/2\r (no-eol) (esc)
70 70 \r (no-eol) (esc)
71 71 \r (no-eol) (esc)
72 72 converting [======> ] 1/6\r (no-eol) (esc)
73 73 getting files [======================================>] 1/1\r (no-eol) (esc)
74 74 \r (no-eol) (esc)
75 75 \r (no-eol) (esc)
76 76 converting [=============> ] 2/6\r (no-eol) (esc)
77 77 getting files [======================================>] 1/1\r (no-eol) (esc)
78 78 \r (no-eol) (esc)
79 79 \r (no-eol) (esc)
80 80 converting [====================> ] 3/6\r (no-eol) (esc)
81 81 getting files [======================================>] 1/1\r (no-eol) (esc)
82 82 \r (no-eol) (esc)
83 83 \r (no-eol) (esc)
84 84 converting [===========================> ] 4/6\r (no-eol) (esc)
85 85 getting files [======================================>] 1/1\r (no-eol) (esc)
86 86 \r (no-eol) (esc)
87 87 \r (no-eol) (esc)
88 88 converting [==================================> ] 5/6\r (no-eol) (esc)
89 89 getting files [======================================>] 1/1\r (no-eol) (esc)
90 90 \r (no-eol) (esc)
91 91 assuming destination git-repo-hg
92 92 initializing destination git-repo-hg repository
93 93 scanning source...
94 94 sorting...
95 95 converting...
96 96 5 t1
97 97 4 t2
98 98 3 t3
99 99 2 t4.1
100 100 1 t4.2
101 101 0 Merge branch other
102 102 updating bookmarks
103 103 $ hg up -q -R git-repo-hg
104 104 $ hg -R git-repo-hg tip -v
105 105 changeset: 5:c78094926be2
106 106 bookmark: master
107 107 tag: tip
108 108 parent: 3:f5f5cb45432b
109 109 parent: 4:4e174f80c67c
110 110 user: test <test@example.org>
111 111 date: Mon Jan 01 00:00:15 2007 +0000
112 112 files: a
113 113 description:
114 114 Merge branch other
115 115
116 116
117 117 $ count=10
118 118 $ mkdir git-repo2
119 119 $ cd git-repo2
120 120 $ git init-db >/dev/null 2>/dev/null
121 121 $ echo foo > foo
122 122 $ git add foo
123 123 $ commit -a -m 'add foo'
124 124 $ echo >> foo
125 125 $ commit -a -m 'change foo'
126 126 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
127 127 $ echo quux >> quux
128 128 $ git add quux
129 129 $ commit -a -m 'add quux'
130 130 $ echo bar > bar
131 131 $ git add bar
132 132 $ commit -a -m 'add bar'
133 133 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
134 134 $ echo baz > baz
135 135 $ git add baz
136 136 $ commit -a -m 'add baz'
137 137 $ git checkout master >/dev/null 2>/dev/null
138 138 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
139 139 $ commit -m 'Octopus merge'
140 140 $ echo bar >> bar
141 141 $ commit -a -m 'change bar'
142 142 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
143 143 $ echo >> foo
144 144 $ commit -a -m 'change foo'
145 145 $ git checkout master >/dev/null 2>/dev/null
146 146 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
147 147 $ commit -m 'Discard change to foo'
148 148 $ cd ..
149 149 $ glog()
150 150 > {
151 151 > hg log -G --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
152 152 > }
153 153 $ splitrepo()
154 154 > {
155 155 > msg="$1"
156 156 > files="$2"
157 157 > opts=$3
158 158 > echo "% $files: $msg"
159 159 > prefix=`echo "$files" | sed -e 's/ /-/g'`
160 160 > fmap="$prefix.fmap"
161 161 > repo="$prefix.repo"
162 162 > for i in $files; do
163 163 > echo "include $i" >> "$fmap"
164 164 > done
165 165 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
166 166 > hg up -q -R "$repo"
167 167 > glog -R "$repo"
168 168 > hg -R "$repo" manifest --debug
169 169 > }
170 170
171 171 full conversion
172 172
173 173 $ hg convert --datesort git-repo2 fullrepo \
174 174 > --config extensions.progress= --config progress.assume-tty=1 \
175 175 > --config progress.delay=0 --config progress.changedelay=0 \
176 176 > --config progress.refresh=0 --config progress.width=60 \
177 177 > --config progress.format='topic, bar, number'
178 178 \r (no-eol) (esc)
179 179 scanning [===> ] 1/9\r (no-eol) (esc)
180 180 scanning [========> ] 2/9\r (no-eol) (esc)
181 181 scanning [=============> ] 3/9\r (no-eol) (esc)
182 182 scanning [==================> ] 4/9\r (no-eol) (esc)
183 183 scanning [=======================> ] 5/9\r (no-eol) (esc)
184 184 scanning [============================> ] 6/9\r (no-eol) (esc)
185 185 scanning [=================================> ] 7/9\r (no-eol) (esc)
186 186 scanning [======================================> ] 8/9\r (no-eol) (esc)
187 187 scanning [===========================================>] 9/9\r (no-eol) (esc)
188 188 \r (no-eol) (esc)
189 189 \r (no-eol) (esc)
190 190 converting [ ] 0/9\r (no-eol) (esc)
191 191 getting files [======================================>] 1/1\r (no-eol) (esc)
192 192 \r (no-eol) (esc)
193 193 \r (no-eol) (esc)
194 194 converting [===> ] 1/9\r (no-eol) (esc)
195 195 getting files [======================================>] 1/1\r (no-eol) (esc)
196 196 \r (no-eol) (esc)
197 197 \r (no-eol) (esc)
198 198 converting [========> ] 2/9\r (no-eol) (esc)
199 199 getting files [======================================>] 1/1\r (no-eol) (esc)
200 200 \r (no-eol) (esc)
201 201 \r (no-eol) (esc)
202 202 converting [=============> ] 3/9\r (no-eol) (esc)
203 203 getting files [======================================>] 1/1\r (no-eol) (esc)
204 204 \r (no-eol) (esc)
205 205 \r (no-eol) (esc)
206 206 converting [=================> ] 4/9\r (no-eol) (esc)
207 207 getting files [======================================>] 1/1\r (no-eol) (esc)
208 208 \r (no-eol) (esc)
209 209 \r (no-eol) (esc)
210 210 converting [======================> ] 5/9\r (no-eol) (esc)
211 211 getting files [===> ] 1/8\r (no-eol) (esc)
212 212 getting files [========> ] 2/8\r (no-eol) (esc)
213 213 getting files [=============> ] 3/8\r (no-eol) (esc)
214 214 getting files [==================> ] 4/8\r (no-eol) (esc)
215 215 getting files [=======================> ] 5/8\r (no-eol) (esc)
216 216 getting files [============================> ] 6/8\r (no-eol) (esc)
217 217 getting files [=================================> ] 7/8\r (no-eol) (esc)
218 218 getting files [======================================>] 8/8\r (no-eol) (esc)
219 219 \r (no-eol) (esc)
220 220 \r (no-eol) (esc)
221 221 converting [===========================> ] 6/9\r (no-eol) (esc)
222 222 getting files [======================================>] 1/1\r (no-eol) (esc)
223 223 \r (no-eol) (esc)
224 224 \r (no-eol) (esc)
225 225 converting [===============================> ] 7/9\r (no-eol) (esc)
226 226 getting files [======================================>] 1/1\r (no-eol) (esc)
227 227 \r (no-eol) (esc)
228 228 \r (no-eol) (esc)
229 229 converting [====================================> ] 8/9\r (no-eol) (esc)
230 230 getting files [==================> ] 1/2\r (no-eol) (esc)
231 231 getting files [======================================>] 2/2\r (no-eol) (esc)
232 232 \r (no-eol) (esc)
233 233 initializing destination fullrepo repository
234 234 scanning source...
235 235 sorting...
236 236 converting...
237 237 8 add foo
238 238 7 change foo
239 239 6 add quux
240 240 5 add bar
241 241 4 add baz
242 242 3 Octopus merge
243 243 2 change bar
244 244 1 change foo
245 245 0 Discard change to foo
246 246 updating bookmarks
247 247 $ hg up -q -R fullrepo
248 248 $ glog -R fullrepo
249 249 @ 9 "Discard change to foo" files: foo
250 250 |\
251 251 | o 8 "change foo" files: foo
252 252 | |
253 253 o | 7 "change bar" files: bar
254 254 |/
255 255 o 6 "(octopus merge fixup)" files:
256 256 |\
257 257 | o 5 "Octopus merge" files: baz
258 258 | |\
259 259 o | | 4 "add baz" files: baz
260 260 | | |
261 261 +---o 3 "add bar" files: bar
262 262 | |
263 263 o | 2 "add quux" files: quux
264 264 | |
265 265 | o 1 "change foo" files: foo
266 266 |/
267 267 o 0 "add foo" files: foo
268 268
269 269 $ hg -R fullrepo manifest --debug
270 270 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
271 271 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
272 272 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
273 273 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
274 274 $ splitrepo 'octopus merge' 'foo bar baz'
275 275 % foo bar baz: octopus merge
276 276 @ 8 "Discard change to foo" files: foo
277 277 |\
278 278 | o 7 "change foo" files: foo
279 279 | |
280 280 o | 6 "change bar" files: bar
281 281 |/
282 282 o 5 "(octopus merge fixup)" files:
283 283 |\
284 284 | o 4 "Octopus merge" files: baz
285 285 | |\
286 286 o | | 3 "add baz" files: baz
287 287 | | |
288 288 +---o 2 "add bar" files: bar
289 289 | |
290 290 | o 1 "change foo" files: foo
291 291 |/
292 292 o 0 "add foo" files: foo
293 293
294 294 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
295 295 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
296 296 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
297 297 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
298 298 % foo baz quux: only some parents of an octopus merge; "discard" a head
299 299 @ 6 "Discard change to foo" files: foo
300 300 |
301 301 o 5 "change foo" files: foo
302 302 |
303 303 o 4 "Octopus merge" files:
304 304 |\
305 305 | o 3 "add baz" files: baz
306 306 | |
307 307 | o 2 "add quux" files: quux
308 308 | |
309 309 o | 1 "change foo" files: foo
310 310 |/
311 311 o 0 "add foo" files: foo
312 312
313 313 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
314 314 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
315 315 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
316 316
317 317 test importing git renames and copies
318 318
319 319 $ cd git-repo2
320 320 $ git mv foo foo-renamed
321 321 since bar is not touched in this commit, this copy will not be detected
322 322 $ cp bar bar-copied
323 323 $ cp baz baz-copied
324 324 $ cp baz baz-copied2
325 325 $ cp baz ba-copy
326 326 $ echo baz2 >> baz
327 327 $ git add bar-copied baz-copied baz-copied2 ba-copy
328 328 $ commit -a -m 'rename and copy'
329 329 $ cd ..
330 330
331 331 input validation
332 332 $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo
333 333 abort: convert.git.similarity is not an integer ('foo')
334 334 [255]
335 335 $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo
336 336 abort: similarity must be between 0 and 100
337 337 [255]
338 338 $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo
339 339 abort: similarity must be between 0 and 100
340 340 [255]
341 341
342 342 $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo
343 343 $ hg -R fullrepo status -C --change master
344 344 M baz
345 345 A ba-copy
346 346 baz
347 347 A bar-copied
348 348 A baz-copied
349 349 baz
350 350 A baz-copied2
351 351 baz
352 352 A foo-renamed
353 353 foo
354 354 R foo
355 355
356 356 Ensure that the modification to the copy source was preserved
357 357 (there was a bug where if the copy dest was alphabetically prior to the copy
358 358 source, the copy source took the contents of the copy dest)
359 359 $ hg cat -r tip fullrepo/baz
360 360 baz
361 361 baz2
362 362
363 363 $ cd git-repo2
364 364 $ echo bar2 >> bar
365 365 $ commit -a -m 'change bar'
366 366 $ cp bar bar-copied2
367 367 $ git add bar-copied2
368 368 $ commit -a -m 'copy with no changes'
369 369 $ cd ..
370 370
371 371 $ hg -q convert --config convert.git.similarity=100 \
372 372 > --config convert.git.findcopiesharder=1 --datesort git-repo2 fullrepo
373 373 $ hg -R fullrepo status -C --change master
374 374 A bar-copied2
375 375 bar
376 376
377 377 test binary conversion (issue1359)
378 378
379 379 $ count=19
380 380 $ mkdir git-repo3
381 381 $ cd git-repo3
382 382 $ git init-db >/dev/null 2>/dev/null
383 383 $ $PYTHON -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
384 384 $ git add b
385 385 $ commit -a -m addbinary
386 386 $ cd ..
387 387
388 388 convert binary file
389 389
390 390 $ hg convert git-repo3 git-repo3-hg
391 391 initializing destination git-repo3-hg repository
392 392 scanning source...
393 393 sorting...
394 394 converting...
395 395 0 addbinary
396 396 updating bookmarks
397 397 $ cd git-repo3-hg
398 398 $ hg up -C
399 399 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
400 400 $ $PYTHON -c 'print len(file("b", "rb").read())'
401 401 4096
402 402 $ cd ..
403 403
404 404 test author vs committer
405 405
406 406 $ mkdir git-repo4
407 407 $ cd git-repo4
408 408 $ git init-db >/dev/null 2>/dev/null
409 409 $ echo >> foo
410 410 $ git add foo
411 411 $ commit -a -m addfoo
412 412 $ echo >> foo
413 413 $ GIT_AUTHOR_NAME="nottest"
414 414 $ commit -a -m addfoo2
415 415 $ cd ..
416 416
417 417 convert author committer
418 418
419 419 $ hg convert git-repo4 git-repo4-hg
420 420 initializing destination git-repo4-hg repository
421 421 scanning source...
422 422 sorting...
423 423 converting...
424 424 1 addfoo
425 425 0 addfoo2
426 426 updating bookmarks
427 427 $ hg -R git-repo4-hg log -v
428 428 changeset: 1:d63e967f93da
429 429 bookmark: master
430 430 tag: tip
431 431 user: nottest <test@example.org>
432 432 date: Mon Jan 01 00:00:21 2007 +0000
433 433 files: foo
434 434 description:
435 435 addfoo2
436 436
437 437 committer: test <test@example.org>
438 438
439 439
440 440 changeset: 0:0735477b0224
441 441 user: test <test@example.org>
442 442 date: Mon Jan 01 00:00:20 2007 +0000
443 443 files: foo
444 444 description:
445 445 addfoo
446 446
447 447
448 448
449 449 --sourceorder should fail
450 450
451 451 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
452 452 initializing destination git-repo4-sourcesort-hg repository
453 453 abort: --sourcesort is not supported by this data source
454 454 [255]
455 455
456 456 test converting certain branches
457 457
458 458 $ mkdir git-testrevs
459 459 $ cd git-testrevs
460 460 $ git init
461 461 Initialized empty Git repository in $TESTTMP/git-testrevs/.git/
462 462 $ echo a >> a ; git add a > /dev/null; git commit -m 'first' > /dev/null
463 463 $ echo a >> a ; git add a > /dev/null; git commit -m 'master commit' > /dev/null
464 464 $ git checkout -b goodbranch 'HEAD^'
465 465 Switched to a new branch 'goodbranch'
466 466 $ echo a >> b ; git add b > /dev/null; git commit -m 'good branch commit' > /dev/null
467 467 $ git checkout -b badbranch 'HEAD^'
468 468 Switched to a new branch 'badbranch'
469 469 $ echo a >> c ; git add c > /dev/null; git commit -m 'bad branch commit' > /dev/null
470 470 $ cd ..
471 471 $ hg convert git-testrevs hg-testrevs --rev master --rev goodbranch
472 472 initializing destination hg-testrevs repository
473 473 scanning source...
474 474 sorting...
475 475 converting...
476 476 2 first
477 477 1 good branch commit
478 478 0 master commit
479 479 updating bookmarks
480 480 $ cd hg-testrevs
481 481 $ hg log -G -T '{rev} {bookmarks}'
482 482 o 2 master
483 483 |
484 484 | o 1 goodbranch
485 485 |/
486 486 o 0
487 487
488 488 $ cd ..
489 489
490 490 test sub modules
491 491
492 492 $ mkdir git-repo5
493 493 $ cd git-repo5
494 494 $ git init-db >/dev/null 2>/dev/null
495 495 $ echo 'sub' >> foo
496 496 $ git add foo
497 497 $ commit -a -m 'addfoo'
498 498 $ BASE=`pwd`
499 499 $ cd ..
500 500 $ mkdir git-repo6
501 501 $ cd git-repo6
502 502 $ git init-db >/dev/null 2>/dev/null
503 503 $ git submodule add ${BASE} >/dev/null 2>/dev/null
504 504 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
505 505
506 506 test non-tab whitespace .gitmodules
507 507
508 508 $ cat >> .gitmodules <<EOF
509 509 > [submodule "git-repo5"]
510 510 > path = git-repo5
511 511 > url = git-repo5
512 512 > EOF
513 513 $ git commit -q -a -m "weird white space submodule"
514 514 $ cd ..
515 515 $ hg convert git-repo6 hg-repo6
516 516 initializing destination hg-repo6 repository
517 517 scanning source...
518 518 sorting...
519 519 converting...
520 520 1 addsubmodule
521 521 0 weird white space submodule
522 522 updating bookmarks
523 523
524 524 $ rm -rf hg-repo6
525 525 $ cd git-repo6
526 526 $ git reset --hard 'HEAD^' > /dev/null
527 527
528 528 test missing .gitmodules
529 529
530 530 $ git submodule add ../git-repo4 >/dev/null 2>/dev/null
531 531 $ git checkout HEAD .gitmodules
532 532 $ git rm .gitmodules
533 533 rm '.gitmodules'
534 534 $ git commit -q -m "remove .gitmodules" .gitmodules
535 535 $ git commit -q -m "missing .gitmodules"
536 536 $ cd ..
537 537 $ hg convert git-repo6 hg-repo6 --traceback 2>&1 | grep -v "fatal: Path '.gitmodules' does not exist"
538 538 initializing destination hg-repo6 repository
539 539 scanning source...
540 540 sorting...
541 541 converting...
542 542 2 addsubmodule
543 543 1 remove .gitmodules
544 544 0 missing .gitmodules
545 545 warning: cannot read submodules config file in * (glob)
546 546 updating bookmarks
547 547 $ rm -rf hg-repo6
548 548 $ cd git-repo6
549 549 $ rm -rf git-repo4
550 550 $ git reset --hard 'HEAD^^' > /dev/null
551 551 $ cd ..
552 552
553 553 test invalid splicemap1
554 554
555 555 $ cat > splicemap <<EOF
556 556 > $VALIDID1
557 557 > EOF
558 558 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap1-hg
559 559 initializing destination git-repo2-splicemap1-hg repository
560 560 abort: syntax error in splicemap(1): child parent1[,parent2] expected
561 561 [255]
562 562
563 563 test invalid splicemap2
564 564
565 565 $ cat > splicemap <<EOF
566 566 > $VALIDID1 $VALIDID2, $VALIDID2, $VALIDID2
567 567 > EOF
568 568 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap2-hg
569 569 initializing destination git-repo2-splicemap2-hg repository
570 570 abort: syntax error in splicemap(1): child parent1[,parent2] expected
571 571 [255]
572 572
573 573 test invalid splicemap3
574 574
575 575 $ cat > splicemap <<EOF
576 576 > $INVALIDID1 $INVALIDID2
577 577 > EOF
578 578 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap3-hg
579 579 initializing destination git-repo2-splicemap3-hg repository
580 580 abort: splicemap entry afd12345af is not a valid revision identifier
581 581 [255]
582 582
583 583 convert sub modules
584 584 $ hg convert git-repo6 git-repo6-hg
585 585 initializing destination git-repo6-hg repository
586 586 scanning source...
587 587 sorting...
588 588 converting...
589 589 0 addsubmodule
590 590 updating bookmarks
591 591 $ hg -R git-repo6-hg log -v
592 592 changeset: 0:* (glob)
593 593 bookmark: master
594 594 tag: tip
595 595 user: nottest <test@example.org>
596 596 date: Mon Jan 01 00:00:23 2007 +0000
597 597 files: .hgsub .hgsubstate
598 598 description:
599 599 addsubmodule
600 600
601 601 committer: test <test@example.org>
602 602
603 603
604 604
605 605 $ cd git-repo6-hg
606 606 $ hg up >/dev/null 2>/dev/null
607 607 $ cat .hgsubstate
608 608 * git-repo5 (glob)
609 609 $ cd git-repo5
610 610 $ cat foo
611 611 sub
612 612
613 613 $ cd ../..
614 614
615 615 make sure rename detection doesn't break removing and adding gitmodules
616 616
617 617 $ cd git-repo6
618 618 $ git mv .gitmodules .gitmodules-renamed
619 619 $ commit -a -m 'rename .gitmodules'
620 620 $ git mv .gitmodules-renamed .gitmodules
621 621 $ commit -a -m 'rename .gitmodules back'
622 622 $ cd ..
623 623
624 624 $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg
625 625 $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n"
626 626 rename .gitmodules
627 627 $ hg -R git-repo6-hg status -C --change 'tip^'
628 628 A .gitmodules-renamed
629 629 R .hgsub
630 630 R .hgsubstate
631 631 $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n"
632 632 rename .gitmodules back
633 633 $ hg -R git-repo6-hg status -C --change tip
634 634 A .hgsub
635 635 A .hgsubstate
636 636 R .gitmodules-renamed
637 637
638 638 convert the revision removing '.gitmodules' itself (and related
639 639 submodules)
640 640
641 641 $ cd git-repo6
642 642 $ git rm .gitmodules
643 643 rm '.gitmodules'
644 644 $ git rm --cached git-repo5
645 645 rm 'git-repo5'
646 646 $ commit -a -m 'remove .gitmodules and submodule git-repo5'
647 647 $ cd ..
648 648
649 649 $ hg convert -q git-repo6 git-repo6-hg
650 650 $ hg -R git-repo6-hg tip -T "{desc|firstline}\n"
651 651 remove .gitmodules and submodule git-repo5
652 652 $ hg -R git-repo6-hg tip -T "{file_dels}\n"
653 653 .hgsub .hgsubstate
654 654
655 655 skip submodules in the conversion
656 656
657 657 $ hg convert -q git-repo6 no-submodules --config convert.git.skipsubmodules=True
658 658 $ hg -R no-submodules manifest --all
659 659 .gitmodules-renamed
660 660
661 661 convert using a different remote prefix
662 662 $ git init git-repo7
663 663 Initialized empty Git repository in $TESTTMP/git-repo7/.git/
664 664 $ cd git-repo7
665 665 TODO: it'd be nice to use (?) lines instead of grep -v to handle the
666 666 git output variance, but that doesn't currently work in the middle of
667 667 a block, so do this for now.
668 668 $ touch a && git add a && git commit -am "commit a" | grep -v changed
669 669 [master (root-commit) 8ae5f69] commit a
670 670 Author: nottest <test@example.org>
671 671 create mode 100644 a
672 672 $ cd ..
673 673 $ git clone git-repo7 git-repo7-client
674 674 Cloning into 'git-repo7-client'...
675 675 done.
676 676 $ hg convert --config convert.git.remoteprefix=origin git-repo7-client hg-repo7
677 677 initializing destination hg-repo7 repository
678 678 scanning source...
679 679 sorting...
680 680 converting...
681 681 0 commit a
682 682 updating bookmarks
683 683 $ hg -R hg-repo7 bookmarks
684 684 master 0:03bf38caa4c6
685 685 origin/master 0:03bf38caa4c6
686 686
687 687 Run convert when the remote branches have changed
688 688 (there was an old bug where the local convert read branches from the server)
689 689
690 690 $ cd git-repo7
691 691 $ echo a >> a
692 692 $ git commit -q -am "move master forward"
693 693 $ cd ..
694 694 $ rm -rf hg-repo7
695 695 $ hg convert --config convert.git.remoteprefix=origin git-repo7-client hg-repo7
696 696 initializing destination hg-repo7 repository
697 697 scanning source...
698 698 sorting...
699 699 converting...
700 700 0 commit a
701 701 updating bookmarks
702 702 $ hg -R hg-repo7 bookmarks
703 703 master 0:03bf38caa4c6
704 704 origin/master 0:03bf38caa4c6
705 705
706 706 damaged git repository tests:
707 707 In case the hard-coded hashes change, the following commands can be used to
708 708 list the hashes and their corresponding types in the repository:
709 709 cd git-repo4/.git/objects
710 710 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
711 711 cd ../../..
712 712
713 713 damage git repository by renaming a commit object
714 714 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
715 715 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
716 716 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
717 abort: cannot read tags from git-repo4/.git
717 abort: cannot retrieve number of commits in git-repo4/.git
718 718 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
719 719 damage git repository by renaming a blob object
720 720
721 721 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
722 722 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
723 723 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
724 724 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
725 725 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
726 726 damage git repository by renaming a tree object
727 727
728 728 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
729 729 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
730 730 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
731 731 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
General Comments 0
You need to be logged in to leave comments. Login now