2

When we do a git diff, it very well shows us the diff alongwith the line numbers and the function in which the lines fall:

@@ -614,10 +636,10 @@ def write_my_name(name):
                         .
                         .
-                        len(name),
+                        len(getattr(resume, name)),

When I do a git add is it also storing these function references?

Also to consider, we have git log -L<func_name>:file_name, not sure how that works. My guess is reference to function is being stored?

If the answer to above questions is yes. Is it possible to undo changes in a particular function? I am unable to find a switch in reset.

Would like to consider both scenarios, changes not staged and changes staged for commit.

Thanks for taking time to read this.

unixia
  • 4,102
  • 1
  • 19
  • 23
  • 2
    My guess is that when you as for -L, git is analyzing the file "on the fly". I'm sure that git does not parse the file as it is being saved into the objects DB. – eftshift0 Jan 09 '19 at 15:53
  • Although I find this question interesting, I think it's off topic, because it's not about programming, even in the sense of solving a problem with a version control tool. OTOH, I'm pretty sure @eftshift0 is right. I remember reading something about how `git diff --function-context` worked that mentioned that it was calculated when the diff was calculated. – jpaugh Jan 09 '19 at 16:13
  • VTC because it's a question about how a particular (devops) program works internally, not a problem with using it. I don't think that's on-topic on Super User, either. – jpaugh Jan 09 '19 at 16:16

1 Answers1

2

When we do a git diff, it very well shows us the diff along with the line numbers and the function in which the lines fall ...

Yes, but it's all based on a trick. :-)

First, git diff finds an edit sequence (see links in my answer to How does git generate diff in files?). Then it uses the edit sequence to claim that this is what you did, even if that's not actually what you did—it's just a change that will accomplish the same thing, if applied to the same input.

Then, given that Git is presenting a change as affectling lines M-through-N, Git does a regular expression search through lines whose number is less than or equal to M (essentially, tests each line, starting at M, moving towards line 1). These regular expressions are built in to the Git source. You can set your own, as documented (somewhat) in the gitattributes documentation (search for "defining a custom hunk-header"). If the expression matches the line, the text is included after the @@.

When I do a git add is it also storing these function references?

No: git add merely copies the work-tree version of the file into the index, replacing whatever version was in the index before. Note, however, that git add -p runs a Perl script. That script does something very different; read it to see precisely what it does, and how it does it.

Also to consider, we have git log -L<func_name>:file_name, not sure how that works.

That, too, uses the regular expression match trick to find functions within files.

Is it possible to undo changes in a particular function? I am unable to find a switch in reset.

It currently is not. To do that, you could modify the Perl script, because git reset -p also invokes this same perl script. Unfortunately, the built-in regular expressions are not exported—so you could read the user's configuration to check for custom regular expressions, but otherwise you would have to re-code the built in regular expressions into the Perl script.

It might be reasonable to request that the Git folks enhance the userdiff code to be able to, as a plumbing command or via git config --get, expose the built in regular expressions. Of course, you should also be aware that these regular expressions are approximations for what real parsers do, in general. (C-like languages are particularly problematic because of macro substitutions—you have to run the entire input through a proper preprocessor before you can really find tokens.)

Note that the installed version of the Perl script is called git-add--interactive and lives in the "git-core" directory printed out by git --exec-path. Since it is a script, it's pretty easy to modify. It would probably be wisest, though, to copy that script to a new name in your own scripts directory, e.g., named git-my-fancier-script, and then invoke it as git my-fancier-script.

torek
  • 448,244
  • 59
  • 642
  • 775