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