{"thread":{"id":"8644","subject":"blame follows renames, but log doesn't","startedAt":"2007-06-19T01:10:28Z","lastAt":"2007-06-20T22:11:34Z","messageCount":10,"participants":["Martin Langhoff","Sam Vilain","Theodore Tso","Junio C Hamano","Steven Grimm","Jakub Narebski"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"45306","messageId":"46a038f90706181810p716f914al4d9abba5bfe7eb5@mail.gmail.com","threadId":"8644","inReplyTo":null,"subject":"blame follows renames, but log doesn't","fromName":"Martin Langhoff","fromEmail":"martin.langhoff@gmail.com","sentAt":"2007-06-19T01:10:28Z","receivedAt":"2007-06-19T01:10:28Z","isPatch":false,"sender":{"key":"martin.langhoff@gmail.com","avatar":"https://gravatar.com/avatar/1e3f311b6c4c15836501901ca58f8c0b0667246488084ba524d8bc9867e22fd9?d=mp&s=160"},"body":"Hi all,\n\nwhen I show git to newbies or demo it to people using other SCMs, and\nwe get to the rename part of the conversation, I discuss and show how\nGIT's approach is significantly better than explicit recording of\nrenames.\n\nOne great example is git-blame -- actually more spectacular with the\nrecent git gui blame improvements. But git-log still doesn't do it.\n\nIf I say\n   git blame git-cvsimport.perl  # goes to the true origin like a champ\n   git log git-cvsimport.perl # stops at the Big Tool Rename\n\nIn thread in May Linus posted a PoC patch to get git-blame to do it\nhttp://marc.info/?l=git&m=117347893211567&w=2 , and outlined the\nreasons why it'd be wrong to try to do that in git-log -- but it\ndidn't come to happen :-/\n\ncg-log used to have some Perl logic that could do this -- it didn't\nalways work, but I'm sometimes tempted to go back to it, and review\nit.\n\nLinus said:\n> But it's an example of the fact that yes, git can do this, but we're so\n> stupid that we don't really accept it.\n\nAnd I'm sure people can cope with git blame --log path/to/file and we\ncan add a note to git-log manpage about renames being reported by\nblame instead.\n\nAnd I kind of hate having to reply to things like these\n\n    http://www.markshuttleworth.com/archives/125\n\n\ncheers\n\n\nmartin\n"},{"id":"45310","messageId":"4677329E.3050903@vilain.net","threadId":"8644","inReplyTo":"46a038f90706181810p716f914al4d9abba5bfe7eb5@mail.gmail.com","subject":"Re: blame follows renames, but log doesn't","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-06-19T01:34:22Z","receivedAt":"2007-06-19T01:34:22Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Martin Langhoff wrote:\n> And I kind of hate having to reply to things like these\n> \n>     http://www.markshuttleworth.com/archives/125\n\nI think that there should be clear conventions for how to place such\nbreadcrumbs in the commit log, that can be suitably ignored or honoured.\n\nAt least these two things fit into this category:\n\n  1. renaming.  A comment on a changelog entry saying \"I moved this file\n     from A to B in this commit\".  With all of the user friendliness and\n     limitations this implies (oh, you got the information wrong or\n     didn't put it in?  oh well, now history is b0rked forever, HAND)\n\n  2. cherry picking.  bzr uses patch UUIDs, with all of the user\n     friendliness and limitations this implies (oh, you merged that\n     patch and accidentally didn't pick any changes?  whoops, it's\n     in your history anyway so never try to merge that again).\n\nPerhaps also there should be other conventions for how to encode other\nstrange data out of the namespace of the filesystem (\"in a different\ndimension\", perhaps) like \"file attributes\".\n\nSam.\n"},{"id":"45323","messageId":"20070619071916.GC9177@thunk.org","threadId":"8644","inReplyTo":"46a038f90706181810p716f914al4d9abba5bfe7eb5@mail.gmail.com","subject":"Re: blame follows renames, but log doesn't","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2007-06-19T07:19:16Z","receivedAt":"2007-06-19T07:19:16Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Tue, Jun 19, 2007 at 01:10:28PM +1200, Martin Langhoff wrote:\n> \n> when I show git to newbies or demo it to people using other SCMs, and\n> we get to the rename part of the conversation, I discuss and show how\n> GIT's approach is significantly better than explicit recording of\n> renames.\n> \n> One great example is git-blame -- actually more spectacular with the\n> recent git gui blame improvements. But git-log still doesn't do it.\n\nActually, the bigger missing gap is merges.  Suppose in the\ndevelopment branch, you rename a whole bunch of files.  (For example,\nfoo_super.c got moved to foo/super.c, foo_inode.c got moved to\nfoo/inode.c, etc.)\n\nNow suppose there are fixes made in the stable branch, in the original\nfoo_super.c and foo_inode.c files.  Ideally you would want to be able\nto pull those changes into the development branch, where the files\nhave new names, and have the changes be applied to foo/super.c and\nfoo/inode.c in the development branch.\n\nI was recently talking to someone who is still using BitKeeper, and he\ncited this scenario as one of the reasons why his project is still\nusing BK; he'd like to move to git, but this is a critical piece of\nfunctionality for him. \n\n\t\t\t\t\t\t- Ted\n"},{"id":"45329","messageId":"46a038f90706190131ub087df0pd7814b477c2a3b40@mail.gmail.com","threadId":"8644","inReplyTo":"20070619071916.GC9177@thunk.org","subject":"Re: blame follows renames, but log doesn't","fromName":"Martin Langhoff","fromEmail":"martin.langhoff@gmail.com","sentAt":"2007-06-19T08:31:38Z","receivedAt":"2007-06-19T08:31:38Z","isPatch":false,"sender":{"key":"martin.langhoff@gmail.com","avatar":"https://gravatar.com/avatar/1e3f311b6c4c15836501901ca58f8c0b0667246488084ba524d8bc9867e22fd9?d=mp&s=160"},"body":"On 6/19/07, Theodore Tso <tytso@mit.edu> wrote:\n> Actually, the bigger missing gap is merges.  Suppose in the\n> development branch, you rename a whole bunch of files.  (For example,\n> foo_super.c got moved to foo/super.c, foo_inode.c got moved to\n> foo/inode.c, etc.)\n\nI thought that the \"recursive\" strategy covered this - though I don't\nwork on a tree that merges across branches with renames, so my\nexperience is _very_ limited.\n\n>From Documentation/merge-strategies.txt:\n\n  Additionally this can detect and handle merges involving\n  renames.  This is the default merge strategy when\n  pulling or merging one branch.\n\ncheers\n\n\nm\n"},{"id":"45330","messageId":"7vtzt4wd68.fsf@assigned-by-dhcp.pobox.com","threadId":"8644","inReplyTo":"20070619071916.GC9177@thunk.org","subject":"Re: blame follows renames, but log doesn't","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-19T08:39:43Z","receivedAt":"2007-06-19T08:39:43Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> Actually, the bigger missing gap is merges.  Suppose in the\n> development branch, you rename a whole bunch of files.  (For example,\n> foo_super.c got moved to foo/super.c, foo_inode.c got moved to\n> foo/inode.c, etc.)\n>\n> Now suppose there are fixes made in the stable branch, in the original\n> foo_super.c and foo_inode.c files.  Ideally you would want to be able\n> to pull those changes into the development branch, where the files\n> have new names, and have the changes be applied to foo/super.c and\n> foo/inode.c in the development branch.\n\nThat happens already with merge-recursive code, which has been\nthe default since late November 2005 (v0.99.9k and later should\nhave it).\n\nWhat does _not_ happen is if foo_fixes.c was _created_ in the\nstable branch.  A merge that tries to forward port such a fix\nwould not move the foo_fixes.c to foo/fixes.c.\n"},{"id":"45337","messageId":"4677A7EF.500@midwinter.com","threadId":"8644","inReplyTo":"20070619071916.GC9177@thunk.org","subject":"Re: blame follows renames, but log doesn't","fromName":"Steven Grimm","fromEmail":"koreth@midwinter.com","sentAt":"2007-06-19T09:54:55Z","receivedAt":"2007-06-19T09:54:55Z","isPatch":false,"sender":{"key":"koreth@midwinter.com","avatar":"https://gravatar.com/avatar/71b4d2e8b62f168bdc9e9205341159e3567003b4f9e2127c617c5fa0a1f5bad2?d=mp&s=160"},"body":"Theodore Tso wrote:\n> Actually, the bigger missing gap is merges.  Suppose in the\n> development branch, you rename a whole bunch of files.  (For example,\n> foo_super.c got moved to foo/super.c, foo_inode.c got moved to\n> foo/inode.c, etc.)\n>\n> Now suppose there are fixes made in the stable branch, in the original\n> foo_super.c and foo_inode.c files.  Ideally you would want to be able\n> to pull those changes into the development branch, where the files\n> have new names, and have the changes be applied to foo/super.c and\n> foo/inode.c in the development branch.\n>   \n\nI believe git handles this case already, actually. I've seen this work \njust fine many times.\n\nWhat git doesn't handle, but BitKeeper does, is applying directory \nrenames to newly created files. I rename the \"lib\" directory to \"util\", \nyou create a new file lib/strings.c and update lib/Makefile to compile \nit. I pull from you. Under BitKeeper, I will get util/strings.c and the \nchange will be applied to my util/Makefile. git will create a brand-new \n\"lib\" directory containing nothing but the new file, but since the \nMakefile existed before, it will (correctly) apply your change to my \nutil/Makefile, which will then break my build because it will refer to a \nfile that doesn't exist in the Makefile's directory.\n\nThis has bitten me a few times in real life, e.g. in cases where I'm \nimporting a third-party source tarfile and reorganizing it a little to \nfit it into my local build system. Every time they add a new source \nfile, I have to go manually clean up after it rather than just merging \nthe vendor branch into mine like I can do when they don't add anything. \nIt is not frequent enough to be a major hassle for me but it sure is \nannoying when it happens (especially since sometimes the build *doesn't* \nbreak and it takes a while to notice a newly created file isn't where it \nshould be.)\n\n-Steve\n"},{"id":"45372","messageId":"4678204C.6050409@midwinter.com","threadId":"8644","inReplyTo":"4677A7EF.500@midwinter.com","subject":"Directory renames (was Re: blame follows renames, but log doesn't)","fromName":"Steven Grimm","fromEmail":"koreth@midwinter.com","sentAt":"2007-06-19T18:28:28Z","receivedAt":"2007-06-19T18:28:28Z","isPatch":false,"sender":{"key":"koreth@midwinter.com","avatar":"https://gravatar.com/avatar/71b4d2e8b62f168bdc9e9205341159e3567003b4f9e2127c617c5fa0a1f5bad2?d=mp&s=160"},"body":"Directory renames can break in more cases than just adding new files. \nHere's a demonstration based on a situation I ran into a few minutes ago \non a real-world project.\n\n$ git init\n$ mkdir a\n$ echo some contents > a/file1\n$ echo other contents > a/file2\n$ git add a\n$ git commit -m \"initial commit\"\n\nSo far so good. Now there's a revision where the files happen to be \nidentical. (On a new branch for later convenience.)\n\n$ git checkout -b modifybranch\n$ echo other contents > a/file1\n$ git commit -a -m \"commit that makes both files identical\"\n\nNow we rename the directory. (Again, the new branch will be used later.)\n\n$ git checkout -b renamebranch\n$ git mv a b\n$ git commit -m \"rename directory\"\n\nMake a change to file2.\n\n$ echo more contents from renamebranch >> b/file2\n$ git commit -a -m \"add contents to file2\"\n\nWhere did file2's contents come from?\n\n$ git blame b/file2\na7dbcfdc a/file1 (Steven Grimm 2007-06-19 10:36:20 -0700 1) other contents\n69a87194 b/file2 (Steven Grimm 2007-06-19 10:43:29 -0700 2) more contents\n\nWhich is wrong. The history of file2 has nothing to do with the history \nof file1, but git blame thinks it does. However, that's not what blew up \non me in my real-world test; it gets better. Let's say one of the files \nchanged in a different branch.\n\n$ git checkout master\n$ echo a change to file2 in master >> a/file2\n$ git commit -a -m \"file2 changed\"\n\n$ git merge renamebranch\nRemoved a/file1\nMerge made by recursive.\n a/file1            |    1 -\n a/file2 => b/file1 |    0\n b/file2            |    2 ++\n 3 files changed, 2 insertions(+), 1 deletions(-)\n delete mode 100644 a/file1\n rename a/file2 => b/file1 (100%)\n create mode 100644 b/file2\n\nAnd this is just completely broken. What it *should* do is give me \nb/file1 with \"other contents\" from renamebranch, and b/file2 with a \nmerge conflict since I added a different line to it in each branch. \nInstead, the merge succeeds with no conflict and applies the change in \nmy current branch to the wrong file:\n\n$ cat b/file1\nother contents\na change to file2 in master\n$ cat b/file2\nother contents\nmore contents from renamebranch\n\nThere's one more variation on this theme that's broken in a similar but \nnot identical way (this didn't happen in my real-world scenario but I \nran into it while coming up with the above test case):\n\n$ git checkout modifybranch\n$ echo a change to file2 in modifybranch >> a/file2\n$ git commit -a -m \"a change in modifybranch\"\n$ git merge renamebranch\nCONFLICT (delete/modify): a/file2 deleted in renamebranch and modified \nin HEAD. Version HEAD of a/file2 left in tree.\nAutomatic merge failed; fix conflicts and then commit the result.\n\nThis should definitely be a merge conflict, but it shouldn't be *this* \nmerge conflict. What I'd expect here would be b/file1 == \"other \ncontents\" and b/file2 with conflict markers.\n\n$ ls a b\na:\nfile2\n\nb:\nfile1   file2\n$ cat a/file2\nother contents\na change to file2 in modifybranch\n$ cat b/file1\nother contents\n$ cat b/file2\nother contents\nmore contents from renamebranch\n\nIn other words, no conflict markers at all, and I still have the old \ndirectory \"a\" with one of its two files in original form, but not the \nother file.\n\nHope that's illuminating or at least interesting to someone.\n\n-Steve\n"},{"id":"45437","messageId":"46798B8E.6040103@vilain.net","threadId":"8644","inReplyTo":"4678204C.6050409@midwinter.com","subject":"Re: Directory renames (was Re: blame follows renames, but log doesn't)","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-06-20T20:18:22Z","receivedAt":"2007-06-20T20:18:22Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Steven Grimm wrote:\n> Hope that's illuminating or at least interesting to someone.\n\nI didn't review your test cases in detail, but they seemed to suffer\nfrom what I call \"over-trivialization\"; the heuristic methods don't work\nvery well for these non-real-world test cases because they're not long\nenough.  Are you confident that these deficiencies are still there with\nlonger examples?\n\nSam.\n"},{"id":"45443","messageId":"46799541.6020608@midwinter.com","threadId":"8644","inReplyTo":"46798B8E.6040103@vilain.net","subject":"Re: Directory renames (was Re: blame follows renames, but log doesn't)","fromName":"Steven Grimm","fromEmail":"koreth@midwinter.com","sentAt":"2007-06-20T20:59:45Z","receivedAt":"2007-06-20T20:59:45Z","isPatch":false,"sender":{"key":"koreth@midwinter.com","avatar":"https://gravatar.com/avatar/71b4d2e8b62f168bdc9e9205341159e3567003b4f9e2127c617c5fa0a1f5bad2?d=mp&s=160"},"body":"Sam Vilain wrote:\n> I didn't review your test cases in detail, but they seemed to suffer\n> from what I call \"over-trivialization\"; the heuristic methods don't work\n> very well for these non-real-world test cases because they're not long\n> enough.  Are you confident that these deficiencies are still there with\n> longer examples?\n>   \n\nThose test cases were a demonstration of something I actually ran into \non a real-world project yesterday. The test cases are trivial and short \nsimply to make them easy to follow in an email message. If you \nsubstitute longer contents for the test files in my example, you will \nsee the exact same behavior. The real file in question is around 2KB \nlong, not a monster but presumably long enough that the heuristics \nshould work.\n\nAlso -- though this doesn't happen to be relevant in the case where I \nran into this -- not all files in real-world projects are huge. If the \nheuristics break on small test-case files then they will break on small \nreal-world files too. If nothing else, a real-world project can itself \ncontain trivial test data (for testing the project, not testing the \nversion control system) in the form of lots of small files with similar \nor identical contents.\n\n-Steve\n"},{"id":"45447","messageId":"f5c8mm$jaj$1@sea.gmane.org","threadId":"8644","inReplyTo":"4677A7EF.500@midwinter.com","subject":"Re: blame follows renames, but log doesn't","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-06-20T22:11:34Z","receivedAt":"2007-06-20T22:11:34Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Steven Grimm wrote:\n\n> What git doesn't handle, but BitKeeper does, is applying directory \n> renames to newly created files. I rename the \"lib\" directory to \"util\", \n> you create a new file lib/strings.c and update lib/Makefile to compile \n> it. I pull from you. Under BitKeeper, I will get util/strings.c and the \n> change will be applied to my util/Makefile. git will create a brand-new \n> \"lib\" directory containing nothing but the new file, but since the \n> Makefile existed before, it will (correctly) apply your change to my \n> util/Makefile, which will then break my build because it will refer to a \n> file that doesn't exist in the Makefile's directory.\n> \n> This has bitten me a few times in real life, e.g. in cases where I'm \n> importing a third-party source tarfile and reorganizing it a little to \n> fit it into my local build system. Every time they add a new source \n> file, I have to go manually clean up after it rather than just merging \n> the vendor branch into mine like I can do when they don't add anything. \n> It is not frequent enough to be a major hassle for me but it sure is \n> annoying when it happens (especially since sometimes the build *doesn't* \n> break and it takes a while to notice a newly created file isn't where it \n> should be.)\n\nI think git can at least try to detect this situation, and perhaps\neven resolve this automatically. Namely, if we add file with the\nfollowing <path>: <dirname>/<basename>, and <dirname> tree does exists in\nthe ancestor but does not exist in the other branch, this is CONFLICT(add)\n(or something like that), with appropriate explanation.\n\nOne way to resolve this CONFLICT(add) automatically would be to check where\nall the files in no longer existing <dirname> moved to, and if they all are\nof the form <newdir>/<somename> then we should add the <dirname>/<basename>\nfile under <newdir>/<basename>. If some of them were moved to other\ndirectory, for example contents of one directory got split into two\ndirectories, this is conflict which cannot be resolved automaticaly\n(CONFLICT(add/multiple) or something like that perhaps?). And I guess that\nSCM which _track_ renaming of directories, like Bazaar-NG, would NOT detect\nthis as a conflict, and happily add to perhaps wrong directory.\n\nOr we could reuse rename detection, taking modes+filenames as tree contents,\nor perhaps set of file contents as tree contents, for our content based\nrename detection.\n\n\nP.S. Allow me to remind you rename _detection_ success story, send here some\ntime ago by Johannes Schindelin in the \"Rename handling\" thread:\n  Message-ID: <Pine.LNX.4.63.0703210120230.22628@wbgn013.biozentrum.uni-wuerzburg.de>\n  http://permalink.gmane.org/gmane.comp.version-control.git/42770\n\nJS> By now, there have been enough arguments _for_ automatic rename detection, \nJS> but I'll add another one.\nJS> \nJS> A colleague of mine worked on a certain file in a branch, where he copied \nJS> the file to another location, and heavily modified it. He did that in a \nJS> branch, and when he was satisfied with the result, he deleted the old \nJS> file, since he liked the new location better.\nJS> \nJS> Now, when I pulled, imagine my surprise (knowing the history of the file), \nJS> when the pull reported a rename with a substantial similarity!\nJS> \nJS> So, the automatic renamer did an awesome job.\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"}]}