【问题标题】:Git - how do I view the change history of a method/function?Git - 如何查看方法/函数的更改历史记录?
【发布时间】:2011-06-14 11:06:13
【问题描述】:

所以我找到了关于如何查看文件更改历史的问题,但是这个特定文件的更改历史很大,我真的只对特定方法的更改感兴趣。那么是否可以仅查看该特定方法的更改历史记录?

我知道这需要 git 来分析代码,并且不同语言的分析会有所不同,但是方法/函数声明在大多数语言中看起来非常相似,所以我想也许有人已经实现了这个功能。

我目前使用的语言是 Objective-C,我目前使用的 SCM 是 git,但我很想知道这个功能是否适用于任何 SCM/语言。

【问题讨论】:

  • 我在 Git GSoG 提案中看到了这样的功能。
  • 这就是你说的提案吗? lists-archives.org/git/…
  • @lpapp 这里的问题是 10 个月前提出的,另一个问题应该被标记为这个问题的骗子(如果他们完全是骗子的话)。
  • @lpapp 这是两个完全不同的问题。您可以编写一个脚本,将函数名称解析为一系列行,然后使用该问题中的技术来获取这些行的历史记录,但它本身并不能回答这个问题。

标签: objective-c git function methods history


【解决方案1】:
  1. 使用git log -L :<funcname>:<file> 显示函数历史记录,如eckes's answergit doc 所示

    如果没有显示任何内容,请参阅Defining a custom hunk-header*.java diff=java 之类的内容添加到.gitattributes 文件以支持您的语言。

  2. 使用git log commit1..commit2 -L :functionName:filePath显示提交之间的函数历史记录

  3. git log -L :sum\(double:filepath显示重载函数历史(可能有许多同名但参数不同的函数)

【讨论】:

    【解决方案2】:

    正确的方法是使用git log -L :function:path/to/file,如eckes answer中所述。

    但是另外,如果你的函数很长,你可能只想看到各种提交引入的更改,而不是整个函数行,包括未修改的,每个提交可能只涉及这些行中的一个。就像普通的diff 一样。

    通常git log 可以查看与-p 的差异,但这不适用于-L。 因此,您必须 grep git log -L 仅显示涉及的行和提交/文件标题以将它们上下文化。这里的诀窍是只匹配终端彩色线,添加--color 开关和正则表达式。最后:

    git log -L :function:path/to/file --color | grep --color=never -E -e "^(^[\[[0-9;]*[a-zA-Z])+" -3
    

    注意^[ 应该是实际的,字面的^[。您可以通过在bash中按^V^[来键入它们,即Ctrl + V, Ctrl + [ .参考here

    最后一个-3 开关,允许在每个匹配的行之前和之后打印 3 行输出上下文。您可能需要根据需要对其进行调整。

    【讨论】:

      【解决方案3】:

      最新版本的git log 学习了-L 参数的特殊形式:

      -L ::

      跟踪"<start>,<end>"(或函数名正则表达式<funcname>)在<file> 中给出的行范围的演变。您不得提供任何路径规范限制器。这目前仅限于从单个修订开始的步行,即,您只能给出零个或一个积极的修订参数。您可以多次指定此选项。
      ...
      如果“:<funcname>” 代替<start><end>,它是一个正则表达式,表示从匹配<funcname> 的第一个funcname 行到下一个funcname 行的范围。 “:<funcname>” 从前一个 -L 范围的末尾搜索(如果有),否则从文件开头搜索。 “^:<funcname>” 从文件开头搜索。

      换句话说:如果你让 Git 给git log -L :myfunction:path/to/myfile.c,它现在会很高兴地打印那个函数的更改历史。

      【讨论】:

      • 这可能适用于开箱即用的objective-c,但如果您正在为其他语言(例如Python、Ruby等)执行此操作,您可能需要在.gitattributes文件中添加适当的配置命令 git 识别该语言的函数/方法声明。对于 python 使用 *.py diff=python,对于 ruby​​ 使用 *.rb diff=ruby
      • git如何跟踪函数?
      • @nn0p 我假设拥有多种语言的语法知识,因此知道如何隔离一个函数并跟踪她的变化。
      • 扩展@samaspin 的评论,对于其他语言你可以参考这里的文档:git-scm.com/docs/gitattributes#_generating_diff_text
      • 这不适用于 Scala 和 Java 甚至 C 等使用嵌套花括号的语言(正则表达式通常无法处理),甚至开始,结束形式也不起作用当函数在文件中移动并在同一个提交中修改时。
      【解决方案4】:

      git log 有一个选项“-G”可用于查找所有差异。

      -G 查找添加或删除的行与 给定<regex>

      只需给它一个您关心的函数名称的适当正则表达式。例如,

      $ git log --oneline -G'^int commit_tree'
      40d52ff make commit_tree a library function
      81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory
      7b9c0a6 git-commit-tree: make it usable from other builtins
      

      【讨论】:

      • 我没有运行该命令,但在我看来,该命令只会显示触及与正则表达式匹配的行的提交,而不是整个方法/函数。
      • 如果需要更多上下文,可以将--oneline替换为-p
      • 但是如果对方法进行了 20 行的更改呢?
      • +1。对我来说,最佳答案有效,但只显示了最近的提交。可能是由于变基或函数移动了几次,不确定。通过搜索实际的代码行而不是它所在的函数(尽管是单行),这个答案让我可以轻松地发现我正在寻找的提交。谢天谢地,我通常会写有用的提交信息!
      【解决方案5】:

      使用git gui blame 很难在脚本中使用,虽然git log -Ggit log --pickaxe 可以分别显示方法定义何时出现或消失,但我还没有找到任何方法让它们列出所有更改制作到您方法的主体

      但是,您可以使用gitattributestextconv 属性拼凑出一个解决方案来实现这一点。尽管这些功能最初旨在帮助您处理二进制文件,但它们在这里也同样适用。

      关键是在执行任何差异操作之前,让 Git 从文件中删除除您感兴趣的行之外的所有行。那么git loggit diff等只会看到你感兴趣的区域。

      这是我在另一种语言中所做的工作的大纲;您可以根据自己的需要进行调整。

      • 编写一个简短的 shell 脚本(或其他程序),它接受一个参数 - 源文件的名称 - 并且只输出该文件中有趣的部分(如果没有一个有趣的部分,则不输出)。例如,您可以按如下方式使用sed

        #!/bin/sh
        sed -n -e '/^int my_func(/,/^}/ p' "$1"
        
      • 为您的新脚本定义一个 Git textconv 过滤器。 (有关详细信息,请参阅 gitattributes 手册页。)过滤器的名称和命令的位置可以是任何您喜欢的。

        $ git config diff.my_filter.textconv /path/to/my_script
        
      • 在计算相关文件的差异之前告诉 Git 使用该过滤器。

        $ echo "my_file diff=my_filter" >> .gitattributes
        
      • 现在,如果您使用-G.(注意.)列出在应用过滤器时产生可见更改的所有提交,您将拥有您感兴趣的那些提交。任何其他选项使用 Git 的 diff 例程,例如 --patch,也会得到这个受限视图。

        $ git log -G. --patch my_file
        
      • 瞧!

      您可能想做的一个有用的改进是让您的过滤器脚本将方法名称作为其第一个参数(并将文件作为其第二个参数)。这使您只需调用git config 即可指定感兴趣的新方法,而不必编辑脚本。例如,你可能会说:

      $ git config diff.my_filter.textconv "/path/to/my_command other_func"
      

      当然,过滤器脚本可以做任何你喜欢的事情,接受更多的参数,或者其他什么:除了我在这里展示的内容之外,还有很多灵活性。

      【讨论】:

      • take more than one 参数对我不起作用,但是将函数名放在辛苦的工作中很好,这真的很棒!
      • 太棒了,虽然我想知道在许多不同的方法之间切换有多方便。另外,你知道有什么程序可以提取整个类 C 函数吗?
      【解决方案6】:

      您可以做的最接近的事情是确定您的函数在文件中的位置(例如,假设您的函数 i_am_buggyfoo/bar.c 的第 241-263 行),然后运行以下内容:

      git log -p -L 200,300:foo/bar.c
      

      这将打开更少(或等效的寻呼机)。现在您可以输入/i_am_buggy(或您的寻呼机等效项)并开始逐步完成更改。

      这甚至可能有效,具体取决于您的代码风格:

      git log -p -L /int i_am_buggy\(/,+30:foo/bar.c
      

      这将搜索从该正则表达式的第一次命中(理想情况下是您的函数声明)限制到之后的三十行。 end 参数也可以是一个正则表达式,尽管用正则表达式检测 that 是一个更不确定的命题。

      【讨论】:

      • 甜蜜!仅供参考,这是 Git v1.8.4 中的新功能。 (我想我应该升级。)虽然更精确的解决方案会很好......就像有人编写 Paul Whittaker 的答案一样。
      • @GregPrice Apparently the edges of the search can even be regular expressions,所以你至少可以有一个或多或少精确的起点。
      • 哦,哇。事实上:与其编写自己的正则表达式,不如说 -L ":int myfunc:foo/bar.c" 并限制为具有该名称的函数。这太棒了——感谢您的指点!现在,如果只有功能检测更可靠一点...
      【解决方案7】:

      git blame 显示最后更改文件每一行的人;您可以指定要检查的行,以避免在函数之外获取行的历史记录。

      【讨论】:

      • 使用git gui blame,您可以浏览旧版本。
      猜你喜欢
      • 1970-01-01
      • 2010-12-19
      • 2018-11-01
      • 2012-08-10
      • 2018-04-19
      • 2010-09-21
      • 2016-10-20
      • 2011-04-20
      相关资源
      最近更新 更多