##// END OF EJS Templates
convert: add support to detect git renames and copies...
Siddharth Agarwal -
r22470:8e0c4df2 default
parent child Browse files
Show More
@@ -291,6 +291,15 b' def convert(ui, src, dest=None, revmapfi'
291 leading 'refs/heads' stripped. Git submodules are converted to Git
291 leading 'refs/heads' stripped. Git submodules are converted to Git
292 subrepos in Mercurial.
292 subrepos in Mercurial.
293
293
294 The following options can be set with ``--config``:
295
296 :convert.git.similarity: specify how similar files modified in a
297 commit must be to be imported as renames or copies, as a
298 percentage between ``0`` (disabled) and ``100`` (files must be
299 identical). For example, ``90`` means that a delete/add pair will
300 be imported as a rename if more than 90% of the file hasn't
301 changed. The default is ``0``.
302
294 Perforce Source
303 Perforce Source
295 ###############
304 ###############
296
305
@@ -94,6 +94,17 b' class convert_git(converter_source):'
94 if not os.path.exists(path + "/objects"):
94 if not os.path.exists(path + "/objects"):
95 raise NoRepo(_("%s does not look like a Git repository") % path)
95 raise NoRepo(_("%s does not look like a Git repository") % path)
96
96
97 try:
98 similarity = int(ui.config('convert', 'git.similarity') or 0)
99 except ValueError:
100 raise util.Abort('convert.git.similarity must be a number')
101 if similarity < 0 or similarity > 100:
102 raise util.Abort(_('similarity must be between 0 and 100'))
103 if similarity > 0:
104 self.simopt = '--find-copies=%d%%' % similarity
105 else:
106 self.simopt = ''
107
97 checktool('git', 'git')
108 checktool('git', 'git')
98
109
99 self.path = path
110 self.path = path
@@ -184,8 +195,10 b' class convert_git(converter_source):'
184 if full:
195 if full:
185 raise util.Abort(_("convert from git do not support --full"))
196 raise util.Abort(_("convert from git do not support --full"))
186 self.modecache = {}
197 self.modecache = {}
187 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
198 fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % (
199 self.simopt, version))
188 changes = []
200 changes = []
201 copies = {}
189 seen = set()
202 seen = set()
190 entry = None
203 entry = None
191 subexists = [False]
204 subexists = [False]
@@ -194,15 +207,16 b' class convert_git(converter_source):'
194 lcount = len(difftree)
207 lcount = len(difftree)
195 i = 0
208 i = 0
196
209
197 def add(entry, f):
210 def add(entry, f, isdest):
198 seen.add(f)
211 seen.add(f)
199 h = entry[3]
212 h = entry[3]
200 p = (entry[1] == "100755")
213 p = (entry[1] == "100755")
201 s = (entry[1] == "120000")
214 s = (entry[1] == "120000")
215 renamesource = (not isdest and entry[4][0] == 'R')
202
216
203 if f == '.gitmodules':
217 if f == '.gitmodules':
204 subexists[0] = True
218 subexists[0] = True
205 if entry[4] == 'D':
219 if entry[4] == 'D' or renamesource:
206 subdeleted[0] = True
220 subdeleted[0] = True
207 changes.append(('.hgsub', hex(nullid)))
221 changes.append(('.hgsub', hex(nullid)))
208 else:
222 else:
@@ -210,6 +224,8 b' class convert_git(converter_source):'
210 elif entry[1] == '160000' or entry[0] == ':160000':
224 elif entry[1] == '160000' or entry[0] == ':160000':
211 subexists[0] = True
225 subexists[0] = True
212 else:
226 else:
227 if renamesource:
228 h = hex(nullid)
213 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
229 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
214 changes.append((f, h))
230 changes.append((f, h))
215
231
@@ -223,7 +239,19 b' class convert_git(converter_source):'
223 continue
239 continue
224 f = l
240 f = l
225 if f not in seen:
241 if f not in seen:
226 add(entry, f)
242 add(entry, f, False)
243 # A file can be copied multiple times, or modified and copied
244 # simultaneously. So f can be repeated even if fdest isn't.
245 if entry[4][0] in 'RC':
246 # rename or copy: next line is the destination
247 fdest = difftree[i]
248 i += 1
249 if fdest not in seen:
250 add(entry, fdest, True)
251 # .gitmodules isn't imported at all, so it being copied to
252 # and fro doesn't really make sense
253 if f != '.gitmodules' and fdest != '.gitmodules':
254 copies[fdest] = f
227 entry = None
255 entry = None
228 if fh.close():
256 if fh.close():
229 raise util.Abort(_('cannot read changes in %s') % version)
257 raise util.Abort(_('cannot read changes in %s') % version)
@@ -234,7 +262,7 b' class convert_git(converter_source):'
234 else:
262 else:
235 self.retrievegitmodules(version)
263 self.retrievegitmodules(version)
236 changes.append(('.hgsubstate', ''))
264 changes.append(('.hgsubstate', ''))
237 return (changes, {})
265 return (changes, copies)
238
266
239 def getcommit(self, version):
267 def getcommit(self, version):
240 c = self.catfile(version, "commit") # read the commit hash
268 c = self.catfile(version, "commit") # read the commit hash
@@ -241,8 +241,45 b' full conversion'
241 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
241 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
242 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
242 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
243
243
244 test importing git renames and copies
245
246 $ cd git-repo2
247 $ git mv foo foo-renamed
248 since bar is not touched in this commit, this copy will not be detected
249 $ cp bar bar-copied
250 $ cp baz baz-copied
251 $ cp baz baz-copied2
252 $ echo baz2 >> baz
253 $ git add bar-copied baz-copied baz-copied2
254 $ commit -a -m 'rename and copy'
255 $ cd ..
256
257 input validation
258 $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo
259 abort: convert.git.similarity must be a number
260 [255]
261 $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo
262 abort: similarity must be between 0 and 100
263 [255]
264 $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo
265 abort: similarity must be between 0 and 100
266 [255]
267
268 $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo
269 $ hg -R fullrepo status -C --change master
270 M baz
271 A bar-copied
272 A baz-copied
273 baz
274 A baz-copied2
275 baz
276 A foo-renamed
277 foo
278 R foo
279
244 test binary conversion (issue1359)
280 test binary conversion (issue1359)
245
281
282 $ count=19
246 $ mkdir git-repo3
283 $ mkdir git-repo3
247 $ cd git-repo3
284 $ cd git-repo3
248 $ git init-db >/dev/null 2>/dev/null
285 $ git init-db >/dev/null 2>/dev/null
@@ -398,6 +435,29 b' convert sub modules'
398
435
399 $ cd ../..
436 $ cd ../..
400
437
438 make sure rename detection doesn't break removing and adding gitmodules
439
440 $ cd git-repo6
441 $ git mv .gitmodules .gitmodules-renamed
442 $ commit -a -m 'rename .gitmodules'
443 $ git mv .gitmodules-renamed .gitmodules
444 $ commit -a -m 'rename .gitmodules back'
445 $ cd ..
446
447 $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg
448 $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n"
449 rename .gitmodules
450 $ hg -R git-repo6-hg status -C --change 'tip^'
451 A .gitmodules-renamed
452 R .hgsub
453 R .hgsubstate
454 $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n"
455 rename .gitmodules back
456 $ hg -R git-repo6-hg status -C --change tip
457 A .hgsub
458 A .hgsubstate
459 R .gitmodules-renamed
460
401 convert the revision removing '.gitmodules' itself (and related
461 convert the revision removing '.gitmodules' itself (and related
402 submodules)
462 submodules)
403
463
@@ -244,6 +244,16 b''
244 converted to bookmarks with the same name, with the leading 'refs/heads'
244 converted to bookmarks with the same name, with the leading 'refs/heads'
245 stripped. Git submodules are converted to Git subrepos in Mercurial.
245 stripped. Git submodules are converted to Git subrepos in Mercurial.
246
246
247 The following options can be set with "--config":
248
249 convert.git.similarity
250 specify how similar files modified in a commit must be to be
251 imported as renames or copies, as a percentage between "0"
252 (disabled) and "100" (files must be identical). For example,
253 "90" means that a delete/add pair will be imported as a
254 rename if more than 90% of the file hasn't changed. The
255 default is "0".
256
247 Perforce Source
257 Perforce Source
248 ###############
258 ###############
249
259
General Comments 0
You need to be logged in to leave comments. Login now