{"thread":{"id":"2628","subject":"Pure renames/copies","startedAt":"2005-11-21T12:01:03Z","lastAt":"2005-11-22T09:03:03Z","messageCount":11,"participants":["Santi Béjar","Linus Torvalds","Junio C Hamano","H. Peter Anvin","Santi Bejar"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"12430","messageId":"87hda61a80.fsf@gmail.com","threadId":"2628","inReplyTo":null,"subject":"Pure renames/copies","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2005-11-21T12:01:03Z","receivedAt":"2005-11-21T12:01:03Z","isPatch":false,"sender":{"key":"santi@agolina.net","avatar":null},"body":"Hello:\n\n\n        Is there any way to ask git to find pure renames or copies?\n\n        I ask this because it is a much cheaper operation than the -C\n        and -M do (-M100 does not work) and can be used when the number\n        of paths if big, or when you track binary files.\n\n        Thanks\n\n        Santi\n"},{"id":"12456","messageId":"Pine.LNX.4.64.0511211020130.13959@g5.osdl.org","threadId":"2628","inReplyTo":"87hda61a80.fsf@gmail.com","subject":"Re: Pure renames/copies","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-11-21T18:37:10Z","receivedAt":"2005-11-21T18:37:10Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 21 Nov 2005, Santi Béjar wrote:\n> \n>         Is there any way to ask git to find pure renames or copies?\n\nNot directly, but git sure makes it easy for you.\n\nDo this:\n\n\tgit-diff-tree -r old..new |\n\t\tgrep '^:[^<tab>]*0000000000000000000000000000000000000000'\n\nand you'll get all the information (that \"<tab>\" is obviously the tab \ncharacter) you need to efficiently do it (or, if you want to just do one \ncommit, just do \"git-diff-tree -r cmit\"). \n\nIn the git tree, commit 0086e2c854e3af3209915e4ec2f933bcef400050 can act \nas a good example of this: the output of \n\n\tgit-diff-tree -r 0086e2c854e3af3209915e4ec2f933bcef400050\n\nis\n\n\t0086e2c854e3af3209915e4ec2f933bcef400050\n\t:100644 100644 328b399f9fe6e2b668691ab359319f50561cd773 16a8af63f0523cec82faa23f29cee579ac224e82 M      .gitignore\n\t:100644 000000 a8cc5739d7851da3aeca2388d74eb92c464f1732 0000000000000000000000000000000000000000 D      Documentation/git-lost+found.txt\n\t:000000 100644 0000000000000000000000000000000000000000 03156f218bb41b955779207ec2e94120f958fc45 A      Documentation/git-lost-found.txt\n\t:100644 100644 a9d47c115c071694321d076af8a73a06ddd46875 1c32dd5be7156ae0e1142523fe50d84745964793 M      Documentation/git.txt\n\t:100644 100644 b75cb137875b3cdb8746d2e0135e6f2743e2046a 5b2eca897386e17021d2a8a052b0c2759df96447 M      Makefile\n\t:100755 000000 3892f52005d1e36676681806a87ef35dc0689f22 0000000000000000000000000000000000000000 D      git-lost+found.sh\n\t:000000 100755 0000000000000000000000000000000000000000 3892f52005d1e36676681806a87ef35dc0689f22 A      git-lost-found.sh\n\nand then after the \"grep\", you have just\n\n\t:100644 000000 a8cc5739d7851da3aeca2388d74eb92c464f1732 0000000000000000000000000000000000000000 D      Documentation/git-lost+found.txt\n\t:000000 100644 0000000000000000000000000000000000000000 03156f218bb41b955779207ec2e94120f958fc45 A      Documentation/git-lost-found.txt\n\t:100755 000000 3892f52005d1e36676681806a87ef35dc0689f22 0000000000000000000000000000000000000000 D      git-lost+found.sh\n\t:000000 100755 0000000000000000000000000000000000000000 3892f52005d1e36676681806a87ef35dc0689f22 A      git-lost-found.sh\n\nleft, which shows you the new and the deleted files.\n\nThen, look for renames: just match up a new file that has the same SHA1 as \na deleted file, and you can see that the change from \"git-lost+found.sh\" \nto \"git-lost-found.sh\" was exactly such an exact rename, because they \nshare the 3892f52005d1e36676681806a87ef35dc0689f22 SHA1.\n\nAfter rename detection, look at any remaining new files (in the above \nexample, only\n\n\t:000000 100644 0000000000000000000000000000000000000000 03156f218bb41b955779207ec2e94120f958fc45 A      Documentation/git-lost-found.txt\n\nwould be left), and try to match up the SHA1 of that file with the result \nof \"git-ls-tree -r $old\", ie something like\n\n\tgit-ls-tree -r 0086e2c854e3af3209915e4ec2f933bcef400050^ |\n\t\tgrep 03156f218bb41b955779207ec2e94120f958fc45\n\nwhich in this case is empty (that new file wasn't an exact copy of any old \nfile, it was a rename+edit, of course).\n\nVery efficient, very simple, you can do it either with a small \nshell-script (using cut + sort + join + grep), or write a specialized tool \naround the git-diff-tree logic.\n\nOf course, arguably \"-M100\" should really do this optimization for you. \nJunio?\n\n\t\t\tLinus"},{"id":"12463","messageId":"7vu0e5re61.fsf@assigned-by-dhcp.cox.net","threadId":"2628","inReplyTo":"Pine.LNX.4.64.0511211020130.13959@g5.osdl.org","subject":"Re: Pure renames/copies","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-21T19:31:18Z","receivedAt":"2005-11-21T19:31:18Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> Of course, arguably \"-M100\" should really do this optimization for you. \n> Junio?\n\nI'd agree.  That is what -M100 should mean.\n"},{"id":"12464","messageId":"7vacfxrdao.fsf@assigned-by-dhcp.cox.net","threadId":"2628","inReplyTo":"Pine.LNX.4.64.0511211020130.13959@g5.osdl.org","subject":"Re: Pure renames/copies","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-21T19:50:07Z","receivedAt":"2005-11-21T19:50:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> Of course, arguably \"-M100\" should really do this optimization for you. \n> Junio?\n\nProbably something like this would suffice.\n\n-- >8 --\nSubject: rename detection with -M100 means \"exact renames only\".\n\nWhen the user is interested in pure renames, there is no point\ndoing the similarity scores.  This changes the score argument\nparsing to special case -M100 (otherwise, it is a precision\nscaled value 0 <= v < 1 and would mean 0.1, not 1.0 --- if you\ndo mean 0.1, you can say -M1), and optimizes the diffcore_rename\ntransformation to only look at pure renames in that case.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\ndiff --git a/diff.c b/diff.c\nindex 0391e8c..0f839c1 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -853,6 +853,10 @@ static int parse_num(const char **cp_p)\n \t}\n \t*cp_p = cp;\n \n+\t/* special case: -M100 would mean 1.0 not 0.1 */\n+\tif (num == 100 && scale == 1000)\n+\t\treturn MAX_SCORE;\n+\n \t/* user says num divided by scale and we say internally that\n \t * is MAX_SCORE * num / scale.\n \t */\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 6a9d95d..dba965c 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -307,6 +307,9 @@ void diffcore_rename(struct diff_options\n \tif (rename_count == rename_dst_nr)\n \t\tgoto cleanup;\n \n+\tif (minimum_score == MAX_SCORE)\n+\t\tgoto cleanup;\n+\n \tnum_create = (rename_dst_nr - rename_count);\n \tnum_src = rename_src_nr;\n \tmx = xmalloc(sizeof(*mx) * num_create * num_src);\n"},{"id":"12471","messageId":"438235AA.8070805@zytor.com","threadId":"2628","inReplyTo":"7vacfxrdao.fsf@assigned-by-dhcp.cox.net","subject":"Re: Pure renames/copies","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-11-21T21:01:30Z","receivedAt":"2005-11-21T21:01:30Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Junio C Hamano wrote:\n> Linus Torvalds <torvalds@osdl.org> writes:\n> \n> \n>>Of course, arguably \"-M100\" should really do this optimization for you. \n>>Junio?\n> \n> \n> Probably something like this would suffice.\n> \n> -- >8 --\n> Subject: rename detection with -M100 means \"exact renames only\".\n> \n> When the user is interested in pure renames, there is no point\n> doing the similarity scores.  This changes the score argument\n> parsing to special case -M100 (otherwise, it is a precision\n> scaled value 0 <= v < 1 and would mean 0.1, not 1.0 --- if you\n> do mean 0.1, you can say -M1), and optimizes the diffcore_rename\n> transformation to only look at pure renames in that case.\n> \n\nAny reason we can't make it take an actual decimal number, like -M1.0 or \n-M0.345?  It seems odd and annoying to invent our own notation for \nfloating-point numbers, especially in userspace.\n\n\t-hpa\n"},{"id":"12476","messageId":"7vpsotofd0.fsf@assigned-by-dhcp.cox.net","threadId":"2628","inReplyTo":"438235AA.8070805@zytor.com","subject":"Re: Pure renames/copies","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-21T21:33:47Z","receivedAt":"2005-11-21T21:33:47Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"H. Peter Anvin\" <hpa@zytor.com> writes:\n\n> Any reason we can't make it take an actual decimal number, like -M1.0 or \n> -M0.345?  It seems odd and annoying to invent our own notation for \n> floating-point numbers, especially in userspace.\n\nNo reason we \"can't\".  About we \"don't\", inertia and nothing\nelse.  It happened around this time.\n\n\thttp://marc.theaimsgroup.com/?l=git&m=111654149421574\n\nWe could in addition to take 0 <= x <= 1 decimal number and that\nshould be a simple patch to diff.c::parse_num().\n"},{"id":"12479","messageId":"43823E31.2050500@zytor.com","threadId":"2628","inReplyTo":"7vpsotofd0.fsf@assigned-by-dhcp.cox.net","subject":"Re: Pure renames/copies","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-11-21T21:37:53Z","receivedAt":"2005-11-21T21:37:53Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Junio C Hamano wrote:\n> \"H. Peter Anvin\" <hpa@zytor.com> writes:\n> \n> \n>>Any reason we can't make it take an actual decimal number, like -M1.0 or \n>>-M0.345?  It seems odd and annoying to invent our own notation for \n>>floating-point numbers, especially in userspace.\n> \n> \n> No reason we \"can't\".  About we \"don't\", inertia and nothing\n> else.  It happened around this time.\n> \n> \thttp://marc.theaimsgroup.com/?l=git&m=111654149421574\n> \n> We could in addition to take 0 <= x <= 1 decimal number and that\n> should be a simple patch to diff.c::parse_num().\n> \n\nOkay, in that post Linus suggests that -M without an argument should be \n== 100% (1.0), thus avoiding having to mess up the meaning of -M100 as \n0.100.  It seems like a really odd thing to have -M100 mean something \nthat's completely out of line with the rest of the meaning.\n\n\t-hpa\n"},{"id":"12484","messageId":"7vd5ktoe52.fsf@assigned-by-dhcp.cox.net","threadId":"2628","inReplyTo":"43823E31.2050500@zytor.com","subject":"Re: Pure renames/copies","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-21T22:00:09Z","receivedAt":"2005-11-21T22:00:09Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"H. Peter Anvin\" <hpa@zytor.com> writes:\n\n> Okay, in that post Linus suggests that -M without an argument should be \n> == 100% (1.0), thus avoiding having to mess up the meaning of -M100 as \n> 0.100.  It seems like a really odd thing to have -M100 mean something \n> that's completely out of line with the rest of the meaning.\n\nTrue, but it might be too late to change that; I suspect people\nexpect -M to do a bit more than pure renames by now.\n"},{"id":"12485","messageId":"438245CF.9030501@zytor.com","threadId":"2628","inReplyTo":"7vd5ktoe52.fsf@assigned-by-dhcp.cox.net","subject":"Re: Pure renames/copies","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-11-21T22:10:23Z","receivedAt":"2005-11-21T22:10:23Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Junio C Hamano wrote:\n> \"H. Peter Anvin\" <hpa@zytor.com> writes:\n> \n> \n>>Okay, in that post Linus suggests that -M without an argument should be \n>>== 100% (1.0), thus avoiding having to mess up the meaning of -M100 as \n>>0.100.  It seems like a really odd thing to have -M100 mean something \n>>that's completely out of line with the rest of the meaning.\n> \n> True, but it might be too late to change that; I suspect people\n> expect -M to do a bit more than pure renames by now.\n> \n\nOkay, how about the following?  It lets both -M1.0 and -M100% work, \nwhile keeping everything else compatible, and avoiding artificial \nspecial cases.\n\n\t-hpa\n\n\ndiff --git a/diff.c b/diff.c\nindex 0391e8c..df62d2b 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -843,11 +843,19 @@ static int parse_num(const char **cp_p)\n \n \tcnt = num = 0;\n \tscale = 1;\n-\twhile ('0' <= (ch = *cp) && ch <= '9') {\n-\t\tif (cnt++ < 5) {\n-\t\t\t/* We simply ignore more than 5 digits precision. */\n-\t\t\tscale *= 10;\n-\t\t\tnum = num * 10 + ch - '0';\n+\tfor(;;) {\n+\t\tch = *cp;\n+\t\tif ( ch == '.' ) {\n+\t\t\tscale = 1;\n+\t\t} else if ( ch == '%' ) {\n+\t\t\tscale = 100;\n+\t\t} else if ( ch >= '0' && ch <= '9' ) {\n+\t\t\tif ( scale < 100000 ) {\n+\t\t\t\tscale *= 10;\n+\t\t\t\tnum = (num*10) + (ch-'0');\n+\t\t\t}\n+\t\t} else {\n+\t\t\tbreak;\n \t\t}\n \t\tcp++;\n \t}\n@@ -856,7 +864,7 @@ static int parse_num(const char **cp_p)\n \t/* user says num divided by scale and we say internally that\n \t * is MAX_SCORE * num / scale.\n \t */\n-\treturn (MAX_SCORE * num / scale);\n+\treturn (num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale);\n }\n \n int diff_scoreopt_parse(const char *opt)\n"},{"id":"12487","messageId":"43824768.2070207@zytor.com","threadId":"2628","inReplyTo":"438245CF.9030501@zytor.com","subject":"Re: Pure renames/copies","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-11-21T22:17:12Z","receivedAt":"2005-11-21T22:17:12Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Better variant, which handles stuff like \"4.5%\" and rejects \n\"192.168.0.1\".  Additionally, make sure numbers are unsigned (I'm making \nthem unsigned long just for the hell of it), to make sure that \nartificial wraparound scenarios don't cause harm.\n\n\t-hpa\n\n\n\ndiff --git a/diff.c b/diff.c\nindex 0391e8c..ffe8a55 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -838,16 +838,29 @@ int diff_opt_parse(struct diff_options *\n \n static int parse_num(const char **cp_p)\n {\n-\tint num, scale, ch, cnt;\n+\tunsigned long num, scale;\n+\tint ch, dot;\n \tconst char *cp = *cp_p;\n \n-\tcnt = num = 0;\n+\tnum = 0;\n \tscale = 1;\n-\twhile ('0' <= (ch = *cp) && ch <= '9') {\n-\t\tif (cnt++ < 5) {\n-\t\t\t/* We simply ignore more than 5 digits precision. */\n-\t\t\tscale *= 10;\n-\t\t\tnum = num * 10 + ch - '0';\n+\tdot = 0;\n+\tfor(;;) {\n+\t\tch = *cp;\n+\t\tif ( !dot && ch == '.' ) {\n+\t\t\tscale = 1;\n+\t\t\tdot = 1;\n+\t\t} else if ( ch == '%' ) {\n+\t\t\tscale = dot ? scale*100 : 100;\n+\t\t\tcp++;\t/* % is always at the end */\n+\t\t\tbreak;\n+\t\t} else if ( ch >= '0' && ch <= '9' ) {\n+\t\t\tif ( scale < 100000 ) {\n+\t\t\t\tscale *= 10;\n+\t\t\t\tnum = (num*10) + (ch-'0');\n+\t\t\t}\n+\t\t} else {\n+\t\t\tbreak;\n \t\t}\n \t\tcp++;\n \t}\n@@ -856,7 +869,7 @@ static int parse_num(const char **cp_p)\n \t/* user says num divided by scale and we say internally that\n \t * is MAX_SCORE * num / scale.\n \t */\n-\treturn (MAX_SCORE * num / scale);\n+\treturn (num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale);\n }\n \n int diff_scoreopt_parse(const char *opt)\n"},{"id":"12528","messageId":"8aa486160511220103t7caf5ad2n@mail.gmail.com","threadId":"2628","inReplyTo":"7vacfxrdao.fsf@assigned-by-dhcp.cox.net","subject":"Re: Pure renames/copies","fromName":"Santi Bejar","fromEmail":"sbejar@gmail.com","sentAt":"2005-11-22T09:03:03Z","receivedAt":"2005-11-22T09:03:03Z","isPatch":false,"sender":{"key":"santi@agolina.net","avatar":null},"body":">\n> Probably something like this would suffice.\n>\n\nOk, thanks. Now the only issue with my broken repository (it does not\nhave all the blobs) is that it outputs:\n\nerror: unable to find abcde....\n\nfor all the src paths, but the result is ok.\n\nBut I can live with it.\n\nThanks\n"}]}