##// END OF EJS Templates
splicemap: improve error handling when source is git (issue2084)...
Ben Goswami -
r19121:478a0460 default
parent child Browse files
Show More
@@ -1,298 +1,303 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 else:
49 else:
50 def gitopen(self, s, err=None):
50 def gitopen(self, s, err=None):
51 if err == subprocess.PIPE:
51 if err == subprocess.PIPE:
52 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
52 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
53 return so
53 return so
54 elif err == subprocess.STDOUT:
54 elif err == subprocess.STDOUT:
55 return self.popen_with_stderr(s)
55 return self.popen_with_stderr(s)
56 else:
56 else:
57 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
57 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
58
58
59 def popen_with_stderr(self, s):
59 def popen_with_stderr(self, s):
60 p = subprocess.Popen(s, shell=True, bufsize=-1,
60 p = subprocess.Popen(s, shell=True, bufsize=-1,
61 close_fds=util.closefds,
61 close_fds=util.closefds,
62 stdin=subprocess.PIPE,
62 stdin=subprocess.PIPE,
63 stdout=subprocess.PIPE,
63 stdout=subprocess.PIPE,
64 stderr=subprocess.STDOUT,
64 stderr=subprocess.STDOUT,
65 universal_newlines=False,
65 universal_newlines=False,
66 env=None)
66 env=None)
67 return p.stdout
67 return p.stdout
68
68
69 def gitread(self, s):
69 def gitread(self, s):
70 fh = self.gitopen(s)
70 fh = self.gitopen(s)
71 data = fh.read()
71 data = fh.read()
72 return data, fh.close()
72 return data, fh.close()
73
73
74 def __init__(self, ui, path, rev=None):
74 def __init__(self, ui, path, rev=None):
75 super(convert_git, self).__init__(ui, path, rev=rev)
75 super(convert_git, self).__init__(ui, path, rev=rev)
76
76
77 if os.path.isdir(path + "/.git"):
77 if os.path.isdir(path + "/.git"):
78 path += "/.git"
78 path += "/.git"
79 if not os.path.exists(path + "/objects"):
79 if not os.path.exists(path + "/objects"):
80 raise NoRepo(_("%s does not look like a Git repository") % path)
80 raise NoRepo(_("%s does not look like a Git repository") % path)
81
81
82 checktool('git', 'git')
82 checktool('git', 'git')
83
83
84 self.path = path
84 self.path = path
85 self.submodules = []
85 self.submodules = []
86
86
87 def getheads(self):
87 def getheads(self):
88 if not self.rev:
88 if not self.rev:
89 heads, ret = self.gitread('git rev-parse --branches --remotes')
89 heads, ret = self.gitread('git rev-parse --branches --remotes')
90 heads = heads.splitlines()
90 heads = heads.splitlines()
91 else:
91 else:
92 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
92 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
93 heads = [heads[:-1]]
93 heads = [heads[:-1]]
94 if ret:
94 if ret:
95 raise util.Abort(_('cannot retrieve git heads'))
95 raise util.Abort(_('cannot retrieve git heads'))
96 return heads
96 return heads
97
97
98 def catfile(self, rev, type):
98 def catfile(self, rev, type):
99 if rev == hex(nullid):
99 if rev == hex(nullid):
100 raise IOError
100 raise IOError
101 data, ret = self.gitread("git cat-file %s %s" % (type, rev))
101 data, ret = self.gitread("git cat-file %s %s" % (type, rev))
102 if ret:
102 if ret:
103 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
103 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
104 return data
104 return data
105
105
106 def getfile(self, name, rev):
106 def getfile(self, name, rev):
107 if name == '.hgsub':
107 if name == '.hgsub':
108 data = '\n'.join([m.hgsub() for m in self.submoditer()])
108 data = '\n'.join([m.hgsub() for m in self.submoditer()])
109 mode = ''
109 mode = ''
110 elif name == '.hgsubstate':
110 elif name == '.hgsubstate':
111 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
111 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
112 mode = ''
112 mode = ''
113 else:
113 else:
114 data = self.catfile(rev, "blob")
114 data = self.catfile(rev, "blob")
115 mode = self.modecache[(name, rev)]
115 mode = self.modecache[(name, rev)]
116 return data, mode
116 return data, mode
117
117
118 def submoditer(self):
118 def submoditer(self):
119 null = hex(nullid)
119 null = hex(nullid)
120 for m in sorted(self.submodules, key=lambda p: p.path):
120 for m in sorted(self.submodules, key=lambda p: p.path):
121 if m.node != null:
121 if m.node != null:
122 yield m
122 yield m
123
123
124 def parsegitmodules(self, content):
124 def parsegitmodules(self, content):
125 """Parse the formatted .gitmodules file, example file format:
125 """Parse the formatted .gitmodules file, example file format:
126 [submodule "sub"]\n
126 [submodule "sub"]\n
127 \tpath = sub\n
127 \tpath = sub\n
128 \turl = git://giturl\n
128 \turl = git://giturl\n
129 """
129 """
130 self.submodules = []
130 self.submodules = []
131 c = config.config()
131 c = config.config()
132 # Each item in .gitmodules starts with \t that cant be parsed
132 # Each item in .gitmodules starts with \t that cant be parsed
133 c.parse('.gitmodules', content.replace('\t',''))
133 c.parse('.gitmodules', content.replace('\t',''))
134 for sec in c.sections():
134 for sec in c.sections():
135 s = c[sec]
135 s = c[sec]
136 if 'url' in s and 'path' in s:
136 if 'url' in s and 'path' in s:
137 self.submodules.append(submodule(s['path'], '', s['url']))
137 self.submodules.append(submodule(s['path'], '', s['url']))
138
138
139 def retrievegitmodules(self, version):
139 def retrievegitmodules(self, version):
140 modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
140 modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
141 if ret:
141 if ret:
142 raise util.Abort(_('cannot read submodules config file in %s') %
142 raise util.Abort(_('cannot read submodules config file in %s') %
143 version)
143 version)
144 self.parsegitmodules(modules)
144 self.parsegitmodules(modules)
145 for m in self.submodules:
145 for m in self.submodules:
146 node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
146 node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
147 if ret:
147 if ret:
148 continue
148 continue
149 m.node = node.strip()
149 m.node = node.strip()
150
150
151 def getchanges(self, version):
151 def getchanges(self, version):
152 self.modecache = {}
152 self.modecache = {}
153 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
153 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
154 changes = []
154 changes = []
155 seen = set()
155 seen = set()
156 entry = None
156 entry = None
157 subexists = False
157 subexists = False
158 for l in fh.read().split('\x00'):
158 for l in fh.read().split('\x00'):
159 if not entry:
159 if not entry:
160 if not l.startswith(':'):
160 if not l.startswith(':'):
161 continue
161 continue
162 entry = l
162 entry = l
163 continue
163 continue
164 f = l
164 f = l
165 if f not in seen:
165 if f not in seen:
166 seen.add(f)
166 seen.add(f)
167 entry = entry.split()
167 entry = entry.split()
168 h = entry[3]
168 h = entry[3]
169 p = (entry[1] == "100755")
169 p = (entry[1] == "100755")
170 s = (entry[1] == "120000")
170 s = (entry[1] == "120000")
171
171
172 if f == '.gitmodules':
172 if f == '.gitmodules':
173 subexists = True
173 subexists = True
174 changes.append(('.hgsub', ''))
174 changes.append(('.hgsub', ''))
175 elif entry[1] == '160000' or entry[0] == ':160000':
175 elif entry[1] == '160000' or entry[0] == ':160000':
176 subexists = True
176 subexists = True
177 else:
177 else:
178 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
178 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
179 changes.append((f, h))
179 changes.append((f, h))
180 entry = None
180 entry = None
181 if fh.close():
181 if fh.close():
182 raise util.Abort(_('cannot read changes in %s') % version)
182 raise util.Abort(_('cannot read changes in %s') % version)
183
183
184 if subexists:
184 if subexists:
185 self.retrievegitmodules(version)
185 self.retrievegitmodules(version)
186 changes.append(('.hgsubstate', ''))
186 changes.append(('.hgsubstate', ''))
187 return (changes, {})
187 return (changes, {})
188
188
189 def getcommit(self, version):
189 def getcommit(self, version):
190 c = self.catfile(version, "commit") # read the commit hash
190 c = self.catfile(version, "commit") # read the commit hash
191 end = c.find("\n\n")
191 end = c.find("\n\n")
192 message = c[end + 2:]
192 message = c[end + 2:]
193 message = self.recode(message)
193 message = self.recode(message)
194 l = c[:end].splitlines()
194 l = c[:end].splitlines()
195 parents = []
195 parents = []
196 author = committer = None
196 author = committer = None
197 for e in l[1:]:
197 for e in l[1:]:
198 n, v = e.split(" ", 1)
198 n, v = e.split(" ", 1)
199 if n == "author":
199 if n == "author":
200 p = v.split()
200 p = v.split()
201 tm, tz = p[-2:]
201 tm, tz = p[-2:]
202 author = " ".join(p[:-2])
202 author = " ".join(p[:-2])
203 if author[0] == "<": author = author[1:-1]
203 if author[0] == "<": author = author[1:-1]
204 author = self.recode(author)
204 author = self.recode(author)
205 if n == "committer":
205 if n == "committer":
206 p = v.split()
206 p = v.split()
207 tm, tz = p[-2:]
207 tm, tz = p[-2:]
208 committer = " ".join(p[:-2])
208 committer = " ".join(p[:-2])
209 if committer[0] == "<": committer = committer[1:-1]
209 if committer[0] == "<": committer = committer[1:-1]
210 committer = self.recode(committer)
210 committer = self.recode(committer)
211 if n == "parent":
211 if n == "parent":
212 parents.append(v)
212 parents.append(v)
213
213
214 if committer and committer != author:
214 if committer and committer != author:
215 message += "\ncommitter: %s\n" % committer
215 message += "\ncommitter: %s\n" % committer
216 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
216 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
217 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
217 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
218 date = tm + " " + str(tz)
218 date = tm + " " + str(tz)
219
219
220 c = commit(parents=parents, date=date, author=author, desc=message,
220 c = commit(parents=parents, date=date, author=author, desc=message,
221 rev=version)
221 rev=version)
222 return c
222 return c
223
223
224 def gettags(self):
224 def gettags(self):
225 tags = {}
225 tags = {}
226 alltags = {}
226 alltags = {}
227 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
227 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
228 err=subprocess.STDOUT)
228 err=subprocess.STDOUT)
229 prefix = 'refs/tags/'
229 prefix = 'refs/tags/'
230
230
231 # Build complete list of tags, both annotated and bare ones
231 # Build complete list of tags, both annotated and bare ones
232 for line in fh:
232 for line in fh:
233 line = line.strip()
233 line = line.strip()
234 if line.startswith("error:") or line.startswith("fatal:"):
234 if line.startswith("error:") or line.startswith("fatal:"):
235 raise util.Abort(_('cannot read tags from %s') % self.path)
235 raise util.Abort(_('cannot read tags from %s') % self.path)
236 node, tag = line.split(None, 1)
236 node, tag = line.split(None, 1)
237 if not tag.startswith(prefix):
237 if not tag.startswith(prefix):
238 continue
238 continue
239 alltags[tag[len(prefix):]] = node
239 alltags[tag[len(prefix):]] = node
240 if fh.close():
240 if fh.close():
241 raise util.Abort(_('cannot read tags from %s') % self.path)
241 raise util.Abort(_('cannot read tags from %s') % self.path)
242
242
243 # Filter out tag objects for annotated tag refs
243 # Filter out tag objects for annotated tag refs
244 for tag in alltags:
244 for tag in alltags:
245 if tag.endswith('^{}'):
245 if tag.endswith('^{}'):
246 tags[tag[:-3]] = alltags[tag]
246 tags[tag[:-3]] = alltags[tag]
247 else:
247 else:
248 if tag + '^{}' in alltags:
248 if tag + '^{}' in alltags:
249 continue
249 continue
250 else:
250 else:
251 tags[tag] = alltags[tag]
251 tags[tag] = alltags[tag]
252
252
253 return tags
253 return tags
254
254
255 def getchangedfiles(self, version, i):
255 def getchangedfiles(self, version, i):
256 changes = []
256 changes = []
257 if i is None:
257 if i is None:
258 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
258 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
259 for l in fh:
259 for l in fh:
260 if "\t" not in l:
260 if "\t" not in l:
261 continue
261 continue
262 m, f = l[:-1].split("\t")
262 m, f = l[:-1].split("\t")
263 changes.append(f)
263 changes.append(f)
264 else:
264 else:
265 fh = self.gitopen('git diff-tree --name-only --root -r %s '
265 fh = self.gitopen('git diff-tree --name-only --root -r %s '
266 '"%s^%s" --' % (version, version, i + 1))
266 '"%s^%s" --' % (version, version, i + 1))
267 changes = [f.rstrip('\n') for f in fh]
267 changes = [f.rstrip('\n') for f in fh]
268 if fh.close():
268 if fh.close():
269 raise util.Abort(_('cannot read changes in %s') % version)
269 raise util.Abort(_('cannot read changes in %s') % version)
270
270
271 return changes
271 return changes
272
272
273 def getbookmarks(self):
273 def getbookmarks(self):
274 bookmarks = {}
274 bookmarks = {}
275
275
276 # Interesting references in git are prefixed
276 # Interesting references in git are prefixed
277 prefix = 'refs/heads/'
277 prefix = 'refs/heads/'
278 prefixlen = len(prefix)
278 prefixlen = len(prefix)
279
279
280 # factor two commands
280 # factor two commands
281 gitcmd = { 'remote/': 'git ls-remote --heads origin',
281 gitcmd = { 'remote/': 'git ls-remote --heads origin',
282 '': 'git show-ref'}
282 '': 'git show-ref'}
283
283
284 # Origin heads
284 # Origin heads
285 for reftype in gitcmd:
285 for reftype in gitcmd:
286 try:
286 try:
287 fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
287 fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
288 for line in fh:
288 for line in fh:
289 line = line.strip()
289 line = line.strip()
290 rev, name = line.split(None, 1)
290 rev, name = line.split(None, 1)
291 if not name.startswith(prefix):
291 if not name.startswith(prefix):
292 continue
292 continue
293 name = '%s%s' % (reftype, name[prefixlen:])
293 name = '%s%s' % (reftype, name[prefixlen:])
294 bookmarks[name] = rev
294 bookmarks[name] = rev
295 except Exception:
295 except Exception:
296 pass
296 pass
297
297
298 return bookmarks
298 return bookmarks
299
300 def checkrevformat(self, revstr):
301 """ git revision string is a 40 byte hex """
302 self.checkhexformat(revstr)
303
@@ -1,358 +1,392 b''
1
1
2 $ "$TESTDIR/hghave" git || exit 80
2 $ "$TESTDIR/hghave" git || exit 80
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 $ echo 'hgext.graphlog =' >> $HGRCPATH
9 $ echo 'hgext.graphlog =' >> $HGRCPATH
10 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
10 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
11 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
11 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
12 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
12 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
13 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
13 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
14 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
14 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
15 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
15 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
16 $ INVALIDID1=afd12345af
17 $ INVALIDID2=28173x36ddd1e67bf7098d541130558ef5534a86
18 $ VALIDID1=39b3d83f9a69a9ba4ebb111461071a0af0027357
19 $ VALIDID2=8dd6476bd09d9c7776355dc454dafe38efaec5da
16 $ count=10
20 $ count=10
17 $ commit()
21 $ commit()
18 > {
22 > {
19 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
23 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
20 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
24 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
21 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
25 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
22 > count=`expr $count + 1`
26 > count=`expr $count + 1`
23 > }
27 > }
24 $ mkdir git-repo
28 $ mkdir git-repo
25 $ cd git-repo
29 $ cd git-repo
26 $ git init-db >/dev/null 2>/dev/null
30 $ git init-db >/dev/null 2>/dev/null
27 $ echo a > a
31 $ echo a > a
28 $ mkdir d
32 $ mkdir d
29 $ echo b > d/b
33 $ echo b > d/b
30 $ git add a d
34 $ git add a d
31 $ commit -a -m t1
35 $ commit -a -m t1
32
36
33 Remove the directory, then try to replace it with a file
37 Remove the directory, then try to replace it with a file
34 (issue 754)
38 (issue 754)
35
39
36 $ git rm -f d/b
40 $ git rm -f d/b
37 rm 'd/b'
41 rm 'd/b'
38 $ commit -m t2
42 $ commit -m t2
39 $ echo d > d
43 $ echo d > d
40 $ git add d
44 $ git add d
41 $ commit -m t3
45 $ commit -m t3
42 $ echo b >> a
46 $ echo b >> a
43 $ commit -a -m t4.1
47 $ commit -a -m t4.1
44 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
48 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
45 $ echo c > a
49 $ echo c > a
46 $ echo a >> a
50 $ echo a >> a
47 $ commit -a -m t4.2
51 $ commit -a -m t4.2
48 $ git checkout master >/dev/null 2>/dev/null
52 $ git checkout master >/dev/null 2>/dev/null
49 $ git pull --no-commit . other > /dev/null 2>/dev/null
53 $ git pull --no-commit . other > /dev/null 2>/dev/null
50 $ commit -m 'Merge branch other'
54 $ commit -m 'Merge branch other'
51 $ cd ..
55 $ cd ..
52 $ hg convert --datesort git-repo
56 $ hg convert --datesort git-repo
53 assuming destination git-repo-hg
57 assuming destination git-repo-hg
54 initializing destination git-repo-hg repository
58 initializing destination git-repo-hg repository
55 scanning source...
59 scanning source...
56 sorting...
60 sorting...
57 converting...
61 converting...
58 5 t1
62 5 t1
59 4 t2
63 4 t2
60 3 t3
64 3 t3
61 2 t4.1
65 2 t4.1
62 1 t4.2
66 1 t4.2
63 0 Merge branch other
67 0 Merge branch other
64 updating bookmarks
68 updating bookmarks
65 $ hg up -q -R git-repo-hg
69 $ hg up -q -R git-repo-hg
66 $ hg -R git-repo-hg tip -v
70 $ hg -R git-repo-hg tip -v
67 changeset: 5:c78094926be2
71 changeset: 5:c78094926be2
68 bookmark: master
72 bookmark: master
69 tag: tip
73 tag: tip
70 parent: 3:f5f5cb45432b
74 parent: 3:f5f5cb45432b
71 parent: 4:4e174f80c67c
75 parent: 4:4e174f80c67c
72 user: test <test@example.org>
76 user: test <test@example.org>
73 date: Mon Jan 01 00:00:15 2007 +0000
77 date: Mon Jan 01 00:00:15 2007 +0000
74 files: a
78 files: a
75 description:
79 description:
76 Merge branch other
80 Merge branch other
77
81
78
82
79 $ count=10
83 $ count=10
80 $ mkdir git-repo2
84 $ mkdir git-repo2
81 $ cd git-repo2
85 $ cd git-repo2
82 $ git init-db >/dev/null 2>/dev/null
86 $ git init-db >/dev/null 2>/dev/null
83 $ echo foo > foo
87 $ echo foo > foo
84 $ git add foo
88 $ git add foo
85 $ commit -a -m 'add foo'
89 $ commit -a -m 'add foo'
86 $ echo >> foo
90 $ echo >> foo
87 $ commit -a -m 'change foo'
91 $ commit -a -m 'change foo'
88 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
92 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
89 $ echo quux >> quux
93 $ echo quux >> quux
90 $ git add quux
94 $ git add quux
91 $ commit -a -m 'add quux'
95 $ commit -a -m 'add quux'
92 $ echo bar > bar
96 $ echo bar > bar
93 $ git add bar
97 $ git add bar
94 $ commit -a -m 'add bar'
98 $ commit -a -m 'add bar'
95 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
99 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
96 $ echo baz > baz
100 $ echo baz > baz
97 $ git add baz
101 $ git add baz
98 $ commit -a -m 'add baz'
102 $ commit -a -m 'add baz'
99 $ git checkout master >/dev/null 2>/dev/null
103 $ git checkout master >/dev/null 2>/dev/null
100 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
104 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
101 $ commit -m 'Octopus merge'
105 $ commit -m 'Octopus merge'
102 $ echo bar >> bar
106 $ echo bar >> bar
103 $ commit -a -m 'change bar'
107 $ commit -a -m 'change bar'
104 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
108 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
105 $ echo >> foo
109 $ echo >> foo
106 $ commit -a -m 'change foo'
110 $ commit -a -m 'change foo'
107 $ git checkout master >/dev/null 2>/dev/null
111 $ git checkout master >/dev/null 2>/dev/null
108 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
112 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
109 $ commit -m 'Discard change to foo'
113 $ commit -m 'Discard change to foo'
110 $ cd ..
114 $ cd ..
111 $ glog()
115 $ glog()
112 > {
116 > {
113 > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
117 > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
114 > }
118 > }
115 $ splitrepo()
119 $ splitrepo()
116 > {
120 > {
117 > msg="$1"
121 > msg="$1"
118 > files="$2"
122 > files="$2"
119 > opts=$3
123 > opts=$3
120 > echo "% $files: $msg"
124 > echo "% $files: $msg"
121 > prefix=`echo "$files" | sed -e 's/ /-/g'`
125 > prefix=`echo "$files" | sed -e 's/ /-/g'`
122 > fmap="$prefix.fmap"
126 > fmap="$prefix.fmap"
123 > repo="$prefix.repo"
127 > repo="$prefix.repo"
124 > for i in $files; do
128 > for i in $files; do
125 > echo "include $i" >> "$fmap"
129 > echo "include $i" >> "$fmap"
126 > done
130 > done
127 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
131 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
128 > hg up -q -R "$repo"
132 > hg up -q -R "$repo"
129 > glog -R "$repo"
133 > glog -R "$repo"
130 > hg -R "$repo" manifest --debug
134 > hg -R "$repo" manifest --debug
131 > }
135 > }
132
136
133 full conversion
137 full conversion
134
138
135 $ hg -q convert --datesort git-repo2 fullrepo
139 $ hg -q convert --datesort git-repo2 fullrepo
136 $ hg up -q -R fullrepo
140 $ hg up -q -R fullrepo
137 $ glog -R fullrepo
141 $ glog -R fullrepo
138 @ 9 "Discard change to foo" files: foo
142 @ 9 "Discard change to foo" files: foo
139 |\
143 |\
140 | o 8 "change foo" files: foo
144 | o 8 "change foo" files: foo
141 | |
145 | |
142 o | 7 "change bar" files: bar
146 o | 7 "change bar" files: bar
143 |/
147 |/
144 o 6 "(octopus merge fixup)" files:
148 o 6 "(octopus merge fixup)" files:
145 |\
149 |\
146 | o 5 "Octopus merge" files: baz
150 | o 5 "Octopus merge" files: baz
147 | |\
151 | |\
148 o | | 4 "add baz" files: baz
152 o | | 4 "add baz" files: baz
149 | | |
153 | | |
150 +---o 3 "add bar" files: bar
154 +---o 3 "add bar" files: bar
151 | |
155 | |
152 o | 2 "add quux" files: quux
156 o | 2 "add quux" files: quux
153 | |
157 | |
154 | o 1 "change foo" files: foo
158 | o 1 "change foo" files: foo
155 |/
159 |/
156 o 0 "add foo" files: foo
160 o 0 "add foo" files: foo
157
161
158 $ hg -R fullrepo manifest --debug
162 $ hg -R fullrepo manifest --debug
159 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
163 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
160 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
164 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
161 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
165 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
162 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
166 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
163 $ splitrepo 'octopus merge' 'foo bar baz'
167 $ splitrepo 'octopus merge' 'foo bar baz'
164 % foo bar baz: octopus merge
168 % foo bar baz: octopus merge
165 @ 8 "Discard change to foo" files: foo
169 @ 8 "Discard change to foo" files: foo
166 |\
170 |\
167 | o 7 "change foo" files: foo
171 | o 7 "change foo" files: foo
168 | |
172 | |
169 o | 6 "change bar" files: bar
173 o | 6 "change bar" files: bar
170 |/
174 |/
171 o 5 "(octopus merge fixup)" files:
175 o 5 "(octopus merge fixup)" files:
172 |\
176 |\
173 | o 4 "Octopus merge" files: baz
177 | o 4 "Octopus merge" files: baz
174 | |\
178 | |\
175 o | | 3 "add baz" files: baz
179 o | | 3 "add baz" files: baz
176 | | |
180 | | |
177 +---o 2 "add bar" files: bar
181 +---o 2 "add bar" files: bar
178 | |
182 | |
179 | o 1 "change foo" files: foo
183 | o 1 "change foo" files: foo
180 |/
184 |/
181 o 0 "add foo" files: foo
185 o 0 "add foo" files: foo
182
186
183 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
187 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
184 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
188 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
185 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
189 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
186 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
190 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
187 % foo baz quux: only some parents of an octopus merge; "discard" a head
191 % foo baz quux: only some parents of an octopus merge; "discard" a head
188 @ 6 "Discard change to foo" files: foo
192 @ 6 "Discard change to foo" files: foo
189 |
193 |
190 o 5 "change foo" files: foo
194 o 5 "change foo" files: foo
191 |
195 |
192 o 4 "Octopus merge" files:
196 o 4 "Octopus merge" files:
193 |\
197 |\
194 | o 3 "add baz" files: baz
198 | o 3 "add baz" files: baz
195 | |
199 | |
196 | o 2 "add quux" files: quux
200 | o 2 "add quux" files: quux
197 | |
201 | |
198 o | 1 "change foo" files: foo
202 o | 1 "change foo" files: foo
199 |/
203 |/
200 o 0 "add foo" files: foo
204 o 0 "add foo" files: foo
201
205
202 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
206 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
203 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
207 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
204 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
208 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
205
209
206 test binary conversion (issue 1359)
210 test binary conversion (issue 1359)
207
211
208 $ mkdir git-repo3
212 $ mkdir git-repo3
209 $ cd git-repo3
213 $ cd git-repo3
210 $ git init-db >/dev/null 2>/dev/null
214 $ git init-db >/dev/null 2>/dev/null
211 $ python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
215 $ python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
212 $ git add b
216 $ git add b
213 $ commit -a -m addbinary
217 $ commit -a -m addbinary
214 $ cd ..
218 $ cd ..
215
219
216 convert binary file
220 convert binary file
217
221
218 $ hg convert git-repo3 git-repo3-hg
222 $ hg convert git-repo3 git-repo3-hg
219 initializing destination git-repo3-hg repository
223 initializing destination git-repo3-hg repository
220 scanning source...
224 scanning source...
221 sorting...
225 sorting...
222 converting...
226 converting...
223 0 addbinary
227 0 addbinary
224 updating bookmarks
228 updating bookmarks
225 $ cd git-repo3-hg
229 $ cd git-repo3-hg
226 $ hg up -C
230 $ hg up -C
227 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
228 $ python -c 'print len(file("b", "rb").read())'
232 $ python -c 'print len(file("b", "rb").read())'
229 4096
233 4096
230 $ cd ..
234 $ cd ..
231
235
232 test author vs committer
236 test author vs committer
233
237
234 $ mkdir git-repo4
238 $ mkdir git-repo4
235 $ cd git-repo4
239 $ cd git-repo4
236 $ git init-db >/dev/null 2>/dev/null
240 $ git init-db >/dev/null 2>/dev/null
237 $ echo >> foo
241 $ echo >> foo
238 $ git add foo
242 $ git add foo
239 $ commit -a -m addfoo
243 $ commit -a -m addfoo
240 $ echo >> foo
244 $ echo >> foo
241 $ GIT_AUTHOR_NAME="nottest"
245 $ GIT_AUTHOR_NAME="nottest"
242 $ commit -a -m addfoo2
246 $ commit -a -m addfoo2
243 $ cd ..
247 $ cd ..
244
248
245 convert author committer
249 convert author committer
246
250
247 $ hg convert git-repo4 git-repo4-hg
251 $ hg convert git-repo4 git-repo4-hg
248 initializing destination git-repo4-hg repository
252 initializing destination git-repo4-hg repository
249 scanning source...
253 scanning source...
250 sorting...
254 sorting...
251 converting...
255 converting...
252 1 addfoo
256 1 addfoo
253 0 addfoo2
257 0 addfoo2
254 updating bookmarks
258 updating bookmarks
255 $ hg -R git-repo4-hg log -v
259 $ hg -R git-repo4-hg log -v
256 changeset: 1:d63e967f93da
260 changeset: 1:d63e967f93da
257 bookmark: master
261 bookmark: master
258 tag: tip
262 tag: tip
259 user: nottest <test@example.org>
263 user: nottest <test@example.org>
260 date: Mon Jan 01 00:00:21 2007 +0000
264 date: Mon Jan 01 00:00:21 2007 +0000
261 files: foo
265 files: foo
262 description:
266 description:
263 addfoo2
267 addfoo2
264
268
265 committer: test <test@example.org>
269 committer: test <test@example.org>
266
270
267
271
268 changeset: 0:0735477b0224
272 changeset: 0:0735477b0224
269 user: test <test@example.org>
273 user: test <test@example.org>
270 date: Mon Jan 01 00:00:20 2007 +0000
274 date: Mon Jan 01 00:00:20 2007 +0000
271 files: foo
275 files: foo
272 description:
276 description:
273 addfoo
277 addfoo
274
278
275
279
276
280
277 --sourceorder should fail
281 --sourceorder should fail
278
282
279 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
283 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
280 initializing destination git-repo4-sourcesort-hg repository
284 initializing destination git-repo4-sourcesort-hg repository
281 abort: --sourcesort is not supported by this data source
285 abort: --sourcesort is not supported by this data source
282 [255]
286 [255]
283
287
284 test sub modules
288 test sub modules
285
289
286 $ mkdir git-repo5
290 $ mkdir git-repo5
287 $ cd git-repo5
291 $ cd git-repo5
288 $ git init-db >/dev/null 2>/dev/null
292 $ git init-db >/dev/null 2>/dev/null
289 $ echo 'sub' >> foo
293 $ echo 'sub' >> foo
290 $ git add foo
294 $ git add foo
291 $ commit -a -m 'addfoo'
295 $ commit -a -m 'addfoo'
292 $ BASE=`pwd`
296 $ BASE=`pwd`
293 $ cd ..
297 $ cd ..
294 $ mkdir git-repo6
298 $ mkdir git-repo6
295 $ cd git-repo6
299 $ cd git-repo6
296 $ git init-db >/dev/null 2>/dev/null
300 $ git init-db >/dev/null 2>/dev/null
297 $ git submodule add ${BASE} >/dev/null 2>/dev/null
301 $ git submodule add ${BASE} >/dev/null 2>/dev/null
298 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
302 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
299 $ cd ..
303 $ cd ..
300
304
305 test invalid splicemap1
306
307 $ cat > splicemap <<EOF
308 > $VALIDID1
309 > EOF
310 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap1-hg
311 initializing destination git-repo2-splicemap1-hg repository
312 abort: syntax error in splicemap(1): child parent1[,parent2] expected
313 [255]
314
315 test invalid splicemap2
316
317 $ cat > splicemap <<EOF
318 > $VALIDID1 $VALIDID2, $VALIDID2, $VALIDID2
319 > EOF
320 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap2-hg
321 initializing destination git-repo2-splicemap2-hg repository
322 abort: syntax error in splicemap(1): child parent1[,parent2] expected
323 [255]
324
325 test invalid splicemap3
326
327 $ cat > splicemap <<EOF
328 > $INVALIDID1 $INVALIDID2
329 > EOF
330 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap3-hg
331 initializing destination git-repo2-splicemap3-hg repository
332 abort: splicemap entry afd12345af is not a valid revision identifier
333 [255]
334
301 convert sub modules
335 convert sub modules
302 $ hg convert git-repo6 git-repo6-hg
336 $ hg convert git-repo6 git-repo6-hg
303 initializing destination git-repo6-hg repository
337 initializing destination git-repo6-hg repository
304 scanning source...
338 scanning source...
305 sorting...
339 sorting...
306 converting...
340 converting...
307 0 addsubmodule
341 0 addsubmodule
308 updating bookmarks
342 updating bookmarks
309 $ hg -R git-repo6-hg log -v
343 $ hg -R git-repo6-hg log -v
310 changeset: 0:* (glob)
344 changeset: 0:* (glob)
311 bookmark: master
345 bookmark: master
312 tag: tip
346 tag: tip
313 user: nottest <test@example.org>
347 user: nottest <test@example.org>
314 date: Mon Jan 01 00:00:23 2007 +0000
348 date: Mon Jan 01 00:00:23 2007 +0000
315 files: .hgsub .hgsubstate
349 files: .hgsub .hgsubstate
316 description:
350 description:
317 addsubmodule
351 addsubmodule
318
352
319 committer: test <test@example.org>
353 committer: test <test@example.org>
320
354
321
355
322
356
323 $ cd git-repo6-hg
357 $ cd git-repo6-hg
324 $ hg up >/dev/null 2>/dev/null
358 $ hg up >/dev/null 2>/dev/null
325 $ cat .hgsubstate
359 $ cat .hgsubstate
326 * git-repo5 (glob)
360 * git-repo5 (glob)
327 $ cd git-repo5
361 $ cd git-repo5
328 $ cat foo
362 $ cat foo
329 sub
363 sub
330
364
331 $ cd ../..
365 $ cd ../..
332
366
333 damaged git repository tests:
367 damaged git repository tests:
334 In case the hard-coded hashes change, the following commands can be used to
368 In case the hard-coded hashes change, the following commands can be used to
335 list the hashes and their corresponding types in the repository:
369 list the hashes and their corresponding types in the repository:
336 cd git-repo4/.git/objects
370 cd git-repo4/.git/objects
337 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
371 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
338 cd ../../..
372 cd ../../..
339
373
340 damage git repository by renaming a commit object
374 damage git repository by renaming a commit object
341 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
375 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
342 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
376 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
343 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
377 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
344 abort: cannot read tags from git-repo4/.git
378 abort: cannot read tags from git-repo4/.git
345 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
379 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
346 damage git repository by renaming a blob object
380 damage git repository by renaming a blob object
347
381
348 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
382 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
349 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
383 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
350 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
384 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
351 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
385 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
352 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
386 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
353 damage git repository by renaming a tree object
387 damage git repository by renaming a tree object
354
388
355 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
389 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
356 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
390 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
357 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
391 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
358 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
392 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
General Comments 0
You need to be logged in to leave comments. Login now