Show More
@@ -291,6 +291,15 b' def convert(ui, src, dest=None, revmapfi' | |||
|
291 | 291 | leading 'refs/heads' stripped. Git submodules are converted to Git |
|
292 | 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 | 303 | Perforce Source |
|
295 | 304 | ############### |
|
296 | 305 |
@@ -94,6 +94,17 b' class convert_git(converter_source):' | |||
|
94 | 94 | if not os.path.exists(path + "/objects"): |
|
95 | 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 | 108 | checktool('git', 'git') |
|
98 | 109 | |
|
99 | 110 | self.path = path |
@@ -184,8 +195,10 b' class convert_git(converter_source):' | |||
|
184 | 195 | if full: |
|
185 | 196 | raise util.Abort(_("convert from git do not support --full")) |
|
186 | 197 | self.modecache = {} |
|
187 |
fh = self.gitopen("git diff-tree -z --root -m -r %s" % |
|
|
198 | fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % ( | |
|
199 | self.simopt, version)) | |
|
188 | 200 | changes = [] |
|
201 | copies = {} | |
|
189 | 202 | seen = set() |
|
190 | 203 | entry = None |
|
191 | 204 | subexists = [False] |
@@ -194,15 +207,16 b' class convert_git(converter_source):' | |||
|
194 | 207 | lcount = len(difftree) |
|
195 | 208 | i = 0 |
|
196 | 209 | |
|
197 | def add(entry, f): | |
|
210 | def add(entry, f, isdest): | |
|
198 | 211 | seen.add(f) |
|
199 | 212 | h = entry[3] |
|
200 | 213 | p = (entry[1] == "100755") |
|
201 | 214 | s = (entry[1] == "120000") |
|
215 | renamesource = (not isdest and entry[4][0] == 'R') | |
|
202 | 216 | |
|
203 | 217 | if f == '.gitmodules': |
|
204 | 218 | subexists[0] = True |
|
205 | if entry[4] == 'D': | |
|
219 | if entry[4] == 'D' or renamesource: | |
|
206 | 220 | subdeleted[0] = True |
|
207 | 221 | changes.append(('.hgsub', hex(nullid))) |
|
208 | 222 | else: |
@@ -210,6 +224,8 b' class convert_git(converter_source):' | |||
|
210 | 224 | elif entry[1] == '160000' or entry[0] == ':160000': |
|
211 | 225 | subexists[0] = True |
|
212 | 226 | else: |
|
227 | if renamesource: | |
|
228 | h = hex(nullid) | |
|
213 | 229 | self.modecache[(f, h)] = (p and "x") or (s and "l") or "" |
|
214 | 230 | changes.append((f, h)) |
|
215 | 231 | |
@@ -223,7 +239,19 b' class convert_git(converter_source):' | |||
|
223 | 239 | continue |
|
224 | 240 | f = l |
|
225 | 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 | 255 | entry = None |
|
228 | 256 | if fh.close(): |
|
229 | 257 | raise util.Abort(_('cannot read changes in %s') % version) |
@@ -234,7 +262,7 b' class convert_git(converter_source):' | |||
|
234 | 262 | else: |
|
235 | 263 | self.retrievegitmodules(version) |
|
236 | 264 | changes.append(('.hgsubstate', '')) |
|
237 |
return (changes, |
|
|
265 | return (changes, copies) | |
|
238 | 266 | |
|
239 | 267 | def getcommit(self, version): |
|
240 | 268 | c = self.catfile(version, "commit") # read the commit hash |
@@ -241,8 +241,45 b' full conversion' | |||
|
241 | 241 | 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo |
|
242 | 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 | 280 | test binary conversion (issue1359) |
|
245 | 281 | |
|
282 | $ count=19 | |
|
246 | 283 | $ mkdir git-repo3 |
|
247 | 284 | $ cd git-repo3 |
|
248 | 285 | $ git init-db >/dev/null 2>/dev/null |
@@ -398,6 +435,29 b' convert sub modules' | |||
|
398 | 435 | |
|
399 | 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 | 461 | convert the revision removing '.gitmodules' itself (and related |
|
402 | 462 | submodules) |
|
403 | 463 |
@@ -244,6 +244,16 b'' | |||
|
244 | 244 | converted to bookmarks with the same name, with the leading 'refs/heads' |
|
245 | 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 | 257 | Perforce Source |
|
248 | 258 | ############### |
|
249 | 259 |
General Comments 0
You need to be logged in to leave comments.
Login now