##// END OF EJS Templates
convert/bzr: convert all branches (issue3229) (BC)...
Patrick Mezard -
r16060:f84dda15 default
parent child Browse files
Show More
@@ -1,265 +1,280
1 1 # bzr.py - bzr support for the convert extension
2 2 #
3 3 # Copyright 2008, 2009 Marek Kubica <marek@xivilization.net> 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 # This module is for handling 'bzr', that was formerly known as Bazaar-NG;
9 9 # it cannot access 'bar' repositories, but they were never used very much
10 10
11 11 import os
12 12 from mercurial import demandimport
13 13 # these do not work with demandimport, blacklist
14 14 demandimport.ignore.extend([
15 15 'bzrlib.transactions',
16 16 'bzrlib.urlutils',
17 17 'ElementPath',
18 18 ])
19 19
20 20 from mercurial.i18n import _
21 21 from mercurial import util
22 22 from common import NoRepo, commit, converter_source
23 23
24 24 try:
25 25 # bazaar imports
26 from bzrlib import branch, revision, errors
26 from bzrlib import bzrdir, revision, errors
27 27 from bzrlib.revisionspec import RevisionSpec
28 28 except ImportError:
29 29 pass
30 30
31 31 supportedkinds = ('file', 'symlink')
32 32
33 33 class bzr_source(converter_source):
34 34 """Reads Bazaar repositories by using the Bazaar Python libraries"""
35 35
36 36 def __init__(self, ui, path, rev=None):
37 37 super(bzr_source, self).__init__(ui, path, rev=rev)
38 38
39 39 if not os.path.exists(os.path.join(path, '.bzr')):
40 40 raise NoRepo(_('%s does not look like a Bazaar repository')
41 41 % path)
42 42
43 43 try:
44 44 # access bzrlib stuff
45 branch
45 bzrdir
46 46 except NameError:
47 47 raise NoRepo(_('Bazaar modules could not be loaded'))
48 48
49 49 path = os.path.abspath(path)
50 50 self._checkrepotype(path)
51 self.branch = branch.Branch.open(path)
52 self.sourcerepo = self.branch.repository
51 try:
52 self.sourcerepo = bzrdir.BzrDir.open(path).open_repository()
53 except errors.NoRepositoryPresent:
54 raise NoRepo(_('%s does not look like a Bazaar repository')
55 % path)
53 56 self._parentids = {}
54 57
55 58 def _checkrepotype(self, path):
56 59 # Lightweight checkouts detection is informational but probably
57 60 # fragile at API level. It should not terminate the conversion.
58 61 try:
59 62 from bzrlib import bzrdir
60 63 dir = bzrdir.BzrDir.open_containing(path)[0]
61 64 try:
62 65 tree = dir.open_workingtree(recommend_upgrade=False)
63 66 branch = tree.branch
64 67 except (errors.NoWorkingTree, errors.NotLocalUrl):
65 68 tree = None
66 69 branch = dir.open_branch()
67 70 if (tree is not None and tree.bzrdir.root_transport.base !=
68 71 branch.bzrdir.root_transport.base):
69 72 self.ui.warn(_('warning: lightweight checkouts may cause '
70 73 'conversion failures, try with a regular '
71 74 'branch instead.\n'))
72 75 except:
73 76 self.ui.note(_('bzr source type could not be determined\n'))
74 77
75 78 def before(self):
76 79 """Before the conversion begins, acquire a read lock
77 80 for all the operations that might need it. Fortunately
78 81 read locks don't block other reads or writes to the
79 82 repository, so this shouldn't have any impact on the usage of
80 83 the source repository.
81 84
82 85 The alternative would be locking on every operation that
83 86 needs locks (there are currently two: getting the file and
84 87 getting the parent map) and releasing immediately after,
85 88 but this approach can take even 40% longer."""
86 89 self.sourcerepo.lock_read()
87 90
88 91 def after(self):
89 92 self.sourcerepo.unlock()
90 93
91 94 def getheads(self):
92 95 if not self.rev:
93 return [self.branch.last_revision()]
94 try:
95 r = RevisionSpec.from_string(self.rev)
96 info = r.in_history(self.branch)
97 except errors.BzrError:
98 raise util.Abort(_('%s is not a valid revision in current branch')
99 % self.rev)
100 return [info.rev_id]
96 heads = sorted([b.last_revision()
97 for b in self.sourcerepo.find_branches()])
98 else:
99 revid = None
100 for branch in self.sourcerepo.find_branches():
101 try:
102 r = RevisionSpec.from_string(self.rev)
103 info = r.in_history(branch)
104 except errors.BzrError:
105 pass
106 revid = info.rev_id
107 if revid is None:
108 raise util.Abort(_('%s is not a valid revision') % self.rev)
109 heads = [revid]
110 return heads
101 111
102 112 def getfile(self, name, rev):
103 113 revtree = self.sourcerepo.revision_tree(rev)
104 114 fileid = revtree.path2id(name.decode(self.encoding or 'utf-8'))
105 115 kind = None
106 116 if fileid is not None:
107 117 kind = revtree.kind(fileid)
108 118 if kind not in supportedkinds:
109 119 # the file is not available anymore - was deleted
110 120 raise IOError(_('%s is not available in %s anymore') %
111 121 (name, rev))
112 122 mode = self._modecache[(name, rev)]
113 123 if kind == 'symlink':
114 124 target = revtree.get_symlink_target(fileid)
115 125 if target is None:
116 126 raise util.Abort(_('%s.%s symlink has no target')
117 127 % (name, rev))
118 128 return target, mode
119 129 else:
120 130 sio = revtree.get_file(fileid)
121 131 return sio.read(), mode
122 132
123 133 def getchanges(self, version):
124 134 # set up caches: modecache and revtree
125 135 self._modecache = {}
126 136 self._revtree = self.sourcerepo.revision_tree(version)
127 137 # get the parentids from the cache
128 138 parentids = self._parentids.pop(version)
129 139 # only diff against first parent id
130 140 prevtree = self.sourcerepo.revision_tree(parentids[0])
131 141 return self._gettreechanges(self._revtree, prevtree)
132 142
133 143 def getcommit(self, version):
134 144 rev = self.sourcerepo.get_revision(version)
135 145 # populate parent id cache
136 146 if not rev.parent_ids:
137 147 parents = []
138 148 self._parentids[version] = (revision.NULL_REVISION,)
139 149 else:
140 150 parents = self._filterghosts(rev.parent_ids)
141 151 self._parentids[version] = parents
142 152
153 branch = self.recode(rev.properties.get('branch-nick', u'default'))
154 if branch == 'trunk':
155 branch = 'default'
143 156 return commit(parents=parents,
144 157 date='%d %d' % (rev.timestamp, -rev.timezone),
145 158 author=self.recode(rev.committer),
146 159 desc=self.recode(rev.message),
160 branch=branch,
147 161 rev=version)
148 162
149 163 def gettags(self):
150 if not self.branch.supports_tags():
151 return {}
152 tagdict = self.branch.tags.get_tag_dict()
153 164 bytetags = {}
154 for name, rev in tagdict.iteritems():
155 bytetags[self.recode(name)] = rev
165 for branch in self.sourcerepo.find_branches():
166 if not branch.supports_tags():
167 return {}
168 tagdict = branch.tags.get_tag_dict()
169 for name, rev in tagdict.iteritems():
170 bytetags[self.recode(name)] = rev
156 171 return bytetags
157 172
158 173 def getchangedfiles(self, rev, i):
159 174 self._modecache = {}
160 175 curtree = self.sourcerepo.revision_tree(rev)
161 176 if i is not None:
162 177 parentid = self._parentids[rev][i]
163 178 else:
164 179 # no parent id, get the empty revision
165 180 parentid = revision.NULL_REVISION
166 181
167 182 prevtree = self.sourcerepo.revision_tree(parentid)
168 183 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
169 184 return changes
170 185
171 186 def _gettreechanges(self, current, origin):
172 187 revid = current._revision_id
173 188 changes = []
174 189 renames = {}
175 190 seen = set()
176 191 # Process the entries by reverse lexicographic name order to
177 192 # handle nested renames correctly, most specific first.
178 193 curchanges = sorted(current.iter_changes(origin),
179 194 key=lambda c: c[1][0] or c[1][1],
180 195 reverse=True)
181 196 for (fileid, paths, changed_content, versioned, parent, name,
182 197 kind, executable) in curchanges:
183 198
184 199 if paths[0] == u'' or paths[1] == u'':
185 200 # ignore changes to tree root
186 201 continue
187 202
188 203 # bazaar tracks directories, mercurial does not, so
189 204 # we have to rename the directory contents
190 205 if kind[1] == 'directory':
191 206 if kind[0] not in (None, 'directory'):
192 207 # Replacing 'something' with a directory, record it
193 208 # so it can be removed.
194 209 changes.append((self.recode(paths[0]), revid))
195 210
196 211 if kind[0] == 'directory' and None not in paths:
197 212 renaming = paths[0] != paths[1]
198 213 # neither an add nor an delete - a move
199 214 # rename all directory contents manually
200 215 subdir = origin.inventory.path2id(paths[0])
201 216 # get all child-entries of the directory
202 217 for name, entry in origin.inventory.iter_entries(subdir):
203 218 # hg does not track directory renames
204 219 if entry.kind == 'directory':
205 220 continue
206 221 frompath = self.recode(paths[0] + '/' + name)
207 222 if frompath in seen:
208 223 # Already handled by a more specific change entry
209 224 # This is important when you have:
210 225 # a => b
211 226 # a/c => a/c
212 227 # Here a/c must not be renamed into b/c
213 228 continue
214 229 seen.add(frompath)
215 230 if not renaming:
216 231 continue
217 232 topath = self.recode(paths[1] + '/' + name)
218 233 # register the files as changed
219 234 changes.append((frompath, revid))
220 235 changes.append((topath, revid))
221 236 # add to mode cache
222 237 mode = ((entry.executable and 'x')
223 238 or (entry.kind == 'symlink' and 's')
224 239 or '')
225 240 self._modecache[(topath, revid)] = mode
226 241 # register the change as move
227 242 renames[topath] = frompath
228 243
229 244 # no futher changes, go to the next change
230 245 continue
231 246
232 247 # we got unicode paths, need to convert them
233 248 path, topath = paths
234 249 if path is not None:
235 250 path = self.recode(path)
236 251 if topath is not None:
237 252 topath = self.recode(topath)
238 253 seen.add(path or topath)
239 254
240 255 if topath is None:
241 256 # file deleted
242 257 changes.append((path, revid))
243 258 continue
244 259
245 260 # renamed
246 261 if path and path != topath:
247 262 renames[topath] = path
248 263 changes.append((path, revid))
249 264
250 265 # populate the mode cache
251 266 kind, executable = [e[1] for e in (kind, executable)]
252 267 mode = ((executable and 'x') or (kind == 'symlink' and 'l')
253 268 or '')
254 269 self._modecache[(topath, revid)] = mode
255 270 changes.append((topath, revid))
256 271
257 272 return changes, renames
258 273
259 274 def _filterghosts(self, ids):
260 275 """Filters out ghost revisions which hg does not support, see
261 276 <http://bazaar-vcs.org/GhostRevision>
262 277 """
263 278 parentmap = self.sourcerepo.get_parent_map(ids)
264 279 parents = tuple([parent for parent in ids if parent in parentmap])
265 280 return parents
@@ -1,19 +1,19
1 1 # this file holds the definitions that are used in various bzr tests
2 2
3 3 "$TESTDIR/hghave" bzr || exit 80
4 4
5 5 TERM=dumb; export TERM
6 6 echo '[extensions]' >> $HGRCPATH
7 7 echo 'convert = ' >> $HGRCPATH
8 8 echo 'hgext.graphlog = ' >> $HGRCPATH
9 9
10 10 glog()
11 11 {
12 hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
12 hg glog --template '{rev}@{branch} "{desc|firstline}" files: {files}\n' "$@"
13 13 }
14 14
15 15 manifest()
16 16 {
17 17 echo "% manifest of $2"
18 18 hg -R $1 manifest -v -r $2
19 19 }
@@ -1,36 +1,36
1 1
2 2 $ . "$TESTDIR/bzr-definitions"
3 3 $ cat > ghostcreator.py <<EOF
4 4 > import sys
5 5 > from bzrlib import workingtree
6 6 > wt = workingtree.WorkingTree.open('.')
7 7 >
8 8 > message, ghostrev = sys.argv[1:]
9 9 > wt.set_parent_ids(wt.get_parent_ids() + [ghostrev])
10 10 > wt.commit(message)
11 11 > EOF
12 12
13 13 ghost revisions
14 14
15 15 $ mkdir test-ghost-revisions
16 16 $ cd test-ghost-revisions
17 17 $ bzr init -q source
18 18 $ cd source
19 19 $ echo content > somefile
20 20 $ bzr add -q somefile
21 21 $ bzr commit -q -m 'Initial layout setup'
22 22 $ echo morecontent >> somefile
23 23 $ python ../../ghostcreator.py 'Commit with ghost revision' ghostrev
24 24 $ cd ..
25 25 $ hg convert source source-hg
26 26 initializing destination source-hg repository
27 27 scanning source...
28 28 sorting...
29 29 converting...
30 30 1 Initial layout setup
31 31 0 Commit with ghost revision
32 32 $ glog -R source-hg
33 o 1 "Commit with ghost revision" files: somefile
33 o 1@source "Commit with ghost revision" files: somefile
34 34 |
35 o 0 "Initial layout setup" files: somefile
35 o 0@source "Initial layout setup" files: somefile
36 36
@@ -1,68 +1,68
1 1 N.B. bzr 1.13 has a bug that breaks this test. If you see this
2 2 test fail, check your bzr version. Upgrading to bzr 1.13.1
3 3 should fix it.
4 4
5 5 $ . "$TESTDIR/bzr-definitions"
6 6
7 7 test multiple merges at once
8 8
9 9 $ mkdir test-multimerge
10 10 $ cd test-multimerge
11 11 $ bzr init -q source
12 12 $ cd source
13 13 $ echo content > file
14 14 $ bzr add -q file
15 15 $ bzr commit -q -m 'Initial add'
16 16 $ cd ..
17 17 $ bzr branch -q source source-branch1
18 18 $ cd source-branch1
19 19 $ echo morecontent >> file
20 20 $ echo evenmorecontent > file-branch1
21 21 $ bzr add -q file-branch1
22 22 $ bzr commit -q -m 'Added branch1 file'
23 23 $ cd ../source
24 24 $ sleep 1
25 25 $ echo content > file-parent
26 26 $ bzr add -q file-parent
27 27 $ bzr commit -q -m 'Added parent file'
28 28 $ cd ..
29 29 $ bzr branch -q source source-branch2
30 30 $ cd source-branch2
31 31 $ echo somecontent > file-branch2
32 32 $ bzr add -q file-branch2
33 33 $ bzr commit -q -m 'Added brach2 file'
34 34 $ sleep 1
35 35 $ cd ../source
36 36 $ bzr merge -q ../source-branch1
37 37 $ bzr merge -q --force ../source-branch2
38 38 $ bzr commit -q -m 'Merged branches'
39 39 $ cd ..
40 40 $ hg convert --datesort source source-hg
41 41 initializing destination source-hg repository
42 42 scanning source...
43 43 sorting...
44 44 converting...
45 45 4 Initial add
46 46 3 Added branch1 file
47 47 2 Added parent file
48 48 1 Added brach2 file
49 49 0 Merged branches
50 50 $ glog -R source-hg
51 o 5 "(octopus merge fixup)" files:
51 o 5@source "(octopus merge fixup)" files:
52 52 |\
53 | o 4 "Merged branches" files: file-branch2
53 | o 4@source "Merged branches" files: file-branch2
54 54 | |\
55 o---+ 3 "Added brach2 file" files: file-branch2
55 o---+ 3@source-branch2 "Added brach2 file" files: file-branch2
56 56 / /
57 | o 2 "Added parent file" files: file-parent
57 | o 2@source "Added parent file" files: file-parent
58 58 | |
59 o | 1 "Added branch1 file" files: file file-branch1
59 o | 1@source-branch1 "Added branch1 file" files: file file-branch1
60 60 |/
61 o 0 "Initial add" files: file
61 o 0@source "Initial add" files: file
62 62
63 63 $ manifest source-hg tip
64 64 % manifest of tip
65 65 644 file
66 66 644 file-branch1
67 67 644 file-branch2
68 68 644 file-parent
@@ -1,210 +1,238
1 1 $ "$TESTDIR/hghave" symlink execbit || exit 80
2 2
3 3 $ . "$TESTDIR/bzr-definitions"
4 4
5 5 create and rename on the same file in the same step
6 6
7 7 $ mkdir test-createandrename
8 8 $ cd test-createandrename
9 9 $ bzr init -q source
10 10 $ cd source
11 11 $ echo a > a
12 12 $ echo c > c
13 13 $ echo e > e
14 14 $ bzr add -q a c e
15 15 $ bzr commit -q -m 'Initial add: a, c, e'
16 16 $ bzr mv a b
17 17 a => b
18 18 $ bzr mv c d
19 19 c => d
20 20 $ bzr mv e f
21 21 e => f
22 22 $ echo a2 >> a
23 23 $ mkdir e
24 24 $ bzr add -q a e
25 25 $ bzr commit -q -m 'rename a into b, create a, rename c into d'
26 26 $ cd ..
27 27 $ hg convert source source-hg
28 28 initializing destination source-hg repository
29 29 scanning source...
30 30 sorting...
31 31 converting...
32 32 1 Initial add: a, c, e
33 33 0 rename a into b, create a, rename c into d
34 34 $ glog -R source-hg
35 o 1 "rename a into b, create a, rename c into d" files: a b c d e f
35 o 1@source "rename a into b, create a, rename c into d" files: a b c d e f
36 36 |
37 o 0 "Initial add: a, c, e" files: a c e
37 o 0@source "Initial add: a, c, e" files: a c e
38 38
39 39
40 40 manifest
41 41
42 42 $ hg manifest -R source-hg -r tip
43 43 a
44 44 b
45 45 d
46 46 f
47 47
48 48 test --rev option
49 49
50 50 $ hg convert -r 1 source source-1-hg
51 51 initializing destination source-1-hg repository
52 52 scanning source...
53 53 sorting...
54 54 converting...
55 55 0 Initial add: a, c, e
56 56 $ glog -R source-1-hg
57 o 0 "Initial add: a, c, e" files: a c e
57 o 0@source "Initial add: a, c, e" files: a c e
58 58
59 59
60 60 test with filemap
61 61
62 62 $ cat > filemap <<EOF
63 63 > exclude a
64 64 > EOF
65 65 $ hg convert --filemap filemap source source-filemap-hg
66 66 initializing destination source-filemap-hg repository
67 67 scanning source...
68 68 sorting...
69 69 converting...
70 70 1 Initial add: a, c, e
71 71 0 rename a into b, create a, rename c into d
72 72 $ hg -R source-filemap-hg manifest -r tip
73 73 b
74 74 d
75 75 f
76 76
77 77 convert from lightweight checkout
78 78
79 79 $ bzr checkout --lightweight source source-light
80 $ hg convert source-light source-light-hg
80 $ hg convert -s bzr source-light source-light-hg
81 81 initializing destination source-light-hg repository
82 82 warning: lightweight checkouts may cause conversion failures, try with a regular branch instead.
83 scanning source...
84 sorting...
85 converting...
86 1 Initial add: a, c, e
87 0 rename a into b, create a, rename c into d
88
89 lightweight manifest
90
91 $ hg manifest -R source-light-hg -r tip
92 a
93 b
94 d
95 f
83 $TESTTMP/test-createandrename/source-light does not look like a Bazaar repository
84 abort: source-light: missing or unsupported repository
85 [255]
96 86
97 87 extract timestamps that look just like hg's {date|isodate}:
98 88 yyyy-mm-dd HH:MM zzzz (no seconds!)
99 89 compare timestamps
100 90
101 91 $ cd source
102 92 $ bzr log | \
103 93 > sed '/timestamp/!d;s/.\{15\}\([0-9: -]\{16\}\):.. \(.[0-9]\{4\}\)/\1 \2/' \
104 94 > > ../bzr-timestamps
105 95 $ cd ..
106 96 $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
107 97 $ diff -u bzr-timestamps hg-timestamps
108 98 $ cd ..
109 99
110 100 merge
111 101
112 102 $ mkdir test-merge
113 103 $ cd test-merge
114 104 $ cat > helper.py <<EOF
115 105 > import sys
116 106 > from bzrlib import workingtree
117 107 > wt = workingtree.WorkingTree.open('.')
118 108 >
119 109 > message, stamp = sys.argv[1:]
120 110 > wt.commit(message, timestamp=int(stamp))
121 111 > EOF
122 112 $ bzr init -q source
123 113 $ cd source
124 114 $ echo content > a
125 115 $ echo content2 > b
126 116 $ bzr add -q a b
127 117 $ bzr commit -q -m 'Initial add'
128 118 $ cd ..
129 119 $ bzr branch -q source source-improve
130 120 $ cd source
131 121 $ echo more >> a
132 122 $ python ../helper.py 'Editing a' 100
133 123 $ cd ../source-improve
134 124 $ echo content3 >> b
135 125 $ python ../helper.py 'Editing b' 200
136 126 $ cd ../source
137 127 $ bzr merge -q ../source-improve
138 128 $ bzr commit -q -m 'Merged improve branch'
139 129 $ cd ..
140 130 $ hg convert --datesort source source-hg
141 131 initializing destination source-hg repository
142 132 scanning source...
143 133 sorting...
144 134 converting...
145 135 3 Initial add
146 136 2 Editing a
147 137 1 Editing b
148 138 0 Merged improve branch
149 139 $ glog -R source-hg
150 o 3 "Merged improve branch" files:
140 o 3@source "Merged improve branch" files:
151 141 |\
152 | o 2 "Editing b" files: b
142 | o 2@source-improve "Editing b" files: b
153 143 | |
154 o | 1 "Editing a" files: a
144 o | 1@source "Editing a" files: a
155 145 |/
156 o 0 "Initial add" files: a b
146 o 0@source "Initial add" files: a b
157 147
158 148 $ cd ..
159 149
160 150 symlinks and executable files
161 151
162 152 $ mkdir test-symlinks
163 153 $ cd test-symlinks
164 154 $ bzr init -q source
165 155 $ cd source
166 156 $ touch program
167 157 $ chmod +x program
168 158 $ ln -s program altname
169 159 $ mkdir d
170 160 $ echo a > d/a
171 161 $ ln -s a syma
172 162 $ bzr add -q altname program syma d/a
173 163 $ bzr commit -q -m 'Initial setup'
174 164 $ touch newprog
175 165 $ chmod +x newprog
176 166 $ rm altname
177 167 $ ln -s newprog altname
178 168 $ chmod -x program
179 169 $ bzr add -q newprog
180 170 $ bzr commit -q -m 'Symlink changed, x bits changed'
181 171 $ cd ..
182 172 $ hg convert source source-hg
183 173 initializing destination source-hg repository
184 174 scanning source...
185 175 sorting...
186 176 converting...
187 177 1 Initial setup
188 178 0 Symlink changed, x bits changed
189 179 $ manifest source-hg 0
190 180 % manifest of 0
191 181 644 @ altname
192 182 644 d/a
193 183 755 * program
194 184 644 @ syma
195 185 $ manifest source-hg tip
196 186 % manifest of tip
197 187 644 @ altname
198 188 644 d/a
199 189 755 * newprog
200 190 644 program
201 191 644 @ syma
202 192 $ cd source-hg
203 193
204 194 test the symlinks can be recreated
205 195
206 196 $ hg up
207 197 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 198 $ hg cat syma; echo
209 199 a
210 200
201 Multiple branches
202
203 $ bzr init-repo -q --no-trees repo
204 $ bzr init -q repo/trunk
205 $ bzr co repo/trunk repo-trunk
206 $ cd repo-trunk
207 $ echo a > a
208 $ bzr add a
209 adding a
210 $ bzr ci -qm adda --commit-time '2012-01-01 00:00:01 +0000'
211 $ bzr switch -b branch
212 Tree is up to date at revision 1.
213 Switched to branch: *repo/branch/ (glob)
214 $ echo b > b
215 $ bzr add b
216 adding b
217 $ bzr ci -qm addb --commit-time '2012-01-01 00:00:02 +0000'
218 $ bzr switch --force ../repo/trunk
219 Updated to revision 1.
220 Switched to branch: */repo/trunk/ (glob)
221 $ echo a >> a
222 $ bzr ci -qm changea --commit-time '2012-01-01 00:00:03 +0000'
223 $ cd ..
224 $ hg convert --datesort repo repo-bzr
225 initializing destination repo-bzr repository
226 scanning source...
227 sorting...
228 converting...
229 2 adda
230 1 addb
231 0 changea
232 $ (cd repo-bzr; glog)
233 o 2@default "changea" files: a
234 |
235 | o 1@branch "addb" files: b
236 |/
237 o 0@default "adda" files: a
238
General Comments 0
You need to be logged in to leave comments. Login now