{"thread":{"id":"16973","subject":"how to track the history of a line in a file","startedAt":"2009-01-02T21:26:56Z","lastAt":"2009-01-06T16:28:54Z","messageCount":17,"participants":["david@lang.hm","Jeff King","Jeff Whiteside","Junio C Hamano","Thomas Rast","Bernt Hansen","Miklos Vajna"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"99202","messageId":"20090102212655.GA24082@coredump.intra.peff.net","threadId":"16973","inReplyTo":"alpine.DEB.1.10.0901021405460.21567@asgard.lang.hm","subject":"Re: how to track the history of a line in a file","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-01-02T21:26:56Z","receivedAt":"2009-01-02T21:26:56Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 02, 2009 at 02:13:32PM -0800, david@lang.hm wrote:\n\n> I have a need to setup a repository where I'm storing config files, and I  \n> need to be able to search the history of a particular line, not just when  \n> the last edit of the line was (which is what I see from git blame)\n\nAs you figured out, the \"manual\" way is to just keep reblaming from the\nparent of each blame. Recent versions of \"git gui blame\" have a \"reblame\nfrom parent\" option in the context menu which makes this a lot less\npainful.\n\n> 57f8f7b6 (Linus Torvalds 2008-10-23 20:06:52 -0700 3) SUBLEVEL = 28\n>\n> what I would want it to show would be a list of the commits that have  \n> changed this line.\n\nThe tricky thing here is what is \"this line\"? Using the line number\nisn't right, since it will change based on other content coming in and\nout of the file. You can keep drilling down by reblaming parent commits,\nbut remember that each time you do that you are manually looking at the\ncontent and saying \"Oh, this is the line I am still interested in.\" So I\na script would have to correlate the old version and new version of the\nline and realize how to follow the \"interesting\" thing.\n\nIn your case, I think you want to see any commit in Makefile which\nchanged a line with SUBLEVEL in it. Which is maybe easiest done as:\n\n  git log -z -p Makefile |\n    perl -0ne 'print if /\\n[+-]SUBLEVEL/' |\n    tr '\\0' '\\n'\n\nand is pretty fast. But obviously we're leveraging some content-specific\nknowledge about what's in the Makefile.\n\n-Peff\n"},{"id":"99206","messageId":"3ab397d0901021349h4ebae0c1g460a0c8abd4ec072@mail.gmail.com","threadId":"16973","inReplyTo":"alpine.DEB.1.10.0901021439080.21567@asgard.lang.hm","subject":"Re: how to track the history of a line in a file","fromName":"Jeff Whiteside","fromEmail":"jeff.m.whiteside@gmail.com","sentAt":"2009-01-02T21:49:34Z","receivedAt":"2009-01-02T21:49:34Z","isPatch":false,"sender":{"key":"jeff.m.whiteside@gmail.com","avatar":null},"body":"> -oldline\n> +newline\n>\n> it's a 1-1 correspondence\n>\n> if it's instead\n> -oldline1\n> -oldline2\n> +newline1\n> +newline2\n\nwhat a neat idea.  i'm going to start malloc'ing 10,000 lines x 120\nchars for each file i add, and edit them so that no new lines replace\nremoved lines unless it's intended that they were the same line.\n"},{"id":"99201","messageId":"alpine.DEB.1.10.0901021405460.21567@asgard.lang.hm","threadId":"16973","inReplyTo":null,"subject":"how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-02T22:13:32Z","receivedAt":"2009-01-02T22:13:32Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"I have a need to setup a repository where I'm storing config files, and I \nneed to be able to search the history of a particular line, not just when \nthe last edit of the line was (which is what I see from git blame)\n\nI'm not seeing a obvious way to do this, am I missing something or does it \nneed a non-obvious approach?\n\nfor example, if I do\n\ngit blame -L /SUBLEVEL/,+1 -M Makefile\n\non the linux kernel it currently shows\n\n57f8f7b6 (Linus Torvalds 2008-10-23 20:06:52 -0700 3) SUBLEVEL = 28\n\nwhat I would want it to show would be a list of the commits that have \nchanged this line.\n\nIt looks like I can write a script to do this\n\ngit blame -L /SUBLEVEL/,+1 -M Makefile 57f8f7b6^\n6e86841d (Linus Torvalds 2008-07-28 19:40:31 -0700 3) SUBLEVEL = 27\ngit blame -L /SUBLEVEL/,+1 -M Makefile 6e86841d^\n2ddcca36 (Linus Torvalds 2008-05-03 11:59:44 -0700 3) SUBLEVEL = 26\n\netc.\n\nis there a better way to do this?\n\nDavid Lang\n"},{"id":"99204","messageId":"alpine.DEB.1.10.0901021439080.21567@asgard.lang.hm","threadId":"16973","inReplyTo":"20090102212655.GA24082@coredump.intra.peff.net","subject":"Re: how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-02T22:43:37Z","receivedAt":"2009-01-02T22:43:37Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"On Fri, 2 Jan 2009, Jeff King wrote:\n\n> On Fri, Jan 02, 2009 at 02:13:32PM -0800, david@lang.hm wrote:\n>\n>> I have a need to setup a repository where I'm storing config files, and I\n>> need to be able to search the history of a particular line, not just when\n>> the last edit of the line was (which is what I see from git blame)\n>\n> As you figured out, the \"manual\" way is to just keep reblaming from the\n> parent of each blame. Recent versions of \"git gui blame\" have a \"reblame\n> from parent\" option in the context menu which makes this a lot less\n> painful.\n\nunfortunantly I am needing to do this from the command line.\n\n>> 57f8f7b6 (Linus Torvalds 2008-10-23 20:06:52 -0700 3) SUBLEVEL = 28\n>>\n>> what I would want it to show would be a list of the commits that have\n>> changed this line.\n>\n> The tricky thing here is what is \"this line\"? Using the line number\n> isn't right, since it will change based on other content coming in and\n> out of the file. You can keep drilling down by reblaming parent commits,\n> but remember that each time you do that you are manually looking at the\n> content and saying \"Oh, this is the line I am still interested in.\" So I\n> a script would have to correlate the old version and new version of the\n> line and realize how to follow the \"interesting\" thing.\n>\n> In your case, I think you want to see any commit in Makefile which\n> changed a line with SUBLEVEL in it. Which is maybe easiest done as:\n>\n>  git log -z -p Makefile |\n>    perl -0ne 'print if /\\n[+-]SUBLEVEL/' |\n>    tr '\\0' '\\n'\n>\n> and is pretty fast. But obviously we're leveraging some content-specific\n> knowledge about what's in the Makefile.\n\nusing the line number shouldn't be _that_ hard becouse git knows what \nlines came and went from the file, so it can calculate the new line number \n(and does with the -M option)\n\nIn my case I would consider 'the same line' to be any lines in the diff \nthat were taken out when this line was put in\n\nso in the usual case (for me) of\n\n-oldline\n+newline\n\nit's a 1-1 correspondence\n\nif it's instead\n-oldline1\n-oldline2\n+newline1\n+newline2\n\nI can't know for sure which oldline corresponds to the newline, but the \nodds are very good that they are related, so if I widen the search to \ncover each of the lines I am probably good.\n\nDavid Lang\n"},{"id":"99228","messageId":"7vvdsxb9oh.fsf@gitster.siamese.dyndns.org","threadId":"16973","inReplyTo":"alpine.DEB.1.10.0901021544580.21567@asgard.lang.hm","subject":"Re: how to track the history of a line in a file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-01-02T22:54:54Z","receivedAt":"2009-01-02T22:54:54Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"david@lang.hm writes:\n\n> I was misunderstanding git blame\n\nYou may find the --porcelain output format of git-blame useful to make\nyour script safer and more robust.\n"},{"id":"99207","messageId":"alpine.DEB.1.10.0901021455390.21567@asgard.lang.hm","threadId":"16973","inReplyTo":"3ab397d0901021349h4ebae0c1g460a0c8abd4ec072@mail.gmail.com","subject":"Re: how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-02T22:58:23Z","receivedAt":"2009-01-02T22:58:23Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"On Fri, 2 Jan 2009, Jeff Whiteside wrote:\n\n>> -oldline\n>> +newline\n>>\n>> it's a 1-1 correspondence\n>>\n>> if it's instead\n>> -oldline1\n>> -oldline2\n>> +newline1\n>> +newline2\n>\n> what a neat idea.  i'm going to start malloc'ing 10,000 lines x 120\n> chars for each file i add, and edit them so that no new lines replace\n> removed lines unless it's intended that they were the same line.\n\nI don't understand your comment. that isn't nessasary to do the tracking \nthat I'm needing (you don't have to look at every line, only some of the \nlines that are in the same hunk of the patch as the line(s) you are \ninterested in)\n\nin my situation the use case is config files. in them each line is usually \nedited independantly of other lines (with stuff being added, usually, but \nnot always on the end)\n\nDavid Lang\n"},{"id":"99209","messageId":"alpine.DEB.1.10.0901021459480.21567@asgard.lang.hm","threadId":"16973","inReplyTo":"20090102212655.GA24082@coredump.intra.peff.net","subject":"Re: how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-02T23:01:20Z","receivedAt":"2009-01-02T23:01:20Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"On Fri, 2 Jan 2009, Jeff King wrote:\n\n> The tricky thing here is what is \"this line\"? Using the line number\n> isn't right, since it will change based on other content coming in and\n> out of the file. You can keep drilling down by reblaming parent commits,\n> but remember that each time you do that you are manually looking at the\n> content and saying \"Oh, this is the line I am still interested in.\" So I\n> a script would have to correlate the old version and new version of the\n> line and realize how to follow the \"interesting\" thing.\n>\n> In your case, I think you want to see any commit in Makefile which\n> changed a line with SUBLEVEL in it. Which is maybe easiest done as:\n>\n>  git log -z -p Makefile |\n>    perl -0ne 'print if /\\n[+-]SUBLEVEL/' |\n>    tr '\\0' '\\n'\n>\n> and is pretty fast. But obviously we're leveraging some content-specific\n> knowledge about what's in the Makefile.\n\nOk, I hacked togeather a quick bash script to try this\n\n#!/bin/bash\nline=`git blame -L /$1/,+1 -M $2`\nCOMMIT=`echo $line |cut -f 1 -d \" \"`\nfoundline=`echo $line |cut -f 6 -d \" \"|sed s/\")\"//`\necho \"$foundline $COMMIT\"\necho \"$line\"\nwhile [ \"$COMMIT\" != \"\" ] ;do\necho \"git blame -L $foundline,+1 -M $2 $COMMIT^\"\nline=`git blame -L $foundline,+1 -M $2 $COMMIT^`\nCOMMIT=`echo $line |cut -f 1 -d \" \"`\nfoundline=`echo $line |cut -f 6 -d \" \"|sed s/\")\"//`\necho \"$line\"\ndone\n\n\nthe problem that this has is that line 3 of $COMMIT may not be line 3 of \n$COMMIT^, and if they aren't it ends up hunting down the wrong data\n\neither that or I am not understanding the output of git blame properly \n(also very possible)\n\nDavid Lang\n"},{"id":"99223","messageId":"alpine.DEB.1.10.0901021544580.21567@asgard.lang.hm","threadId":"16973","inReplyTo":"alpine.DEB.1.10.0901021459480.21567@asgard.lang.hm","subject":"Re: how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-02T23:48:03Z","receivedAt":"2009-01-02T23:48:03Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"On Fri, 2 Jan 2009, david@lang.hm wrote:\n\n> On Fri, 2 Jan 2009, Jeff King wrote:\n>\n>> The tricky thing here is what is \"this line\"? Using the line number\n>> isn't right, since it will change based on other content coming in and\n>> out of the file. You can keep drilling down by reblaming parent commits,\n>> but remember that each time you do that you are manually looking at the\n>> content and saying \"Oh, this is the line I am still interested in.\" So I\n>> a script would have to correlate the old version and new version of the\n>> line and realize how to follow the \"interesting\" thing.\n>> \n>> In your case, I think you want to see any commit in Makefile which\n>> changed a line with SUBLEVEL in it. Which is maybe easiest done as:\n>>\n>>  git log -z -p Makefile |\n>>    perl -0ne 'print if /\\n[+-]SUBLEVEL/' |\n>>    tr '\\0' '\\n'\n>> \n>> and is pretty fast. But obviously we're leveraging some content-specific\n>> knowledge about what's in the Makefile.\n>\n> Ok, I hacked togeather a quick bash script to try this\n>\n<SNIP>\n> the problem that this has is that line 3 of $COMMIT may not be line 3 of \n> $COMMIT^, and if they aren't it ends up hunting down the wrong data\n>\n> either that or I am not understanding the output of git blame properly (also \n> very possible)\n\nI was misunderstanding git blame\n\nnew script is\n\n#!/bin/bash\nline=`git blame -n -b -l -L /$1/,+1 -M $2`\necho \"-$line\"\nfoundCOMMIT=`echo \"$line\" |cut -c -40`\nfoundline=`echo \"$line\" |cut -c 42- |cut -f 1 -d \" \"`\nwhile [ \"$foundCOMMIT\" != \"                                        \" ] ;do\n#git diff -U0 $foundCOMMIT..$foundCOMMIT^ $2\nline=`git blame -n -b -l -L $foundline,+1 -M $2 $foundCOMMIT^`\necho \"-$line\"\nfoundCOMMIT=`echo \"$line\" |cut -c -40`\nfoundline=`echo \"$line\" |cut -c 42- |cut -f 1 -d \" \"`\ndone\n\nthis seems to be working for me now.\n\nDavid Lang\n"},{"id":"99225","messageId":"alpine.DEB.1.10.0901021554581.21567@asgard.lang.hm","threadId":"16973","inReplyTo":"alpine.DEB.1.10.0901021544580.21567@asgard.lang.hm","subject":"Re: how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-02T23:56:05Z","receivedAt":"2009-01-02T23:56:05Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"On Fri, 2 Jan 2009, david@lang.hm wrote:\n\n> On Fri, 2 Jan 2009, david@lang.hm wrote:\n>\n>> On Fri, 2 Jan 2009, Jeff King wrote:\n>> \n>>> The tricky thing here is what is \"this line\"? Using the line number\n>>> isn't right, since it will change based on other content coming in and\n>>> out of the file. You can keep drilling down by reblaming parent commits,\n>>> but remember that each time you do that you are manually looking at the\n>>> content and saying \"Oh, this is the line I am still interested in.\" So I\n>>> a script would have to correlate the old version and new version of the\n>>> line and realize how to follow the \"interesting\" thing.\n>>> \n>>> In your case, I think you want to see any commit in Makefile which\n>>> changed a line with SUBLEVEL in it. Which is maybe easiest done as:\n>>>\n>>>  git log -z -p Makefile |\n>>>    perl -0ne 'print if /\\n[+-]SUBLEVEL/' |\n>>>    tr '\\0' '\\n'\n>>> \n>>> and is pretty fast. But obviously we're leveraging some content-specific\n>>> knowledge about what's in the Makefile.\n>> \n>> Ok, I hacked togeather a quick bash script to try this\n>> \n> <SNIP>\n>> the problem that this has is that line 3 of $COMMIT may not be line 3 of \n>> $COMMIT^, and if they aren't it ends up hunting down the wrong data\n>> \n>> either that or I am not understanding the output of git blame properly \n>> (also very possible)\n>\n> I was misunderstanding git blame\n>\n> new script is\n>\n> #!/bin/bash\n> line=`git blame -n -b -l -L /$1/,+1 -M $2`\n> echo \"-$line\"\n> foundCOMMIT=`echo \"$line\" |cut -c -40`\n> foundline=`echo \"$line\" |cut -c 42- |cut -f 1 -d \" \"`\n> while [ \"$foundCOMMIT\" != \"                                        \" ] ;do\n> #git diff -U0 $foundCOMMIT..$foundCOMMIT^ $2\n> line=`git blame -n -b -l -L $foundline,+1 -M $2 $foundCOMMIT^`\n> echo \"-$line\"\n> foundCOMMIT=`echo \"$line\" |cut -c -40`\n> foundline=`echo \"$line\" |cut -c 42- |cut -f 1 -d \" \"`\n> done\n>\n> this seems to be working for me now.\n\nnot quite, it works as long as the line doesn't move in the commit where \nit changes.\n\nDavid Lang\n"},{"id":"99234","messageId":"200901030107.07228.trast@student.ethz.ch","threadId":"16973","inReplyTo":"alpine.DEB.1.10.0901021658330.21567@asgard.lang.hm","subject":"Re: how to track the history of a line in a file","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-03T00:07:03Z","receivedAt":"2009-01-03T00:07:03Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"david@lang.hm wrote:\n> On Fri, 2 Jan 2009, Junio C Hamano wrote:\n> > You may find the --porcelain output format of git-blame useful to make\n> > your script safer and more robust.\n> \n> where is this output defined? I can look at it and understand it, but I \n> don't know what is guarenteeded to exist, what will be on a specific line, \n> and what may vanish on me.\n\nman git-blame | less -p PORCELAIN\\ FORMAT\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n\n"},{"id":"99233","messageId":"alpine.DEB.1.10.0901021658330.21567@asgard.lang.hm","threadId":"16973","inReplyTo":"7vvdsxb9oh.fsf@gitster.siamese.dyndns.org","subject":"Re: how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-03T00:59:36Z","receivedAt":"2009-01-03T00:59:36Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"On Fri, 2 Jan 2009, Junio C Hamano wrote:\n\n> david@lang.hm writes:\n>\n>> I was misunderstanding git blame\n>\n> You may find the --porcelain output format of git-blame useful to make\n> your script safer and more robust.\n\nwhere is this output defined? I can look at it and understand it, but I \ndon't know what is guarenteeded to exist, what will be on a specific line, \nand what may vanish on me.\n\nDavid Lang\n"},{"id":"99236","messageId":"alpine.DEB.1.10.0901021805100.21567@asgard.lang.hm","threadId":"16973","inReplyTo":"200901030107.07228.trast@student.ethz.ch","subject":"Re: how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-03T02:05:45Z","receivedAt":"2009-01-03T02:05:45Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"On Sat, 3 Jan 2009, Thomas Rast wrote:\n\n> david@lang.hm wrote:\n>> On Fri, 2 Jan 2009, Junio C Hamano wrote:\n>>> You may find the --porcelain output format of git-blame useful to make\n>>> your script safer and more robust.\n>>\n>> where is this output defined? I can look at it and understand it, but I\n>> don't know what is guarenteeded to exist, what will be on a specific line,\n>> and what may vanish on me.\n>\n> man git-blame | less -p PORCELAIN\\ FORMAT\n\nthanks,\n\nam I missing something else or will git blame with a regex only return \ninfo on the first line it matches?\n\nDavid Lang\n"},{"id":"99238","messageId":"alpine.DEB.1.10.0901022020410.21567@asgard.lang.hm","threadId":"16973","inReplyTo":"alpine.DEB.1.10.0901021554581.21567@asgard.lang.hm","subject":"Re: how to track the history of a line in a file","fromName":"","fromEmail":"david@lang.hm","sentAt":"2009-01-03T04:25:58Z","receivedAt":"2009-01-03T04:25:58Z","isPatch":false,"sender":{"key":"david@lang.hm","avatar":null},"body":"On Fri, 2 Jan 2009, david@lang.hm wrote:\n\n> On Fri, 2 Jan 2009, david@lang.hm wrote:\n>\n>> On Fri, 2 Jan 2009, david@lang.hm wrote:\n>> \n>>> On Fri, 2 Jan 2009, Jeff King wrote:\n>>> \n>>>> The tricky thing here is what is \"this line\"? Using the line number\n>>>> isn't right, since it will change based on other content coming in and\n>>>> out of the file. You can keep drilling down by reblaming parent commits,\n>>>> but remember that each time you do that you are manually looking at the\n>>>> content and saying \"Oh, this is the line I am still interested in.\" So I\n>>>> a script would have to correlate the old version and new version of the\n>>>> line and realize how to follow the \"interesting\" thing.\n>>>> \n>>>> In your case, I think you want to see any commit in Makefile which\n>>>> changed a line with SUBLEVEL in it. Which is maybe easiest done as:\n>>>>\n>>>>  git log -z -p Makefile |\n>>>>    perl -0ne 'print if /\\n[+-]SUBLEVEL/' |\n>>>>    tr '\\0' '\\n'\n>>>> \n>>>> and is pretty fast. But obviously we're leveraging some content-specific\n>>>> knowledge about what's in the Makefile.\n>>> \n>>> Ok, I hacked togeather a quick bash script to try this\n>>> \n>> <SNIP>\n>>> the problem that this has is that line 3 of $COMMIT may not be line 3 of \n>>> $COMMIT^, and if they aren't it ends up hunting down the wrong data\n\nsolving this problem was a bit more work than expected. I ended up \ninvoking git diff to do the step back and find what lines were replaced by \nthe one I care about.\n\nthis still can run into problems if the lines that are examined are not \nunique (git blame only finds the first match)\n\n\n\n#!/usr/bin/perl\n# program to trace the history of a line through a git repository\n#\n# useage findlines pattern filespec\n#\n# finds all occurances of the pattern in the file and then uses git blame\n#  to find where those lines were introduced. It then takes a step back \nand\n#  looks at what the line replaced (if anything) and does a git blame on \nthose\n#  lines as well\n#\n# written by David Lang and released under GPLv2\n#\n$target = shift @ARGV;\n$file = shift @ARGV;\nopen($infile,\"<$file\");\n$linecount=0;\n# find all lines in the file that match the target pattern\n# we have been provided. add them to a stack of items to research\nwhile(<$infile>){\n   $linecount++;\n   if ($_ =~ /$target/) {\n     $items[++$#items]{line} = $linecount;\n     $items[$#items]{tree} = \"HEAD\";\n     chomp;\n     $items[$#items]{target} = $_;\n   }\n}\n# go through all the items and research them in turn\n#  (note that more items may be added to the list while inside this loop)\nfor ($i=0;$i<=$#items;$i++) {\n# do a git blame to find where the lines came from\n   $result = `git blame -b -l -L \"$items[$i]{line}\",+1 -M  $file \n$items[$i]{tree}` ;\n   print \"in \".$items[$i]{tree}.\" found:\\n$result\";\n   $commit=substr($result,0,40);\n   # if this is not the root commit,\n   #  do a diff to find what lines may have been replaced by the line we \nare looking for\n   if($commit ne \"                                        \"){\n     $diff=`git diff -U0 $commit^..$commit $file`;\n     @lines=split(\"\\n\",$diff);\n     #strip the first four lines from the diff (as they just talk about the \nfile)\n     shift(@lines);\n     shift(@lines);\n     shift(@lines);\n     shift(@lines);\n     $match=0;\n     $hunk='';\n     # find what hunk of the diff introduced the lines we are looking for,\n     #  add the lines that they replaced to the list of items to examine\n     foreach(@lines){\n       if ($_ =~ /^\\@\\@/ ) {\n         if ($match) {\n           process_hunk();\n         } else {\n           $hunk = '';\n         };\n       } else {\n         $hunk .= $_.\"\\n\";\n         if ($_ =~ /$items[$i]{target}/) {\n           $match = 1;\n         }\n       }\n     }\n     if ($match) {\n       process_hunk();\n     }\n   }\n}\nsub process_hunk(){\n   # find lines in the hunk of diff that are being replaced\n   foreach (split(\"\\n\",$hunk)){\n     if ($_ =~ /^-/ ){\n       # for now queue the line contents for further processing.\n       #   this really should be the line number becouse otherwise\n       #   git blame will use the first match it finds. since we are\n       # matching the entire line this is less of a problem than it could \nbe.\n       $items[++$#items]{line} = \"/\".substr($_,1).\"/\";\n       $items[$#items]{target} = substr($_,1);\n       $items[$#items]{tree} = \"$commit^\";\n     }\n   }\n}\n"},{"id":"99479","messageId":"87d4f01lmt.fsf@gollum.intra.norang.ca","threadId":"16973","inReplyTo":"alpine.DEB.1.10.0901021405460.21567@asgard.lang.hm","subject":"Re: how to track the history of a line in a file","fromName":"Bernt Hansen","fromEmail":"bernt@norang.ca","sentAt":"2009-01-06T15:48:10Z","receivedAt":"2009-01-06T15:48:10Z","isPatch":false,"sender":{"key":"bernt@norang.ca","avatar":null},"body":"david@lang.hm writes:\n\n> I have a need to setup a repository where I'm storing config files,\n> and I need to be able to search the history of a particular line, not\n> just when the last edit of the line was (which is what I see from git\n> blame)\n>\n> I'm not seeing a obvious way to do this, am I missing something or\n> does it need a non-obvious approach?\n>\n> for example, if I do\n>\n> git blame -L /SUBLEVEL/,+1 -M Makefile\n>\n> on the linux kernel it currently shows\n>\n> 57f8f7b6 (Linus Torvalds 2008-10-23 20:06:52 -0700 3) SUBLEVEL = 28\n>\n> what I would want it to show would be a list of the commits that have\n> changed this line.\n>\n> It looks like I can write a script to do this\n>\n> git blame -L /SUBLEVEL/,+1 -M Makefile 57f8f7b6^\n> 6e86841d (Linus Torvalds 2008-07-28 19:40:31 -0700 3) SUBLEVEL = 27\n> git blame -L /SUBLEVEL/,+1 -M Makefile 6e86841d^\n> 2ddcca36 (Linus Torvalds 2008-05-03 11:59:44 -0700 3) SUBLEVEL = 26\n>\n> etc.\n>\n> is there a better way to do this?\n>\n> David Lang\n\nI think you need a script to do what you want.  I think this works...\n\nSave the following script in ~/bin/git-rblame.sh, make it executable,\nand then create a global git alias for it as follows:\n\n$ git config --global alias.rblame '!~/bin/git-rblame.sh $*'\n\nThen you can just use\n\n$ git rblame -L /SUBLEVEL/,+1 -M Makefile\n6e86841d (Linus Torvalds 2008-07-28 19:40:31 -0700 3) SUBLEVEL = 27\n2ddcca36 (Linus Torvalds 2008-05-03 11:59:44 -0700 3) SUBLEVEL = 26\n...\n4c91aedb (Linus Torvalds 2005-06-28 22:57:29 -0700 3) SUBLEVEL = 13\n^1da177e (Linus Torvalds 2005-04-16 15:20:36 -0700 3) SUBLEVEL = 12\n\n------cut here ------ !/bin/git-rblame.sh ---\n#!/bin/sh\nPARAMS=\"$*\"\nLINE=$(git blame $PARAMS)\nwhile test $? == 0\ndo\n    echo $LINE\n    COMMIT=\"${LINE:0:8}^\"\n    LINE=$(git blame $PARAMS $COMMIT 2>/dev/null)\ndone\n------cut here ------------------------------\n\nCheers,\nBernt\n"},{"id":"99480","messageId":"20090106160814.GI21154@genesis.frugalware.org","threadId":"16973","inReplyTo":"87d4f01lmt.fsf@gollum.intra.norang.ca","subject":"Re: how to track the history of a line in a file","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2009-01-06T16:08:14Z","receivedAt":"2009-01-06T16:08:14Z","isPatch":false,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Tue, Jan 06, 2009 at 10:48:10AM -0500, Bernt Hansen <bernt@norang.ca> wrote:\n> Save the following script in ~/bin/git-rblame.sh, make it executable,\n> and then create a global git alias for it as follows:\n> \n> $ git config --global alias.rblame '!~/bin/git-rblame.sh $*'\n\nGiven that you have ~/bin in PATH, just name the script ~/bin/git-rblame\nand you won't even have to define an alias on each machine. ;-)\n"},{"id":"99482","messageId":"878wpo1k2p.fsf@gollum.intra.norang.ca","threadId":"16973","inReplyTo":"20090106160814.GI21154@genesis.frugalware.org","subject":"Re: how to track the history of a line in a file","fromName":"Bernt Hansen","fromEmail":"bernt@norang.ca","sentAt":"2009-01-06T16:21:50Z","receivedAt":"2009-01-06T16:21:50Z","isPatch":false,"sender":{"key":"bernt@norang.ca","avatar":null},"body":"Miklos Vajna <vmiklos@frugalware.org> writes:\n\n> On Tue, Jan 06, 2009 at 10:48:10AM -0500, Bernt Hansen <bernt@norang.ca> wrote:\n>> Save the following script in ~/bin/git-rblame.sh, make it executable,\n>> and then create a global git alias for it as follows:\n>> \n>> $ git config --global alias.rblame '!~/bin/git-rblame.sh $*'\n>\n> Given that you have ~/bin in PATH, just name the script ~/bin/git-rblame\n> and you won't even have to define an alias on each machine. ;-)\n\nYes but I don't want to use 'git-rblame' as the command since I've\nbroken my habit of using the dashed versions of commands. 'git rblame'\njust feels better to me.\n\nNow I probably should have named the script something that won't ever\nclash with possible future git commands (like my-git-rblame.sh or\nsomething) but since it's in my ~/bin I'll just deal with that if it\never happens in the future :)\n\n-Bernt\n"},{"id":"99484","messageId":"874p0c1jqx.fsf@gollum.intra.norang.ca","threadId":"16973","inReplyTo":"878wpo1k2p.fsf@gollum.intra.norang.ca","subject":"Re: how to track the history of a line in a file","fromName":"Bernt Hansen","fromEmail":"bernt@norang.ca","sentAt":"2009-01-06T16:28:54Z","receivedAt":"2009-01-06T16:28:54Z","isPatch":false,"sender":{"key":"bernt@norang.ca","avatar":null},"body":"Bernt Hansen <bernt@norang.ca> writes:\n\n> Miklos Vajna <vmiklos@frugalware.org> writes:\n>\n>> On Tue, Jan 06, 2009 at 10:48:10AM -0500, Bernt Hansen <bernt@norang.ca> wrote:\n>>> Save the following script in ~/bin/git-rblame.sh, make it executable,\n>>> and then create a global git alias for it as follows:\n>>> \n>>> $ git config --global alias.rblame '!~/bin/git-rblame.sh $*'\n>>\n>> Given that you have ~/bin in PATH, just name the script ~/bin/git-rblame\n>> and you won't even have to define an alias on each machine. ;-)\n>\n> Yes but I don't want to use 'git-rblame' as the command since I've\n> broken my habit of using the dashed versions of commands. 'git rblame'\n> just feels better to me.\n>\n> Now I probably should have named the script something that won't ever\n> clash with possible future git commands (like my-git-rblame.sh or\n> something) but since it's in my ~/bin I'll just deal with that if it\n> ever happens in the future :)\n\nOops. That actually does do what I want.  Thanks for pointing that out\nMiklos!\n\n(sorry for replying to my own post - next time I'll try it first before\n I post :)\n\n-Bernt\n"}]}