{"thread":{"id":"7167","subject":"git-log --full-history renamed-file","startedAt":"2007-03-09T21:30:23Z","lastAt":"2007-03-10T06:14:02Z","messageCount":8,"participants":["Jim Meyering","Linus Torvalds","Junio C Hamano","Jakub Narebski","Andy Parkins"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"36690","messageId":"87lki6umts.fsf@rho.meyering.net","threadId":"7167","inReplyTo":null,"subject":"git-log --full-history renamed-file","fromName":"Jim Meyering","fromEmail":"jim@meyering.net","sentAt":"2007-03-09T21:30:23Z","receivedAt":"2007-03-09T21:30:23Z","isPatch":false,"sender":{"key":"jim@meyering.net","avatar":"https://avatars.githubusercontent.com/u/710630?v=4"},"body":"Hello,\n\nIs there some git-log-like command (or some git-log option)\nto print a log of deltas affecting a file across renames?\n\nI know that git-annotate can detect renames (and gitk),\nbut that's not quite the interface I was looking for.\n\nI've tried with git-log --full-history, with and without --parents,\nto no avail.  Adding --parents does make it produce a couple more\nlog entries, but they are not relevant.\n\nThe \"Why does git not track renames?\" section in the wiki,\nhttp://git.or.cz/gitwiki/Godfry says that \"git-log -M\"\nwill do what I want, but that appears to have no effect.\n\nTo be precise, I'd like to run a command like this\n\n  git-log <options> current-name\n\nto summarize the commits affecting current-name as well as\nthose affecting old-name (which I git-mv'd to current-name).\n\nJim\n"},{"id":"36694","messageId":"Pine.LNX.4.64.0703091339190.10832@woody.linux-foundation.org","threadId":"7167","inReplyTo":"87lki6umts.fsf@rho.meyering.net","subject":"Re: git-log --full-history renamed-file","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-03-09T22:20:55Z","receivedAt":"2007-03-09T22:20:55Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n[ See toy patch at the end as an example of how you could do somethign \n  like this better. I started out just explaining what git does, but ended \n  up writing a simple patch that kind of shows an example of how it could \n  be implemented ]\n\nOn Fri, 9 Mar 2007, Jim Meyering wrote:\n> \n> Is there some git-log-like command (or some git-log option)\n> to print a log of deltas affecting a file across renames?\n\nThere were patches floating around for an option called \"--follow\" to \"git \nlog\", that would actually follow the renames. \n\nI don't remember what happened to them - I suspect the implementation \nwasn't up to snuff. But the *concept* is definitely right.\n\n> I know that git-annotate can detect renames (and gitk),\n> but that's not quite the interface I was looking for.\n> \n> I've tried with git-log --full-history, with and without --parents,\n> to no avail.  Adding --parents does make it produce a couple more\n> log entries, but they are not relevant.\n\nYeah, those don't really do what you want. They are entirely about the \n\"time view\" of the commits, they don't move in \"space\"\n\n[ That's just my personal terminology: git tracks data in two different \n  dimensions: the contents (\"space\") and the history (\"time\"). So with \n  \"git log\" you can limit both the content dimension (by path limiters) \n  and the history dimension (with revision limiters).\n\n  So --full-history and --parents are about showing more detail or \n  changing the limiting in that history dimension, but they do not affect \n  the content dimension. What you want to do is to let the content \n  limiters change over time, and yes, \"git annotate\" obviously does \n  exactly that, but no, we don't do it in \"git log\", and the space \n  limiters are entirely static over time right now ]\n\n> The \"Why does git not track renames?\" section in the wiki,\n> http://git.or.cz/gitwiki/Godfry says that \"git-log -M\"\n> will do what I want, but that appears to have no effect.\n\nActually, it will have effect, but it will have an effect only *within* \nthe space limiter (and only when you actually *watch* what happens by \nshowing the patches).\n\nSo for an example of the effect, do\n\n\tgit log -p 76cead39 Documentation\n\n(or \"git show\" with, and without an \"-M\").\n\nSo no, the -M flag does *not* do what you want. Yes, it detects renames, \nbut it does so within individual diffs, not over time. So to go back to my \nspace/time analogy, \"-M\" works 100% in space, it's a one-time temporal \nevent for showing single commit, it doesn't actually start following \nhistory down under any other name.\n\n> To be precise, I'd like to run a command like this\n> \n>   git-log <options> current-name\n> \n> to summarize the commits affecting current-name as well as\n> those affecting old-name (which I git-mv'd to current-name).\n\nYes. Rigth now you *can* emulate this (in a very cumbersome manner!) by \nletting \"git show -M\" help you see what happened. Eg, in git, many files \nhave gotten renamed over time, and you can do something like\n\n\tgit log builtin-rev-list.c\n\nand when you go to the end of that result, you'll see the first commit \nwhere it showed up under that name:\n\n\t5fb61b8d: Make \"git rev-list\" be a builtin\n\nand *now* you can use the \"-M\" flag to let git figure out what happened:\n\n\tgit show -M 5fb61b8d\n\nwhich will have\n\n\tdiff --git a/rev-list.c b/builtin-rev-list.c\n\tsimilarity index 99%\n\trename from rev-list.c\n\trename to builtin-rev-list.c\n\n(there are lots of other options, ie you could have used\n\n\tgit show -M --name-status --pretty=oneline 5fb61b8d\n\nand it would show the changes in a much condensed manner, but still \nshowing the fact that \"rev-list.c\" got renamed to \"builtin-rev-list.c\" in \nthat commit.\n\nAnd after that, you could re-start the log from that point on (or rather, \nthe parent), and with that older name:\n\n\tgit log 5fb61b8d^ -- rev-list.c\n\nIn other words:\n\n - git can do it, but doesn't really have the interfaces to do it sanely \n   right now.\n\n - you can do it by hand\n\n - it's almost silly, but \"git blame\" internally really already has all \n   the logic for this, it's just not exposed any sane way to a user.\n\nI'm appending a REALLY UGLY patch that makes\n\n\tgit blame --log filename.c\n\nwork kind of like you'd want. IT IS NOT MEANT TO BE REALLY USED, because \nin particular, it doesn't take the nice log options (so you cannot make it \nshow diffs etc, even though we have all the machinery in place for that). \nBut it's an example of the fact that yes, git can do this, but we're so \nstupid that we don't really accept it.\n\n(NOTE! It's also almost totally untested. It might not work. I'm sending \nit out as a very rough example, not as a serious contender)\n\n\t\tLinus\n\n---\ndiff --git a/builtin-blame.c b/builtin-blame.c\nindex b51cdc7..470f3ae 100644\n--- a/builtin-blame.c\n+++ b/builtin-blame.c\n@@ -41,8 +41,11 @@ static int max_score_digits;\n static int show_root;\n static int blank_boundary;\n static int incremental;\n+static int log;\n static int cmd_is_annotate;\n \n+static struct rev_info log_rev;\n+\n #ifndef DEBUG\n #define DEBUG 0\n #endif\n@@ -1376,6 +1379,16 @@ static void found_guilty_entry(struct blame_entry *ent)\n \tif (ent->guilty)\n \t\treturn;\n \tent->guilty = 1;\n+\tif (log) {\n+\t\tstruct origin *suspect = ent->suspect;\n+\t\tstruct commit *commit = suspect->commit;\n+\n+\t\tif (commit->object.flags & SHOWN)\n+\t\t\treturn;\n+\t\tcommit->object.flags |= SHOWN;\n+\t\tlog_tree_commit(&log_rev, commit);\n+\t\treturn;\n+\t}\n \tif (incremental) {\n \t\tstruct origin *suspect = ent->suspect;\n \n@@ -2073,7 +2086,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \tcmd_is_annotate = !strcmp(argv[0], \"annotate\");\n \n \tgit_config(git_blame_config);\n-\tsave_commit_buffer = 0;\n+//\tsave_commit_buffer = 0;\n \n \topt = 0;\n \tseen_dashdash = 0;\n@@ -2139,6 +2152,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \t\t\tseen_dashdash = 1;\n \t\t\ti++;\n \t\t\tbreak;\n+\t\t} if (!strcmp(\"--log\", arg)) {\n+\t\t\tlog = 1;\n+\t\t\tinit_revisions(&log_rev, NULL);\n+\t\t\tlog_rev.diff = 1;\n+\t\t\tlog_rev.diffopt.recursive = 1;\n+\t\t\tlog_rev.commit_format = CMIT_FMT_DEFAULT;\n+\t\t\tlog_rev.verbose_header = 1;\n+\t\t\tlog_rev.abbrev = DEFAULT_ABBREV;\n \t\t}\n \t\telse\n \t\t\targv[unk++] = arg;\n@@ -2336,7 +2357,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \n \tassign_blame(&sb, &revs, opt);\n \n-\tif (incremental)\n+\tif (incremental || log)\n \t\treturn 0;\n \n \tcoalesce(&sb);\n"},{"id":"36707","messageId":"7v8xe53ok5.fsf@assigned-by-dhcp.cox.net","threadId":"7167","inReplyTo":"Pine.LNX.4.64.0703091339190.10832@woody.linux-foundation.org","subject":"Re: git-log --full-history renamed-file","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-10T00:55:06Z","receivedAt":"2007-03-10T00:55:06Z","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> There were patches floating around for an option called \"--follow\" to \"git \n> log\", that would actually follow the renames. \n>\n> I don't remember what happened to them - I suspect the implementation \n> wasn't up to snuff. But the *concept* is definitely right.\n\nYes, the concept is good.  It was from Fredrik of\nmerge-recursive fame.\n\nThe patch was not _bad_, but it looked a bit too intrusive back\nthen and scared me away.\n"},{"id":"36717","messageId":"est24q$p4n$1@sea.gmane.org","threadId":"7167","inReplyTo":"7v8xe53ok5.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-log --full-history renamed-file","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-03-10T01:40:07Z","receivedAt":"2007-03-10T01:40:07Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n\n> Linus Torvalds <torvalds@linux-foundation.org> writes:\n> \n>> There were patches floating around for an option called \"--follow\" to \"git \n>> log\", that would actually follow the renames. \n>>\n>> I don't remember what happened to them - I suspect the implementation \n>> wasn't up to snuff. But the *concept* is definitely right.\n> \n> Yes, the concept is good.  It was from Fredrik of\n> merge-recursive fame.\n> \n> The patch was not _bad_, but it looked a bit too intrusive back\n> then and scared me away.\n\nIf I remember correctly it had somewhat unfortunate timing, as it\nwas around changes in the same area.\n\nBy the way, while it is fairly easy to follow one file, it is hard\nto follow directory or glob... and there is a trouble that one file\nmight come from two files (as concatenation for example; but I don't\nthink git can detect it with default values of rename detection\nheuristics). \n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"36715","messageId":"7vejnxzwmp.fsf@assigned-by-dhcp.cox.net","threadId":"7167","inReplyTo":"Pine.LNX.4.64.0703091339190.10832@woody.linux-foundation.org","subject":"Re: git-log --full-history renamed-file","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-10T01:59:42Z","receivedAt":"2007-03-10T01:59:42Z","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>  - it's almost silly, but \"git blame\" internally really already has all \n>    the logic for this, it's just not exposed any sane way to a user.\n>\n> I'm appending a REALLY UGLY patch that makes\n>\n> \tgit blame --log filename.c\n>\n> work kind of like you'd want. IT IS NOT MEANT TO BE REALLY USED, because \n> in particular, it doesn't take the nice log options (so you cannot make it \n> show diffs etc, even though we have all the machinery in place for that). \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>\n> (NOTE! It's also almost totally untested. It might not work. I'm sending \n> it out as a very rough example, not as a serious contender)\n>\n> \t\tLinus\n\nAt this point that you call log_tree_commit(), \n\n> @@ -1376,6 +1379,16 @@ static void found_guilty_entry(struct blame_entry *ent)\n>  \tif (ent->guilty)\n>  \t\treturn;\n>  \tent->guilty = 1;\n> +\tif (log) {\n> +\t\tstruct origin *suspect = ent->suspect;\n> +\t\tstruct commit *commit = suspect->commit;\n> +\n> +\t\tif (commit->object.flags & SHOWN)\n> +\t\t\treturn;\n> +\t\tcommit->object.flags |= SHOWN;\n> +\t\tlog_tree_commit(&log_rev, commit);\n> +\t\treturn;\n> +\t}\n\nyou have not just the path information _but_ also the line range\nin the postimage, so we could use an enhanced version of\nlog_tree_commit() that also lets us limit its output only to\nhunks that touch the affected range.\n\nAlso, found_guilty_entry() is called number of times for the\nsame suspect <commit, path> pair for discontiguous line ranges.\nI think a saner thing to do is to collect and coalesce the blame\nentry for the same <commit, path> in the above part of the code,\nand then do a single log_tree_commit() for the <commit, path>,\nperhaps limiting to the hunks that touch the line ranges the\ncommit is assigned blame for, before continuing to a different\ncommit (i.e. after the for() loop, which is the only caller of\nthis found_guilty_entry() function, exits).\n"},{"id":"36719","messageId":"7v6499zvyl.fsf@assigned-by-dhcp.cox.net","threadId":"7167","inReplyTo":"est24q$p4n$1@sea.gmane.org","subject":"Re: git-log --full-history renamed-file","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-10T02:14:10Z","receivedAt":"2007-03-10T02:14:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> By the way, while it is fairly easy to follow one file, it is hard\n> to follow directory or glob... and there is a trouble that one file\n> might come from two files (as concatenation for example; but I don't\n> think git can detect it with default values of rename detection\n> heuristics). \n\nThat's why Linus's proof-of-concept is based on the git-blame\nengine.\n"},{"id":"36720","messageId":"Pine.LNX.4.64.0703091813240.10832@woody.linux-foundation.org","threadId":"7167","inReplyTo":"est24q$p4n$1@sea.gmane.org","subject":"Re: git-log --full-history renamed-file","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-03-10T02:14:33Z","receivedAt":"2007-03-10T02:14:33Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 10 Mar 2007, Jakub Narebski wrote:\n>\n> By the way, while it is fairly easy to follow one file, it is hard\n> to follow directory or glob...\n\nDon't even try. Make it clear that the rename-following automatically \nmeans that you only do the trivially obvious cases. Anything else is \nmadness.\n\nIf you want to know where something actually comes from, use \"blame\".\n\n\t\tLinus\n"},{"id":"36731","messageId":"200703100614.04526.andyparkins@gmail.com","threadId":"7167","inReplyTo":"est24q$p4n$1@sea.gmane.org","subject":"Re: git-log --full-history renamed-file","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2007-03-10T06:14:02Z","receivedAt":"2007-03-10T06:14:02Z","isPatch":false,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Saturday 2007, March 10, Jakub Narebski wrote:\n\n> By the way, while it is fairly easy to follow one file, it is hard\n> to follow directory or glob... and there is a trouble that one file\n> might come from two files (as concatenation for example; but I don't\n> think git can detect it with default values of rename detection\n> heuristics).\n\nThat's not rename detection then though.\n\nI know git is clever and has potential to be able to do rename detection \neven when it was rename-and-modify.  For me though, I always like to \nmake the job of the VCS easier by doing the rename in a separate commit \nfrom the modify.\n\nI'd really like it if git would deal with the easy, 100% rename case, \neven if it didn't deal with the \nrename-two-files-to-be-one-file-and-modify-the-result case. \n\n\n\nAndy\n-- \nDr Andy Parkins, M Eng (hons), MIET\nandyparkins@gmail.com\n"}]}