代码之家  ›  专栏  ›  技术社区  ›  Shersh

如何组合“git diff--name status”和“git diff--stat”命令的输出?

  •  3
  • Shersh  · 技术社区  · 6 年前

    git diff --name-status 命令我可以看到文件状态如下的文件名:

    M       .bashrc
    D       .ghc/.ghci.conf.un~
    D       .ghc/ghci_history
    M       .life
    A       .profile
    M       .spacemacs
    

    git diff --stat 我可以看到行计数和文件更改的统计信息:

     .bashrc             |   3 ++-
     .ghc/.ghci.conf.un~ | Bin 13912 -> 0 bytes
     .ghc/ghci_history   | 100 --------------------------------------------------------------------------------------------
     .life               |   2 ++
     .profile            |  23 +++++++++++++++++++++
     .spacemacs          |   3 +++
    

    有没有办法把两个命令的输出结合起来?我想要这样的东西:

    M  .bashrc             |   3 ++-
    D  .ghc/.ghci.conf.un~ | Bin 13912 -> 0 bytes
    D  .ghc/ghci_history   | 100 --------------------------------------------------------------------------------------------
    M  .life               |   2 ++
    A  .profile            |  23 +++++++++++++++++++++
    M  .spacemacs          |   3 +++
    

    当然,我可以通过字符串调用两个命令,然后操纵字符串来手动完成。但我不确定这些命令的输出有多可靠和一致。也许在什么地方有记录。请提供一个shell命令,允许我从终端看到这样的差异,好吗?

    3 回复  |  直到 5 年前
        1
  •  4
  •   drzraf    5 年前
    DIFF=origin/master..HEAD
    join -t $'\t' -1 2 -2 1 -o 1.1,2.1,2.2 \
            <(git diff --name-status $DIFF | sort -k2)
            <(git diff --stat=$((COLUMNS-4)),800 $DIFF | sed -e '$d' -e 's/^ *//;s/ /\t/' | sort) \
            | sed 's/\t/ /g'
    

    或者,在 [alias] 部分 ~/.gitconfig

    ndiff = "!f() { TAB=`printf '\t'`; COLUMNS=`stty size|cut -d' ' -f2`; cd $GIT_PREFIX; git diff --name-status $1 | sort -k2 > /tmp/.tmpgitndiff ; git diff --stat=$COLUMNS,800 $1 |sed -e '$d' -e \"s/^ *//;s/ /${TAB}/\" | sort | join -t \"${TAB}\" -1 2 -2 1 -o 1.1,2.1,2.2 /tmp/.tmpgitndiff - | sed \"s/${TAB}/ /g\"; rm -f /tmp/.tmpgitndiff; }; f"
    
    $ git ndiff origin/master..HEAD -- dev/ # example
    M dev/main.scss   |   9 +
    A dev/rs.js       |  19 ++
    
        2
  •  3
  •   o11c    6 年前

    又快又脏的是用来 wdiff 以下内容:

    $ wdiff -n -w '' -x '' -y '' -z '' <(git diff --name-status) <(git diff --stat)
    vvv 2018-06-26 10:08:27-0700
    M       foo/baz.py   | 19 +++++++++++--------
    M       foo/bar.py   | 37 ++++++++-----------------------------
    M       foo/qux.py   |  2 +-
     3 files changed, 20 insertions(+), 38 deletions(-)
    

    这个 -[w-z] 选项为插入/删除的开始/结束设置分隔符。

    -n 确保输出是逐行的…这可能不重要什么时候 -[西-西] 都通过了,但这是一个好习惯 WDIFF公司 一般来说。

    理论上,如果您的文件名与行上的其他文件类似,则很容易出错。幸运的是,良好的实践倾向于避开文件名,比如 M ,请 | 我是说, 19 ,和 +++++++++++--------


    更正确的方法是 paste ,但这需要传递输出 sed 然后移除重复部分。

        3
  •  1
  •   yaba    5 年前

    您还可以使用for循环筛选每个可能状态的输出:

    for filter in A C D M R T U X B; do git diff --diff-filter="$filter" --stat | head -n -1 | sed "s/.*/$filter &/"; done;
    
    • --diff-filter 确保仅显示当前状态的文件(例如,仅显示[a]DDED文件)
    • --stat 显示所需的状态
    • 这个 head 然后命令删除每个stat输出的最后一行(例如 x files changed, n deletions )
    • 最后 sed 命令在开始时插入当前筛选器(例如 A )

    这意味着您总是按照文件的状态进行排序,而不是仅仅通过git命令对文件进行排序。

    编辑

    正如@shersh在评论中提到的, tail -n 在MacOS上不与负整数一起工作。有两种解决方案:

    1. 安装ghead: brew install coreutils (这是jchook在 this answer )
    2. 或使用 tac 要反转行,请从第二行开始 tail -n +2 然后再倒过来 TAC公司 以下内容:
    for filter in A C D M R T U X B; do git diff --diff-filter="$filter" --stat | tac | tail -n +2 | tac | sed "s/.*/$filter &/"; done;
    

    PS.而不是 TAC公司 你也可以用 tail -r ,但这并不适用于所有系统,而且您的对齐也不正确(请参阅@shersh的评论,无法在我的系统上测试)。