{"thread":{"id":"11060","subject":"problem with git detecting proper renames","startedAt":"2007-11-29T16:57:24Z","lastAt":"2007-11-30T01:18:04Z","messageCount":14,"participants":["Kumar Gala","Linus Torvalds","Jeff King","Jakub Narebski","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"61408","messageId":"Pine.LNX.4.64.0711291050440.1711@blarg.am.freescale.net","threadId":"11060","inReplyTo":null,"subject":"problem with git detecting proper renames","fromName":"Kumar Gala","fromEmail":"galak@kernel.crashing.org","sentAt":"2007-11-29T16:57:24Z","receivedAt":"2007-11-29T16:57:24Z","isPatch":false,"sender":{"key":"galak@kernel.crashing.org","avatar":null},"body":"I was wondering if there was a way to ensure that git tracks renames\nproperly (or maybe its reporting them properly).\n\nI did some git-mv and got the following:\n\nthe problem is git seems confused about what file was associated with its\nsource.\n\nFor example:\n.../mpc8541cds => freescale/mpc8555cds}/init.S\n\nthanks\n\n- k\n\n---\n\n(the following is the results of a git-format-patch after the git-mv)\n\n Makefile                                           |    6 +-\n board/cds/mpc8548cds/Makefile                      |   60 -----\n board/cds/mpc8555cds/Makefile                      |   60 -----\n board/cds/mpc8555cds/init.S                        |  255 --------------------\n board/cds/mpc8555cds/u-boot.lds                    |  150 ------------\n board/{cds => freescale}/common/cadmus.c           |    0\n board/{cds => freescale}/common/cadmus.h           |    0\n board/{cds => freescale}/common/eeprom.c           |    0\n board/{cds => freescale}/common/eeprom.h           |    0\n board/{cds => freescale}/common/ft_board.c         |    0\n board/{cds => freescale}/common/via.c              |    0\n board/{cds => freescale}/common/via.h              |    0\n board/{cds => freescale}/mpc8541cds/Makefile       |    0\n board/{cds => freescale}/mpc8541cds/config.mk      |    0\n board/{cds => freescale}/mpc8541cds/init.S         |    0\n board/{cds => freescale}/mpc8541cds/mpc8541cds.c   |    0\n board/{cds => freescale}/mpc8541cds/u-boot.lds     |    4 +-\n .../mpc8541cds => freescale/mpc8548cds}/Makefile   |    0\n board/{cds => freescale}/mpc8548cds/config.mk      |    0\n board/{cds => freescale}/mpc8548cds/init.S         |    0\n board/{cds => freescale}/mpc8548cds/mpc8548cds.c   |    0\n board/{cds => freescale}/mpc8548cds/u-boot.lds     |    4 +-\n .../mpc8541cds => freescale/mpc8555cds}/Makefile   |    0\n board/{cds => freescale}/mpc8555cds/config.mk      |    0\n .../mpc8541cds => freescale/mpc8555cds}/init.S     |    0\n board/{cds => freescale}/mpc8555cds/mpc8555cds.c   |    0\n .../mpc8541cds => freescale/mpc8555cds}/u-boot.lds |    4 +-\n 27 files changed, 9 insertions(+), 534 deletions(-)\n delete mode 100644 board/cds/mpc8548cds/Makefile\n delete mode 100644 board/cds/mpc8555cds/Makefile\n delete mode 100644 board/cds/mpc8555cds/init.S\n delete mode 100644 board/cds/mpc8555cds/u-boot.lds\n rename board/{cds => freescale}/common/cadmus.c (100%)\n rename board/{cds => freescale}/common/cadmus.h (100%)\n rename board/{cds => freescale}/common/eeprom.c (100%)\n rename board/{cds => freescale}/common/eeprom.h (100%)\n rename board/{cds => freescale}/common/ft_board.c (100%)\n rename board/{cds => freescale}/common/via.c (100%)\n rename board/{cds => freescale}/common/via.h (100%)\n copy board/{cds => freescale}/mpc8541cds/Makefile (100%)\n rename board/{cds => freescale}/mpc8541cds/config.mk (100%)\n copy board/{cds => freescale}/mpc8541cds/init.S (100%)\n rename board/{cds => freescale}/mpc8541cds/mpc8541cds.c (100%)\n copy board/{cds => freescale}/mpc8541cds/u-boot.lds (97%)\n copy board/{cds/mpc8541cds => freescale/mpc8548cds}/Makefile (100%)\n rename board/{cds => freescale}/mpc8548cds/config.mk (100%)\n rename board/{cds => freescale}/mpc8548cds/init.S (100%)\n rename board/{cds => freescale}/mpc8548cds/mpc8548cds.c (100%)\n rename board/{cds => freescale}/mpc8548cds/u-boot.lds (97%)\n rename board/{cds/mpc8541cds => freescale/mpc8555cds}/Makefile (100%)\n rename board/{cds => freescale}/mpc8555cds/config.mk (100%)\n rename board/{cds/mpc8541cds => freescale/mpc8555cds}/init.S (100%)\n rename board/{cds => freescale}/mpc8555cds/mpc8555cds.c (100%)\n rename board/{cds/mpc8541cds => freescale/mpc8555cds}/u-boot.lds (97%)\n\ndiff --git a/Makefile b/Makefile\nindex 92632b9..a0f35df 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1945,7 +1945,7 @@ MPC8541CDS_config:\tunconfig\n \t\techo \"#define CONFIG_LEGACY\" >>$(obj)include/config.h ; \\\n \t\techo \"... legacy\" ; \\\n \tfi\n-\t@$(MKCONFIG) -a MPC8541CDS ppc mpc85xx mpc8541cds cds\n+\t@$(MKCONFIG) -a MPC8541CDS ppc mpc85xx mpc8541cds freescale\n\n MPC8544DS_config:\tunconfig\n \t@$(MKCONFIG) $(@:_config=) ppc mpc85xx mpc8544ds freescale\n@@ -1958,7 +1958,7 @@ MPC8548CDS_config:\tunconfig\n \t\techo \"#define CONFIG_LEGACY\" >>$(obj)include/config.h ; \\\n \t\techo \"... legacy\" ; \\\n \tfi\n-\t@$(MKCONFIG) -a MPC8548CDS ppc mpc85xx mpc8548cds cds\n+\t@$(MKCONFIG) -a MPC8548CDS ppc mpc85xx mpc8548cds freescale\n\n MPC8555CDS_legacy_config \\\n MPC8555CDS_config:\tunconfig\n@@ -1968,7 +1968,7 @@ MPC8555CDS_config:\tunconfig\n \t\techo \"#define CONFIG_LEGACY\" >>$(obj)include/config.h ; \\\n \t\techo \"... legacy\" ; \\\n \tfi\n-\t@$(MKCONFIG) -a MPC8555CDS ppc mpc85xx mpc8555cds cds\n+\t@$(MKCONFIG) -a MPC8555CDS ppc mpc85xx mpc8555cds freescale\n\n MPC8568MDS_config:\tunconfig\n \t@$(MKCONFIG) $(@:_config=) ppc mpc85xx mpc8568mds freescale\n\n[snip]\n\ndiff --git a/board/cds/mpc8541cds/u-boot.lds b/board/freescale/mpc8555cds/u-boot.lds\nsimilarity index 97%\nrename from board/cds/mpc8541cds/u-boot.lds\nrename to board/freescale/mpc8555cds/u-boot.lds\nindex 7a5daef..df21ea8 100644\n--- a/board/cds/mpc8541cds/u-boot.lds\n+++ b/board/freescale/mpc8555cds/u-boot.lds\n@@ -34,7 +34,7 @@ SECTIONS\n   .bootpg 0xFFFFF000 :\n   {\n     cpu/mpc85xx/start.o\t(.bootpg)\n-    board/cds/mpc8541cds/init.o (.bootpg)\n+    board/freescale/mpc8555cds/init.o (.bootpg)\n   } = 0xffff\n\n   /* Read-only sections, merged into text segment: */\n@@ -64,7 +64,7 @@ SECTIONS\n   .text      :\n   {\n     cpu/mpc85xx/start.o\t(.text)\n-    board/cds/mpc8541cds/init.o (.text)\n+    board/freescale/mpc8555cds/init.o (.text)\n     cpu/mpc85xx/traps.o (.text)\n     cpu/mpc85xx/interrupts.o (.text)\n     cpu/mpc85xx/cpu_init.o (.text)\n-- \n1.5.3.4\n"},{"id":"61410","messageId":"alpine.LFD.0.9999.0711290934260.8458@woody.linux-foundation.org","threadId":"11060","inReplyTo":"Pine.LNX.4.64.0711291050440.1711@blarg.am.freescale.net","subject":"Re: problem with git detecting proper renames","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-11-29T17:44:28Z","receivedAt":"2007-11-29T17:44:28Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 29 Nov 2007, Kumar Gala wrote:\n> \n> I did some git-mv and got the following:\n> \n> the problem is git seems confused about what file was associated with its\n> source.\n\nWell, I wouldn't say \"confused\". It found multiple identical options for \nthe source, and picked the first one (where \"first one\" may not be obvious \nto a human, it can depend on an internal hash order).\n\nBut if you have the resultant git tree somewhere public (or just send me \nthe exact \"git mv\" and revision to recreate), I'll happily give it a look, \nto see if we can improve our heuristics to be closer to what a human would \nexpect.\n\nFor example, in this case, it looks  like there were two totally identical \n\"init.S\" files that got renamed with the same identical content to two new \nnames. YOU seem to expect that it would stay as two renames, but from a \ncontent angle, since the two sources were identical, it's a totally \narbitrary choice whether it's a \"copy one source to two destinations and \ndelete the other source\" or whether it's two cases of \"move one source to \nanother destination\" (and the latter case also has the issue of which way \nto move it).\n\n(You also had two identical Makefile's with the exact same issue).\n\nSo git doesn't care about how you did the rename, it only cares about the \nend result, and the exact same way that it will detect a rename if you \nimplement it as a \"copy file\" and then a later \"delete old file\", it will \nalso potentially go the other way, or just decide that identical contents \nmoved in different ways.\n\nBut we can certainly tweak the heuristics. For example, if we find \nmultiple identical renames, right now we just pick one fairly at random, \nand have no logic to prefer independent renames over \"multiple copies and \na delete\". But this code is actually fairly simple, and with a good \nexample I can easily add heurstics (for example, it probably *is* better \nto consider it to be two renames, just because the resulting diff will be \nsmaller - since a \"delete\" diff is much larger than a rename diff).\n\n\t\tLinus\n"},{"id":"61415","messageId":"28BD703B-24D3-41D6-8360-240A884B1305@kernel.crashing.org","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711290934260.8458@woody.linux-foundation.org","subject":"Re: problem with git detecting proper renames","fromName":"Kumar Gala","fromEmail":"galak@kernel.crashing.org","sentAt":"2007-11-29T19:06:58Z","receivedAt":"2007-11-29T19:06:58Z","isPatch":false,"sender":{"key":"galak@kernel.crashing.org","avatar":null},"body":"\nOn Nov 29, 2007, at 11:44 AM, Linus Torvalds wrote:\n\n> On Thu, 29 Nov 2007, Kumar Gala wrote:\n>>\n>> I did some git-mv and got the following:\n>>\n>> the problem is git seems confused about what file was associated  \n>> with its\n>> source.\n>\n> Well, I wouldn't say \"confused\". It found multiple identical options  \n> for\n> the source, and picked the first one (where \"first one\" may not be  \n> obvious\n> to a human, it can depend on an internal hash order).\n>\n> But if you have the resultant git tree somewhere public (or just  \n> send me\n> the exact \"git mv\" and revision to recreate), I'll happily give it a  \n> look,\n> to see if we can improve our heuristics to be closer to what a human  \n> would\n> expect.\n>\n> For example, in this case, it looks  like there were two totally  \n> identical\n> \"init.S\" files that got renamed with the same identical content to  \n> two new\n> names. YOU seem to expect that it would stay as two renames, but  \n> from a\n> content angle, since the two sources were identical, it's a totally\n> arbitrary choice whether it's a \"copy one source to two destinations  \n> and\n> delete the other source\" or whether it's two cases of \"move one  \n> source to\n> another destination\" (and the latter case also has the issue of  \n> which way\n> to move it).\n>\n> (You also had two identical Makefile's with the exact same issue).\n>\n> So git doesn't care about how you did the rename, it only cares  \n> about the\n> end result, and the exact same way that it will detect a rename if you\n> implement it as a \"copy file\" and then a later \"delete old file\", it  \n> will\n> also potentially go the other way, or just decide that identical  \n> contents\n> moved in different ways.\n\nI was guessing most of this but wanted to make sure there wasn't some  \ncool feature of git I wasn't aware of.\n\n> But we can certainly tweak the heuristics. For example, if we find\n> multiple identical renames, right now we just pick one fairly at  \n> random,\n> and have no logic to prefer independent renames over \"multiple  \n> copies and\n> a delete\". But this code is actually fairly simple, and with a good\n> example I can easily add heurstics (for example, it probably *is*  \n> better\n> to consider it to be two renames, just because the resulting diff  \n> will be\n> smaller - since a \"delete\" diff is much larger than a rename diff).\n\nIn the case of multiple identical matches can we look at the file name  \nas a possible heuristic?\n\n- k\n"},{"id":"61416","messageId":"alpine.LFD.0.9999.0711291122050.8458@woody.linux-foundation.org","threadId":"11060","inReplyTo":"28BD703B-24D3-41D6-8360-240A884B1305@kernel.crashing.org","subject":"Re: problem with git detecting proper renames","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-11-29T19:27:02Z","receivedAt":"2007-11-29T19:27:02Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 29 Nov 2007, Kumar Gala wrote:\n> \n> In the case of multiple identical matches can we look at the file name as a\n> possible heuristic?\n\nWe already do. But we only do the base-name part and check it for \nexactness, since moving across directories is very common, and we \nexplicitly want to pick up files that have the same base name.\n\nHowever, in your case, not only did you have the same content, you had the \nsame basename too! So git considered your renames to be totally identical \nwrt scoring with the current heuristics, and just picked one source at \nrandom. \n\nAnd the current heuristics don't even have any \"if you already found a \nrename, avoid picking the same one twice\", so it would pick the *same* \nsource both times, which is why it looked like \"two copies and one \ndelete\".\n\nThis is why I'd like to have a real-life example. I can change the \nheuristics, and I even know what are likely to be better heuristics, but I \nstill want to actually see and play with an example so that when I send \nJunio a patch, I can explain it and say I've tested it with something \nreal..\n\n\t\t\tLinus\n"},{"id":"61417","messageId":"AE325F31-6EDD-4A79-B5EF-5F1D4EBCDBDB@kernel.crashing.org","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711291122050.8458@woody.linux-foundation.org","subject":"Re: problem with git detecting proper renames","fromName":"Kumar Gala","fromEmail":"galak@kernel.crashing.org","sentAt":"2007-11-29T19:32:47Z","receivedAt":"2007-11-29T19:32:47Z","isPatch":false,"sender":{"key":"galak@kernel.crashing.org","avatar":null},"body":"\nOn Nov 29, 2007, at 1:27 PM, Linus Torvalds wrote:\n\n>\n>\n> On Thu, 29 Nov 2007, Kumar Gala wrote:\n>>\n>> In the case of multiple identical matches can we look at the file  \n>> name as a\n>> possible heuristic?\n>\n> We already do. But we only do the base-name part and check it for\n> exactness, since moving across directories is very common, and we\n> explicitly want to pick up files that have the same base name.\n>\n> However, in your case, not only did you have the same content, you  \n> had the\n> same basename too! So git considered your renames to be totally  \n> identical\n> wrt scoring with the current heuristics, and just picked one source at\n> random.\n>\n> And the current heuristics don't even have any \"if you already found a\n> rename, avoid picking the same one twice\", so it would pick the *same*\n> source both times, which is why it looked like \"two copies and one\n> delete\".\n>\n> This is why I'd like to have a real-life example. I can change the\n> heuristics, and I even know what are likely to be better heuristics,  \n> but I\n> still want to actually see and play with an example so that when I  \n> send\n> Junio a patch, I can explain it and say I've tested it with something\n> real..\n\nOk, this is a real example from the u-boot tree.  If you give me a  \nlittle while I can point you at a kernel.org git tree that showed this  \nissue.\n\n- k\n"},{"id":"61423","messageId":"41CB0B7D-5AC1-4703-BA99-21622A410F93@kernel.crashing.org","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711291122050.8458@woody.linux-foundation.org","subject":"Re: problem with git detecting proper renames","fromName":"Kumar Gala","fromEmail":"galak@kernel.crashing.org","sentAt":"2007-11-29T20:27:59Z","receivedAt":"2007-11-29T20:27:59Z","isPatch":false,"sender":{"key":"galak@kernel.crashing.org","avatar":null},"body":"> This is why I'd like to have a real-life example. I can change the\n> heuristics, and I even know what are likely to be better heuristics,  \n> but I\n> still want to actually see and play with an example so that when I  \n> send\n> Junio a patch, I can explain it and say I've tested it with something\n> real..\n\nOk, here's the tree:\n\n         git.kernel.org:/pub/scm/boot/u-boot/galak/u-boot.git linus_git\n\nand the commit that is doing the file movement is:\n\nba30ae3cc2e92d4b2362fbc01bedb659615e123e\n\nlet me know if there is anything else you need.\n\n- k\n"},{"id":"61426","messageId":"alpine.LFD.0.9999.0711291303000.8458@woody.linux-foundation.org","threadId":"11060","inReplyTo":"41CB0B7D-5AC1-4703-BA99-21622A410F93@kernel.crashing.org","subject":"Fix a pathological case in git detecting proper renames","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-11-29T21:30:13Z","receivedAt":"2007-11-29T21:30:13Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nKumar Gala had a case in the u-boot archive with multiple renames of files \nwith identical contents, and git would turn those into multiple \"copy\" \noperations of one of the sources, and just deleting the other sources.\n\nThis patch makes the git exact rename detection prefer to spread out the \nrenames over the multiple sources, rather than do multiple copies of one \nsource.\n\nNOTE! The changes are a bit larger than required, because I also renamed \nthe variables named \"one\" and \"two\" to \"target\" and \"source\" respectively. \nThat makes the logic easier to follow, especially as the \"one\" was \nillogically the target and not the soruce, for purely historical reasons \n(this piece of code used to traverse over sources and targets in the wrong \norder, and when we fixed that, we didn't fix the names back then. So I \nfixed them now).\n\nThe important part of this change is just the trivial score calculations \nfor when files have identical contents:\n\n\t/* Give higher scores to sources that haven't been used already */\n\tscore = !source->rename_used;\n\tscore += basename_same(source, target);\n\nand when we have multiple choices we'll now pick the choice that gets the \nbest rename score, rather than only looking at whether the basename \nmatched.\n\nIt's worth noting a few gotchas:\n\n - this scoring is currently only done for the \"exact match\" case. \n\n   In particular, in Kumar's example, even after this patch, the inexact\n   match case is still done as a copy+delete rather than as two renames:\n\n\t delete mode 100644 board/cds/mpc8555cds/u-boot.lds\n\t copy board/{cds => freescale}/mpc8541cds/u-boot.lds (97%)\n\t rename board/{cds/mpc8541cds => freescale/mpc8555cds}/u-boot.lds (97%)\n\n   because apparently the \"cds/mpc8541cds/u-boot.lds\" copy looked \n   a bit more similar to both end results. That said, I *suspect* we just \n   have the exact same issue there - the similarity analysis just gave \n   identical (or at least very _close_ to identical) similarity points, \n   and we do not have any logic to prefer multiple renames over a \n   copy/delete there.\n\n   That is a separate patch.\n\n - When you have identical contents and identical basenames, the actual \n   entry that is chosen is still picked fairly \"at random\" for the first \n   one (but the subsequent ones will prefer entries that haven't already \n   been used).\n\n   It's not actually really random, in that it actually depends on the\n   relative alphabetical order of the files (which in turn will have \n   impacted the order that the entries got hashed!), so it gives \n   consistent results that can be explained. But I wanted to point it out \n   as an issue for when anybody actually does cross-renames.\n\n   In Kumar's case the choice is the right one (and for a single normal \n   directory rename it should always be, since the relative alphabetical \n   sorting of the files will be identical), and we now get:\n\n\t rename board/{cds => freescale}/mpc8541cds/init.S (100%)\n\t rename board/{cds => freescale}/mpc8548cds/init.S (100%)\n\n   which is the \"expected\" answer. However, it might still be better to \n   change the pedantic \"exact same basename\" on/off choice into a more \n   graduated \"how similar are the pathnames\" scoring situation, in order \n   to be more likely to get the exact rename choice that people *expect* \n   to see, rather than other alternatives that may *technically* be \n   equally good, but are surprising to a human.\n\nIt's also unclear whether we should consider \"basenames are equal\" or \n\"have already used this as a source\" to be more important. This gives them \nequal weight, but I suspect we might want to just multiple the \"basenames \nare equal\" weight by two, or something, to prefer equal basenames even if \nthat causes a copy/delete pair. I dunno.\n\nAnyway, what I'm just saying in a really long-winded manner is that I \nthink this is right as-is, but it's not the complete solution, and it may \nwant some further tweaking in the future.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n---\n\nOn Thu, 29 Nov 2007, Kumar Gala wrote:\n> \n> let me know if there is anything else you need.\n\nNo, this was all right, and I've already got a patch ready for you to try.\n\nSo this patch actually does do what you want (for the exact renames, if \nnot for the u-boot.lds file), but I wanted to just point out that we will \nalmost certainly at least want to extend it to the inexact rename \ndetection logic too, _and_ we may well want to make the \"score\" \ncalculation a bit more involved depending on the actual filename, rather \nthan just depend on the equality of the basename.\n\n\t\tLinus\n\n---\n diffcore-rename.c |   25 ++++++++++++++++---------\n 1 files changed, 16 insertions(+), 9 deletions(-)\n\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex f9ebea5..f64294e 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -244,28 +244,35 @@ static int find_identical_files(struct file_similarity *src,\n \t * Walk over all the destinations ...\n \t */\n \tdo {\n-\t\tstruct diff_filespec *one = dst->filespec;\n+\t\tstruct diff_filespec *target = dst->filespec;\n \t\tstruct file_similarity *p, *best;\n-\t\tint i = 100;\n+\t\tint i = 100, best_score = -1;\n \n \t\t/*\n \t\t * .. to find the best source match\n \t\t */\n \t\tbest = NULL;\n \t\tfor (p = src; p; p = p->next) {\n-\t\t\tstruct diff_filespec *two = p->filespec;\n+\t\t\tint score;\n+\t\t\tstruct diff_filespec *source = p->filespec;\n \n \t\t\t/* False hash collission? */\n-\t\t\tif (hashcmp(one->sha1, two->sha1))\n+\t\t\tif (hashcmp(source->sha1, target->sha1))\n \t\t\t\tcontinue;\n \t\t\t/* Non-regular files? If so, the modes must match! */\n-\t\t\tif (!S_ISREG(one->mode) || !S_ISREG(two->mode)) {\n-\t\t\t\tif (one->mode != two->mode)\n+\t\t\tif (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {\n+\t\t\t\tif (source->mode != target->mode)\n \t\t\t\t\tcontinue;\n \t\t\t}\n-\t\t\tbest = p;\n-\t\t\tif (basename_same(one, two))\n-\t\t\t\tbreak;\n+\t\t\t/* Give higher scores to sources that haven't been used already */\n+\t\t\tscore = !source->rename_used;\n+\t\t\tscore += basename_same(source, target);\n+\t\t\tif (score > best_score) {\n+\t\t\t\tbest = p;\n+\t\t\t\tbest_score = score;\n+\t\t\t\tif (score == 2)\n+\t\t\t\t\tbreak;\n+\t\t\t}\n \n \t\t\t/* Too many identical alternatives? Pick one */\n \t\t\tif (!--i)\n"},{"id":"61431","messageId":"alpine.LFD.0.9999.0711291442300.8458@woody.linux-foundation.org","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711291303000.8458@woody.linux-foundation.org","subject":"Re: Fix a pathological case in git detecting proper renames","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-11-29T23:03:06Z","receivedAt":"2007-11-29T23:03:06Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 29 Nov 2007, Linus Torvalds wrote:\n> \n> It's worth noting a few gotchas:\n> \n>  - this scoring is currently only done for the \"exact match\" case. \n> \n>    In particular, in Kumar's example, even after this patch, the inexact\n>    match case is still done as a copy+delete rather than as two renames:\n> \n> \t delete mode 100644 board/cds/mpc8555cds/u-boot.lds\n> \t copy board/{cds => freescale}/mpc8541cds/u-boot.lds (97%)\n> \t rename board/{cds/mpc8541cds => freescale/mpc8555cds}/u-boot.lds (97%)\n> \n>    because apparently the \"cds/mpc8541cds/u-boot.lds\" copy looked \n>    a bit more similar to both end results. That said, I *suspect* we just \n>    have the exact same issue there - the similarity analysis just gave \n>    identical (or at least very _close_ to identical) similarity points, \n>    and we do not have any logic to prefer multiple renames over a \n>    copy/delete there.\n> \n>    That is a separate patch.\n\nSide note: just in case people were expecting me to actually _ship_ that \nseparate patch that handles the fuzzy matches too.. I wasn't planning on \ndoing that patch. The way the fuzzy rename detection is currently done, \nthat's actually quite painful.\n\nFor the fuzzy rename detection, we generate the full score matrix, and \nsort it by the score, up front. So all the scoring - and more importantly, \nall the sorting - has actually been done before we actually start looking \nat *any* renames at all, so we cannot easily do the same thing I did for \nthe exact renames, namely to take into account _earlier_ renames in the \nscoring. Because those earlier renames have simply not been done when the \nscore is calculated.\n\nThis would probably become easier to do with the linear-time hash-based \nsimilarity engine (the stuff Jeff King was working on), but the way the \ncode is currently structured - with no incremental rename detection at \nall, and with all the scoring in one global table - it's pretty painful.\n\n\t\t\tLinus\n"},{"id":"61434","messageId":"20071129235253.GA10261@coredump.intra.peff.net","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711291442300.8458@woody.linux-foundation.org","subject":"Re: Fix a pathological case in git detecting proper renames","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-11-29T23:52:53Z","receivedAt":"2007-11-29T23:52:53Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Nov 29, 2007 at 03:03:06PM -0800, Linus Torvalds wrote:\n\n> This would probably become easier to do with the linear-time hash-based \n> similarity engine (the stuff Jeff King was working on), but the way the \n> code is currently structured - with no incremental rename detection at \n> all, and with all the scoring in one global table - it's pretty painful.\n\nI think it will get worse, because you are simultaneously calculating\nall of the similarity scores bit by bit rather than doing a loop. Though\nperhaps you mean at the end you will end up with a list of src/dst pairs\nsorted by score, and you can loop over that.\n\n-Peff\n"},{"id":"61437","messageId":"finl2d$9rk$1@ger.gmane.org","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711290934260.8458@woody.linux-foundation.org","subject":"Re: problem with git detecting proper renames","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-11-30T00:21:32Z","receivedAt":"2007-11-30T00:21:32Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Linus Torvalds wrote:\n> On Thu, 29 Nov 2007, Kumar Gala wrote:\n>> \n>> I did some git-mv and got the following:\n>> \n>> the problem is git seems confused about what file was associated with its\n>> source.\n> \n> Well, I wouldn't say \"confused\". It found multiple identical options for \n> the source, and picked the first one (where \"first one\" may not be obvious \n> to a human, it can depend on an internal hash order).\n\nBy the way, which git version do you use? IIRC we have improved rename\ndetection heuristics to take into account similarity of filenames when\ncontents is identical...\n\n...ah, I see, it is git 1.5.3.4\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"61440","messageId":"7v4pf4tvka.fsf@gitster.siamese.dyndns.org","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711291442300.8458@woody.linux-foundation.org","subject":"Re: Fix a pathological case in git detecting proper renames","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-30T00:40:21Z","receivedAt":"2007-11-30T00:40:21Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> For the fuzzy rename detection, we generate the full score matrix, and \n> sort it by the score, up front. So all the scoring - and more importantly, \n> all the sorting - has actually been done before we actually start looking \n> at *any* renames at all, so we cannot easily do the same thing I did for \n> the exact renames, namely to take into account _earlier_ renames in the \n> scoring. Because those earlier renames have simply not been done when the \n> score is calculated.\n\nI think I've mentioned this before, but another thing we may want to do\nis to give similarity boost to a src-dst pair if other files in the same\nsrc directory are found to be renamed to the same dst directory.  That\nis, if you have the same contents in the preimage at A/init.S and B/init.S,\nand a similar contents appear in C/init.S in the postimage, instead of\nrandomly picking A/init.S over B/init.S as the source, we can notice\nthat A/Makefile was moved to C/Makefile (but B/Makefile was sufficiently\ndifferent from A/Makefile in the preimage), and favor A/init.S over\nB/init.S as the rename source of C/init.S.\n\nAbout the code structure, I think the very early draft of rename\ndetector did not do the full matrix, but iterated over dst to see if\nthere is a good src for it, picked the best src that is above the\nthreshold, and went on to next dst, like this:\n\n\tfor (dst in dst candidates) {\n        \tbest_src = NULL;\n                best_score = minimum_score;\n                for (src in src candidates) {\n                \tscore = similarity(dst, src);\n                        if (score > best_score)\n                            best_src = src;\n\t\t}\n\t\tif (best_src) {\n\t\t\tmatch dst with src;\n\t\t}\n\t}\n\nThis was restructured in the current \"full matrix first\" form before the\nrename detection logic first hit your tree, and I do not think it was\nshown in the field to perform worse than the full matrix version.\n\nWe could do the current full matrix that does not take basename\nsimilarity nor what other renames were detected first, and then use that\nmatrix result in order to primarily define the order of dst candidates\nto process and run the above loop.  At that point, similarity between\ndst and src does not need to be recomputed fully (the matrix would\nrecord it).  Instead, we can tweak it to take other renames that already\nhave been detected (this includes \"this src has already been used\", and\n\"somebody nearby moved to the same directory\") and basename similarity\nto affect which possible src candidate to choose for each dst.\n"},{"id":"61442","messageId":"alpine.LFD.0.9999.0711291625580.8458@woody.linux-foundation.org","threadId":"11060","inReplyTo":"20071129235253.GA10261@coredump.intra.peff.net","subject":"Re: Fix a pathological case in git detecting proper renames","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-11-30T00:41:09Z","receivedAt":"2007-11-30T00:41:09Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 29 Nov 2007, Jeff King wrote:\n> \n> I think it will get worse, because you are simultaneously calculating\n> all of the similarity scores bit by bit rather than doing a loop. Though\n> perhaps you mean at the end you will end up with a list of src/dst pairs\n> sorted by score, and you can loop over that.\n\nWell, after thinking about this a bit, I think there's a solution that may \nwork well with the current thing too: instead of looping just *once* over \nthe list of rename pairs, loop twice - and simply refuse to do copies on \nthe first loop.\n\nThis trivial patch does that, and turns Kumar's test-case into a perfect \nrename list.\n\nIt's not pretty, it's not smart, but it seems to work. There's something \nto be said for keeping it simple and stupid.\n\nAnd it should not be nearly as expensive as it may _look_. Yes, the loop \nis \"(i = 0; i < num_create * num_src; i++)\", but the important part is \nthat the whole array is sorted by rename score, and we have a\n\n\tif (mx[i].score < minimum_score)\n\t\tbreak;\n\nin it, so uthe loop actually would tend to terminate rather quickly.\n\nAnyway, Kumar, the thing to take away from this is:\n\n - git really doesn't even *care* about the whole \"rename detection\" \n   internally, and any commits you have done with renames are totally \n   independent of the heuristics we then use to *show* the renames.\n\n - the rename detection really is for just two reasons: (a) keep humans \n   happy, and keep the diffs small and (b) help automatic merging across \n   renames. So getting renames right is certainly good, but it's more of a \n   \"politeness\" issue than a \"correctness\" issue, although the merge \n   portion of it does matter a lot sometimes.\n\n - the important thing here is that you can commit your changes and not \n   worry about them being somehow \"corrupted\" by lack of rename detection, \n   even if you commit them with a version of git that doesn't do rename \n   detection the way you expected it. The rename detection is an \n   \"after-the-fact\" thing, not something that actually gets saved in the \n   repository, which is why we can change the heuristics _after_ seeing \n   examples, and the examples magically correct themselves!\n\n - try out the two patches I've posted, and see if they work for you. They \n   pass the test-suite, and the output for your example commit looks sane, \n   but hey, if you have other test-cases, try them out.\n\nHere's Kumar's pretty diffstat with both my patches:\n\n\t Makefile                                         |    6 +++---\n\t board/{cds => freescale}/common/cadmus.c         |    0\n\t board/{cds => freescale}/common/cadmus.h         |    0\n\t board/{cds => freescale}/common/eeprom.c         |    0\n\t board/{cds => freescale}/common/eeprom.h         |    0\n\t board/{cds => freescale}/common/ft_board.c       |    0\n\t board/{cds => freescale}/common/via.c            |    0\n\t board/{cds => freescale}/common/via.h            |    0\n\t board/{cds => freescale}/mpc8541cds/Makefile     |    0\n\t board/{cds => freescale}/mpc8541cds/config.mk    |    0\n\t board/{cds => freescale}/mpc8541cds/init.S       |    0\n\t board/{cds => freescale}/mpc8541cds/mpc8541cds.c |    0\n\t board/{cds => freescale}/mpc8541cds/u-boot.lds   |    4 ++--\n\t board/{cds => freescale}/mpc8548cds/Makefile     |    0\n\t board/{cds => freescale}/mpc8548cds/config.mk    |    0\n\t board/{cds => freescale}/mpc8548cds/init.S       |    0\n\t board/{cds => freescale}/mpc8548cds/mpc8548cds.c |    0\n\t board/{cds => freescale}/mpc8548cds/u-boot.lds   |    4 ++--\n\t board/{cds => freescale}/mpc8555cds/Makefile     |    0\n\t board/{cds => freescale}/mpc8555cds/config.mk    |    0\n\t board/{cds => freescale}/mpc8555cds/init.S       |    0\n\t board/{cds => freescale}/mpc8555cds/mpc8555cds.c |    0\n\t board/{cds => freescale}/mpc8555cds/u-boot.lds   |    4 ++--\n\t 23 files changed, 9 insertions(+), 9 deletions(-)\n\nand here it is before:\n\n\t Makefile                                           |    6 +-\n\t board/cds/mpc8548cds/Makefile                      |   60 -----\n\t board/cds/mpc8555cds/Makefile                      |   60 -----\n\t board/cds/mpc8555cds/init.S                        |  255 --------------------\n\t board/cds/mpc8555cds/u-boot.lds                    |  150 ------------\n\t board/{cds => freescale}/common/cadmus.c           |    0\n\t board/{cds => freescale}/common/cadmus.h           |    0\n\t board/{cds => freescale}/common/eeprom.c           |    0\n\t board/{cds => freescale}/common/eeprom.h           |    0\n\t board/{cds => freescale}/common/ft_board.c         |    0\n\t board/{cds => freescale}/common/via.c              |    0\n\t board/{cds => freescale}/common/via.h              |    0\n\t board/{cds => freescale}/mpc8541cds/Makefile       |    0\n\t board/{cds => freescale}/mpc8541cds/config.mk      |    0\n\t board/{cds => freescale}/mpc8541cds/init.S         |    0\n\t board/{cds => freescale}/mpc8541cds/mpc8541cds.c   |    0\n\t board/{cds => freescale}/mpc8541cds/u-boot.lds     |    4 +-\n\t .../mpc8541cds => freescale/mpc8548cds}/Makefile   |    0\n\t board/{cds => freescale}/mpc8548cds/config.mk      |    0\n\t board/{cds => freescale}/mpc8548cds/init.S         |    0\n\t board/{cds => freescale}/mpc8548cds/mpc8548cds.c   |    0\n\t board/{cds => freescale}/mpc8548cds/u-boot.lds     |    4 +-\n\t .../mpc8541cds => freescale/mpc8555cds}/Makefile   |    0\n\t board/{cds => freescale}/mpc8555cds/config.mk      |    0\n\t .../mpc8541cds => freescale/mpc8555cds}/init.S     |    0\n\t board/{cds => freescale}/mpc8555cds/mpc8555cds.c   |    0\n\t .../mpc8541cds => freescale/mpc8555cds}/u-boot.lds |    4 +-\n\t 27 files changed, 9 insertions(+), 534 deletions(-)\n\nso it certainly makes the diffs prettier.\n\n\t\tLinus\n\n---\n diffcore-rename.c |   13 +++++++++++++\n 1 files changed, 13 insertions(+), 0 deletions(-)\n\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex f64294e..3d37725 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -497,6 +497,19 @@ void diffcore_rename(struct diff_options *options)\n \tqsort(mx, num_create * num_src, sizeof(*mx), score_compare);\n \tfor (i = 0; i < num_create * num_src; i++) {\n \t\tstruct diff_rename_dst *dst = &rename_dst[mx[i].dst];\n+\t\tstruct diff_filespec *src;\n+\t\tif (dst->pair)\n+\t\t\tcontinue; /* already done, either exact or fuzzy. */\n+\t\tif (mx[i].score < minimum_score)\n+\t\t\tbreak; /* there is no more usable pair. */\n+\t\tsrc = rename_src[mx[i].src].one;\n+\t\tif (src->rename_used)\n+\t\t\tcontinue;\n+\t\trecord_rename_pair(mx[i].dst, mx[i].src, mx[i].score);\n+\t\trename_count++;\n+\t}\n+\tfor (i = 0; i < num_create * num_src; i++) {\n+\t\tstruct diff_rename_dst *dst = &rename_dst[mx[i].dst];\n \t\tif (dst->pair)\n \t\t\tcontinue; /* already done, either exact or fuzzy. */\n \t\tif (mx[i].score < minimum_score)\n"},{"id":"61443","messageId":"20071130004805.GA12185@coredump.intra.peff.net","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711291625580.8458@woody.linux-foundation.org","subject":"Re: Fix a pathological case in git detecting proper renames","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-11-30T00:48:05Z","receivedAt":"2007-11-30T00:48:05Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Nov 29, 2007 at 04:41:09PM -0800, Linus Torvalds wrote:\n\n> It's not pretty, it's not smart, but it seems to work. There's something \n> to be said for keeping it simple and stupid.\n> \n> And it should not be nearly as expensive as it may _look_. Yes, the loop \n> is \"(i = 0; i < num_create * num_src; i++)\", but the important part is \n> that the whole array is sorted by rename score, and we have a\n> \n> \tif (mx[i].score < minimum_score)\n> \t\tbreak;\n> \n> in it, so uthe loop actually would tend to terminate rather quickly.\n\nI think the slowdown is a non-issue. From the benchmarking I did in the\npast, all of the time was spent _before_ even getting to the qsort of\nscores. So even if you doubled the expense of that loop, it would have a\nnegligible impact.\n\nBut I haven't actually benchmarked this new patch, of course.\n\n-Peff\n"},{"id":"61456","messageId":"AC8DD8B5-C41E-4195-9CD6-E1A327F1878A@kernel.crashing.org","threadId":"11060","inReplyTo":"alpine.LFD.0.9999.0711291625580.8458@woody.linux-foundation.org","subject":"Re: Fix a pathological case in git detecting proper renames","fromName":"Kumar Gala","fromEmail":"galak@kernel.crashing.org","sentAt":"2007-11-30T01:18:04Z","receivedAt":"2007-11-30T01:18:04Z","isPatch":false,"sender":{"key":"galak@kernel.crashing.org","avatar":null},"body":"\nOn Nov 29, 2007, at 6:41 PM, Linus Torvalds wrote:\n\n>\n>\n> On Thu, 29 Nov 2007, Jeff King wrote:\n>>\n>> I think it will get worse, because you are simultaneously calculating\n>> all of the similarity scores bit by bit rather than doing a loop.  \n>> Though\n>> perhaps you mean at the end you will end up with a list of src/dst  \n>> pairs\n>> sorted by score, and you can loop over that.\n>\n> Well, after thinking about this a bit, I think there's a solution  \n> that may\n> work well with the current thing too: instead of looping just *once*  \n> over\n> the list of rename pairs, loop twice - and simply refuse to do  \n> copies on\n> the first loop.\n>\n> This trivial patch does that, and turns Kumar's test-case into a  \n> perfect\n> rename list.\n\nGlad I can be of use for something :)\n\n> It's not pretty, it's not smart, but it seems to work. There's  \n> something\n> to be said for keeping it simple and stupid.\n>\n> And it should not be nearly as expensive as it may _look_. Yes, the  \n> loop\n> is \"(i = 0; i < num_create * num_src; i++)\", but the important part is\n> that the whole array is sorted by rename score, and we have a\n>\n> \tif (mx[i].score < minimum_score)\n> \t\tbreak;\n>\n> in it, so uthe loop actually would tend to terminate rather quickly.\n>\n> Anyway, Kumar, the thing to take away from this is:\n>\n> - git really doesn't even *care* about the whole \"rename detection\"\n>   internally, and any commits you have done with renames are totally\n>   independent of the heuristics we then use to *show* the renames.\n>\n> - the rename detection really is for just two reasons: (a) keep humans\n>   happy, and keep the diffs small and (b) help automatic merging  \n> across\n>   renames. So getting renames right is certainly good, but it's more  \n> of a\n>   \"politeness\" issue than a \"correctness\" issue, although the merge\n>   portion of it does matter a lot sometimes.\n\nYeah both of these dawned on me after my brain started working and  \nthinking about what you were talking about when you say git manages  \n'content' and thinking about how the content management correlates to  \nthe diffs we generate.\n\n> - the important thing here is that you can commit your changes and not\n>   worry about them being somehow \"corrupted\" by lack of rename  \n> detection,\n>   even if you commit them with a version of git that doesn't do rename\n>   detection the way you expected it. The rename detection is an\n>   \"after-the-fact\" thing, not something that actually gets saved in  \n> the\n>   repository, which is why we can change the heuristics _after_ seeing\n>   examples, and the examples magically correct themselves!\n>\n> - try out the two patches I've posted, and see if they work for you.  \n> They\n>   pass the test-suite, and the output for your example commit looks  \n> sane,\n>   but hey, if you have other test-cases, try them out.\n\nOnly started using -M when a co-worker informed me about it.  But if I  \nsee other cases in the future I'll let you guys know.\n\n> Here's Kumar's pretty diffstat with both my patches:\n>\n> \t Makefile                                         |    6 +++---\n> \t board/{cds => freescale}/common/cadmus.c         |    0\n> \t board/{cds => freescale}/common/cadmus.h         |    0\n> \t board/{cds => freescale}/common/eeprom.c         |    0\n> \t board/{cds => freescale}/common/eeprom.h         |    0\n> \t board/{cds => freescale}/common/ft_board.c       |    0\n> \t board/{cds => freescale}/common/via.c            |    0\n> \t board/{cds => freescale}/common/via.h            |    0\n> \t board/{cds => freescale}/mpc8541cds/Makefile     |    0\n> \t board/{cds => freescale}/mpc8541cds/config.mk    |    0\n> \t board/{cds => freescale}/mpc8541cds/init.S       |    0\n> \t board/{cds => freescale}/mpc8541cds/mpc8541cds.c |    0\n> \t board/{cds => freescale}/mpc8541cds/u-boot.lds   |    4 ++--\n> \t board/{cds => freescale}/mpc8548cds/Makefile     |    0\n> \t board/{cds => freescale}/mpc8548cds/config.mk    |    0\n> \t board/{cds => freescale}/mpc8548cds/init.S       |    0\n> \t board/{cds => freescale}/mpc8548cds/mpc8548cds.c |    0\n> \t board/{cds => freescale}/mpc8548cds/u-boot.lds   |    4 ++--\n> \t board/{cds => freescale}/mpc8555cds/Makefile     |    0\n> \t board/{cds => freescale}/mpc8555cds/config.mk    |    0\n> \t board/{cds => freescale}/mpc8555cds/init.S       |    0\n> \t board/{cds => freescale}/mpc8555cds/mpc8555cds.c |    0\n> \t board/{cds => freescale}/mpc8555cds/u-boot.lds   |    4 ++--\n> \t 23 files changed, 9 insertions(+), 9 deletions(-)\n>\n> and here it is before:\n>\n> \t Makefile                                           |    6 +-\n> \t board/cds/mpc8548cds/Makefile                      |   60 -----\n> \t board/cds/mpc8555cds/Makefile                      |   60 -----\n> \t board/cds/mpc8555cds/init.S                        |  255  \n> --------------------\n> \t board/cds/mpc8555cds/u-boot.lds                    |  150  \n> ------------\n> \t board/{cds => freescale}/common/cadmus.c           |    0\n> \t board/{cds => freescale}/common/cadmus.h           |    0\n> \t board/{cds => freescale}/common/eeprom.c           |    0\n> \t board/{cds => freescale}/common/eeprom.h           |    0\n> \t board/{cds => freescale}/common/ft_board.c         |    0\n> \t board/{cds => freescale}/common/via.c              |    0\n> \t board/{cds => freescale}/common/via.h              |    0\n> \t board/{cds => freescale}/mpc8541cds/Makefile       |    0\n> \t board/{cds => freescale}/mpc8541cds/config.mk      |    0\n> \t board/{cds => freescale}/mpc8541cds/init.S         |    0\n> \t board/{cds => freescale}/mpc8541cds/mpc8541cds.c   |    0\n> \t board/{cds => freescale}/mpc8541cds/u-boot.lds     |    4 +-\n> \t .../mpc8541cds => freescale/mpc8548cds}/Makefile   |    0\n> \t board/{cds => freescale}/mpc8548cds/config.mk      |    0\n> \t board/{cds => freescale}/mpc8548cds/init.S         |    0\n> \t board/{cds => freescale}/mpc8548cds/mpc8548cds.c   |    0\n> \t board/{cds => freescale}/mpc8548cds/u-boot.lds     |    4 +-\n> \t .../mpc8541cds => freescale/mpc8555cds}/Makefile   |    0\n> \t board/{cds => freescale}/mpc8555cds/config.mk      |    0\n> \t .../mpc8541cds => freescale/mpc8555cds}/init.S     |    0\n> \t board/{cds => freescale}/mpc8555cds/mpc8555cds.c   |    0\n> \t .../mpc8541cds => freescale/mpc8555cds}/u-boot.lds |    4 +-\n> \t 27 files changed, 9 insertions(+), 534 deletions(-)\n>\n> so it certainly makes the diffs prettier.\n\nMuch better.  I love with open source development works.\n\n- k\n"}]}