【问题标题】:Git diff with line numbers (Git log with line numbers)带有行号的 Git diff(带有行号的 Git 日志)
【发布时间】:2014-08-18 18:33:51
【问题描述】:

当我执行git diffgit log -p 时,如何获取与输出内联的源文件的行号?

我尝试查找 man git-diff | grep "line numbers" 并尝试使用谷歌搜索但很快一无所获。

【问题讨论】:

    标签: git line-numbers


    【解决方案1】:

    git diff 无法获得人类可读的行号

    目前没有任何选项可以让行号垂直显示在带有git diff 的一侧。

    统一差异格式

    该信息可在 (c)hunk 标头中获得,但对于 diff 中的每个更改,它只是在 unified-diff format

    @@ -start,count +start,count @@
    

    文件的原始状态用-表示,新状态用+表示(不代表hunk header中的增删改查。start表示每个文件的起始行号文件的版本,count 表示包含多少行,从起点开始。

    示例

    diff --git a/osx/.gitconfig b/osx/.gitconfig
    index 4fd8f04..fcd220c 100644
    --- a/osx/.gitconfig
    +++ b/osx/.gitconfig
    @@ -11,7 +11,7 @@ <== HERE!
     [color "branch"]
            upstream = cyan
     [color "diff"]
    -       meta = yellow
    +       meta = cyan
            plain = white dim
            old = red bold
            new = green bold
    

    大块头

    @@ -11,7 +11,7 @@
    

    表示之前版本的文件从第 11 行开始,包括 7 行:

    11  [color "branch"]
    12         upstream = cyan
    13  [color "diff"]
    14 -       meta = yellow
    14 +       meta = cyan
    15         plain = white dim
    16         old = red bold
    17         new = green bold
    

    而下一个版本的文件也是从第 11 行开始,也包括 7 行。

    Unified-diff 格式不适合人类消费

    正如您可能知道的那样,统一差异格式并不容易计算出行号(至少如果您不是机器)。如果你真的想要你可以阅读的行号,你需要使用一个可以为你显示它们的差异工具。

    补充阅读

    【讨论】:

    • 这是一个 grep 只提取修改文件中的行号,例如用于过滤检查样式报告git diff --unified=0 | grep -Po '^\+\+\+ ./\K.*|^@@ -[0-9]+(,[0-9]+)? \+\K[0-9]+(,[0-9]+)?(?= @@)'
    • @JakubBochenski 的评论很好地解决了我的问题。
    • 这只有在指定--unified=0-U0 时才真正有用。
    • 我刚刚完成了git diffn,这是git diff 的直接替换(包装器),它显示了行号,并且与git diff 的所有用法和选项完全兼容:stackoverflow.com/questions/24455377/…跨度>
    • @JakubBochenski grep 的 -Po 标志是什么?
    【解决方案2】:

    这是另一个解决方案,扩展了 Andy Talkowski 的代码。

    纯文本:

    git diff | gawk '
      match($0,"^@@ -([0-9]+),([0-9]+) [+]([0-9]+),([0-9]+) @@",a){
        left=a[1]
        ll=length(a[2])
        right=a[3]
        rl=length(a[4])
      }
      /^(---|\+\+\+|[^-+ ])/{ print;next }
      { line=substr($0,2) }
      /^[-]/{ printf "-%"ll"s %"rl"s:%s\n",left++,""     ,line;next }
      /^[+]/{ printf "+%"ll"s %"rl"s:%s\n",""    ,right++,line;next }
            { printf " %"ll"s %"rl"s:%s\n",left++,right++,line }
    '
    

    这是示例输出:

    diff --git a/.bashrc b/.bashrc
    index b2b6d5f..51e0b8c 100644
    --- a/.bashrc
    +++ b/.bashrc
    @@ -1,8 +1,26 @@
     1  1:#!/bin/bash
    -2   :# ~/.bashrc: executed by bash(1) for non-login shells.
    -3   :# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
    -4   :# for examples
    +   2:# 2020-03-06 14:54:25 From R S:
    +   3:##export PATH="/usr/local/opt/ed/libexec/gnubin:$PATH"
    +   4:#export PATH="/usr/local/opt/findutils/libexec/gnubin:$PATH"
    +   5:#export PATH="/usr/local/opt/gnu-indent/libexec/gnubin:$PATH"
    +   6:#export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
    +   7:#export PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"
    +   8:#export PATH="/usr/local/opt/gnu-which/libexec/gnubin:$PATH"
     5  9:
    +  10:export PATH="/usr/local/opt/sqlite/bin:$PATH"
    +  11:export PATH="/usr/local/opt/file-formula/bin:$PATH"
    +  12:export PATH="/usr/local/opt/unzip/bin:$PATH"
    +  13:export PATH="/usr/local/opt/openssl/bin:$PATH"
    +  14:export PATH="/usr/local/opt/wireshark/bin:$PATH"
    +  15:
    +  16:
    +  17:#export PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"
    
    

    【讨论】:

    • 我注意到它破坏了代码的对齐(缩进),而原生 git diff 小心地保持对齐。这段代码现在在我头上,所以你愿意修复它吗?换句话说,当一行显示+240:+ 而下一行显示(241,257): 时,您需要在顶行添加一些额外的空格,以使其代码与下一行的代码保持正确的对齐和缩进。也许这可以通过打印轻松完成?
    • ...我的意思是printf
    • 没关系;我得到了它!我刚刚完成git diffn。见这里:stackoverflow.com/a/61997003/4561887。感谢@PFudd,您的回答。我研究它并用它来学习,然后从头开始写git diffn。曾经formatted so I could read your code(感谢@EdMorton),我能够从中学到一些对我有帮助的好东西。
    • 对不起,我写这篇文章已经 5 年多了,这些天我会做得更漂亮。 :-)
    【解决方案3】:

    自 2020 年 5 月 24 日起,您现在可以为此目的使用第三方工具 git diffn(完全披露:我写的)。它是git diff 的轻量级包装器,使用awk 基于模式/动作的编程语言编写。这是运行git diffn 的示例输出。冒号 (:) 都保持白色是有意的,作为一个视觉队列,它们是从左到右的分隔符。 (如果你不喜欢,可以很容易地在代码中更改)。

    1/3:它是什么?

    来自top of git-diffn.sh

    描述:

    git-diffn.sh

    1. git diff 的直接替代品,它还显示了“数字”行!像git diff 一样完全使用它,除了你会看到这些漂亮的行号来帮助你理解 您的更改。

    2. 因为它只是git diff 的轻量级基于 awk 语言的包装器,它接受git diff 接受的所有选项和参数。例子:

    3. git diffn HEAD~

    4. git diffn HEAD~3..HEAD~2

    5. 适用于您的任何git diff 颜色设置,即使您使用的是自定义颜色

    6. 在此处查看我的答案,了解如何设置自定义差异颜色,以及查看来自git diffn:How do you customize the color of the diff header in git diff? 的自定义颜色输出的屏幕截图

    7. 以下是我上面回答中的一些示例git config 命令,用于设置自定义git diff 颜色和属性(文本格式):

         git config --global color.diff.meta "blue"
         git config --global color.diff.old "black red strike"
         git config --global color.diff.new "black green italic"
         git config --global color.diff.context "yellow bold"
      
    8. git diffn中,默认开启颜色输出;如果要禁用输出颜色,则必须使用--no-color--color=never。有关详细信息,请参阅man git diff。例子:

       git diffn --color=never HEAD~
       git diffn --no-color HEAD~3..HEAD~2
      

    2/3:安装

    1. Windows(未经测试):这可能在 Git for Windows 附带的 bash 终端内工作,但未经测试。为 Windows 安装 Git。打开它附带的 bash 终端,并尝试按照以下说明进行操作。我需要一些测试人员在 Git for Windows 中进行测试。请在此处查看并回答:https://github.com/git-for-windows/git/issues/2635
    2. Mac(未经测试):使用终端并按照以下说明进行操作。您可能需要安装gawk。如果是这样,请尝试thisbrew install gawk
    3. Linux(在 Ubuntu 18.04 上测试并且运行良好):按照下面的终端说明进行操作。

    选项 1(我的建议):下载整个 repo,然后创建一个指向该程序的符号链接,以便您可以随时通过 repo 中的git pull 轻松接收更新。

    首先,cd 到你想安装它的任何地方。然后运行:

    git clone https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles.git
    cd eRCaGuy_dotfiles/useful_scripts
    mkdir -p ~/bin
    ln -si "${PWD}/git-diffn.sh" ~/bin/git-diffn
    

    完成!现在只需执行下面的最后一步!

    选项 2(对于只需要 1 个文件的用户):一次只下载一个文件。

    mkdir -p ~/bin
    cd ~/bin
    wget https://raw.githubusercontent.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/master/useful_scripts/git-diffn.sh
    chmod +x git-diffn.sh
    mv git-diffn.sh git-diffn
    

    完成!现在只需执行下面的最后一步!

    最后一步:

    现在关闭并重新打开您的终端,或使用. ~/.bashrc 重新获取它,您就完成了!

    git diffn 现在将完全替代git diff

    这是一个演示:

    3/3:git diffn的演示:

    创建这个文件:

    hello_world.c:

    #include <stdio.h>
    
    int main()
    {
        printf("Hello World\n");
    
        return 0;
    }
    

    提交:

    git add hello_world.c
    git commit -m "add hello_world.c"
    

    把它改成这个并保存文件:

    hello_world.c:

    // Basic hello world example
    
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
        printf("Hello Gabriel\n");
        
        int i = 700;
        printf("i = %i\n", i);
        return 0;
    }
    

    现在运行:

    git diff
    

    这是git diff 的输出,用于比较目的:

    $ git diff
    diff --git a/hello_world.c b/hello_world.c
    index e01704a..e971b73 100644
    --- a/hello_world.c
    +++ b/hello_world.c
    @@ -1,8 +1,12 @@
    +// Basic hello world example
    +
     #include <stdio.h>
     
    -int main()
    +int main(int argc, char *argv[])
     {
    -    printf("Hello World\n");
    -
    +    printf("Hello Gabriel\n");
    +    
    +    int i = 700;
    +    printf("i = %i\n", i);
         return 0;
    -}
    \ No newline at end of file
    +}
    

    以及显示颜色的屏幕截图。请注意,红色突出显示的部分只是显示可以删除的空白(在本例中为空格):

    现在这是git diffn 的输出。请注意,它完美地显示了所有行号!

    • 已删除行的行号位于左侧,并在: 的最左侧和右侧显示- 符号,以帮助您更好地查看 - 无论您的眼睛喜欢向下扫视结肠右侧或屏幕最左侧。
    • 添加的行的行号更靠右,并在: 的最左侧和右侧显示+ 符号。
    • 为上下文显示的未更改行的行号同时显示为左侧(旧文件)和右侧(新文件),由,分隔。

    git diffn 的输出:

    $ git diffn
    diff --git a/hello_world.c b/hello_world.c
    index e01704a..e971b73 100644
    --- a/hello_world.c
    +++ b/hello_world.c
    @@ -1,8 +1,12 @@
    +        1:+// Basic hello world example
    +        2:+
        1,   3: #include <stdio.h>
        2,   4: 
    -   3     :-int main()
    +        5:+int main(int argc, char *argv[])
        4,   6: {
    -   5     :-    printf("Hello World\n");
    -   6     :-
    +        7:+    printf("Hello Gabriel\n");
    +        8:+    
    +        9:+    int i = 700;
    +       10:+    printf("i = %i\n", i);
        7,  11:     return 0;
    -   8     :-}
    \ No newline at end of file
    +       12:+}
    

    以及显示颜色的屏幕截图。请注意,冒号未着色或样式化以匹配左右周围的文本。这是有意和设计的行为,用作左侧添加的行号和右侧的原始git diff 输出之间的视觉分隔符。

    另见

    1. 另请参阅my other answer here,我只是建议您使用meld 作为您的git difftool。 Meld 真棒,我使用它的次数比git diffn 多,尽管我确实同时使用了这两种方法。虽然现在有了git diffn,但我几乎从不使用git diff,除非我在另一台电脑上。

    【讨论】:

    • 第一次尝试 linux:从浏览器复制,粘贴到 vim :new git-diffn.sh, "+gP, :wq, chmod +x git-diffn.sh ...成功了。
    • 很棒的文档,应该是详细的。
    【解决方案4】:

    这是一个尝试解决此问题的脚本 - 没有在愤怒中对其进行测试,但看起来还可以。它依赖 git diff 生成的记录并使用 awk 来维护行数。

    # Massage the @@ counts so they are usable
    function prep1() {
       cat | awk -F',' 'BEGIN { convert = 0; }
           /^@@ / { convert=1; }
           /^/  { if ( convert == 1 ) { print $1,$2,$3;
                  } else { print $0;
                  }
                  convert=0;
                 }'
    }
    
    # Extract all new changes added with the line count
    function prep2() {
      cat | awk 'BEGIN { display=0; line=0; left=0; out=1;}
         /^@@ / { out=0; inc=0; line=$4; line--; display=line; left=line;        }
         /^[-]/   { left++; display=left; inc=0; }
         /^[+]/   { line++; display=line; inc=0; }
         /^[-+][-+][-+] / { out=0; inc=0; }
         /^/    { 
                   line += inc;
                   left += inc;
                   display += inc;
                   if ( out == 1 ) {
                       print display,$0;
                   } else {
                       print $0;
                   }
                   out = 1;
                   inc = 1;
                   display = line;
                }'
    } 
    
    git diff $1 | prep1 | prep2 
    

    【讨论】:

      【解决方案5】:

      一种快速的方法是使用git diff -U0。这会将上下文行设置为 0,这将使 @@ 值与实际更改的行匹配。默认情况下,@@ 值包括 3 行前后上下文,这对人类来说并不方便。

      例子:

      git diff # default
      @@ -10,8 +10,8 @@
      

      这很难计算更改行的行号,因为第 10 行引用了之前上下文的第一行。第一个更改的行的实际行号是 10+3=13。要计算更改的行数,您还必须减去前后上下文:8-3-3=2。

      git diff -U0
      @@ -13,2 +13,2 @@
      

      如您所见,设置 context = 0 使 @@ 值更易于人类阅读。可以看到改行从第13行开始,改行有2行。

      这并不完美,因为它只显示每个块的行号。如果您想查看每一行的行号,请使用 difftool 作为外部编辑器。见https://stackoverflow.com/a/50049752

      【讨论】:

        【解决方案6】:

        您可以使用git difftool 与将显示行号的外部编辑器进行比较。以下是使用 vim / vimdiff 的方法:

        1. 将 vimdiff 设置为 git 的 difftool:

          git config --global diff.tool vimdiff
          
        2. 配置~/.vimrc使用vimdiff时自动显示行号:

          if &diff
              set number
          endif
          
        3. 运行 git difftool,它将使用带有行号的 vimdiff:

          git difftool
          

        【讨论】:

        • 只做 git difftool 它为我打开了 tkdiff 工具,它本身具有行号功能。谢谢wisbucky
        【解决方案7】:

        我喜欢使用 git difftoolmeld 作为我的 difftool。它比 git diff 更容易查看,具有很好的并排 gui 比较,并在每一侧显示行号。

        设置:

        1. My instructions on how to set up meld as your difftool for Windows or Linux

        示例截图:

        2020 年 5 月 24 日更新:

        我刚刚在过去几天写了git diffn 来替代命令行上的git diff。试一试。 See my other answer here.

        【讨论】:

          【解决方案8】:

          你可以试试

          git blame
          

          在文件上。它会显示文件中每一行的提交者、提交 ID 和行号。

          【讨论】:

          • 问题在于它没有向您显示 diff,而这正是原始发帖人所要求的。 git blame 只会显示文件的当前状态和行号。
          • 我知道 git blame,但谷歌搜索的人可能不知道。它可能会帮助某人。感谢您的回答。
          • git blame 绝不回答问题;我对这里的赞成票感到很困惑
          • 请不要向stackoverflow发送与问题无关的答案。
          【解决方案9】:

          首先,配置你的 git diff 工具,例如融合

          git config --global diff.tool meld
          

          然后,将您的 difftool 拉到某个文件上:

          git difftool -y config.rb
          

          记住在差异工具的首选项中设置行号。

          【讨论】:

            【解决方案10】:

            试试https://github.com/so-fancy/diff-so-fancy

            brew install diff-so-fancynpm install -g diff-so-fancy

            然后

            git config --global core.pager "diff-so-fancy | less --tabs=4 -RFX"
            git config --global interactive.diffFilter "diff-so-fancy --patch"
            

            【讨论】:

              猜你喜欢
              • 2019-02-15
              • 2014-04-03
              • 2021-10-20
              • 2020-09-07
              • 2012-01-23
              • 2014-06-01
              • 2019-03-04
              • 1970-01-01
              相关资源
              最近更新 更多