【问题标题】:How to combine output of `git diff --name-status` and `git diff --stat` commands?如何组合 `git diff --name-status` 和 `git diff --stat` 命令的输出?
【发布时间】:2018-06-26 16:40:30
【问题描述】:

使用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 命令,让我可以从终端查看这些差异?

【问题讨论】:

    标签: git shell diff


    【解决方案1】:
    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'
    

    或者,在 ~/.gitconfig[alias] 部分中完全 POSIX

    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 ++
    

    【讨论】:

    • 应该使用 local temp_file=$(mktemp) 之类的东西,而不是硬编码一个文件名会破坏多次使用。
    • 我尝试从我的 shell 中执行这两个命令,但它们似乎都不能正常工作。
    • @Shersh:确保您正在运行 bash(对于第一个命令),而不是像 busybox 这样的精简 POSIX shell。
    • 我已经找到了问题的原因。我正在使用 macOS。我需要在任何我想使用\t 字符的地方使用$'...' 字符串。现在join 的解决方案有效,输出非常可爱!我会更多地测试它。
    • 要使其适用于所有情况,您还需要sort -k1 git diff --stat 的结果。否则,它并不总是对我有用。但至少我可以有一个同时适用于 macOS 和 Ubuntu 的命令,这对我来说很好。
    【解决方案2】:

    最简单的方法是使用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 确保输出是逐行的……这在传递-[w-z] 时可能无关紧要,但通常对于wdiff 来说是一个好习惯。

    理论上,如果您的文件名看起来像在线上的其他任何内容,这很容易出错。幸运的是,好的做法倾向于避免使用 M|19+++++++++++-------- 等文件名


    更正确的方法是使用paste,但这需要随后通过sed 传递输出以删除重复的部分。

    【讨论】:

      【解决方案3】:

      您还可以使用 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] 已添加的文件)
      • --stat 显示你想要的状态
      • head 命令然后删除每个统计输出的最后一行(例如x files changed, n deletions
      • 最后sed 命令在开头插入当前过滤器(例如A

      这确实意味着您始终可以根据文件的状态而不是单独通过 git 命令对其进行排序的方式对文件进行排序。

      编辑

      正如@Shersh 在 cmets 中所提到的,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;
      

      附言。除了tac,您还可以使用tail -r,但这不适用于所有系统,并且您会松散对齐(参见@Shersh 的评论,无法在我的系统上测试)。

      【讨论】:

      • 当某些过滤器没有输出时,我看到以下错误:head: illegal line count -- -1
      • 嗯.. 运行它时不会发生这种情况。您可以尝试在head 命令的末尾添加2&gt;/dev/null 吗?所以,像这样head -n -1 2&gt;/dev/null |
      • 确实,我在我的 Ubuntu 上看不到错误。错误出现在 macOS 上。那我会在 macOS 上试试这个技巧。
      • 我已经弄清楚为什么我在 macOS 上看到了错误。 macOS 上的 head 不支持否定参数。所以我不得不使用这个问题中描述的 tail reverse trick 使它在两个系统上都工作:unix.stackexchange.com/a/169080/359940 我认为你的解决方案非常好,也是最简单的一个。但是,它不提供 |... 的对齐方式
      • 最简单的方法是在 Mac OS X 上使用 ghead(通过 brew install coreutils 安装,感谢 jchook,评论 this answer)。您将保持对齐并保持命令(相对)简单。我会相应地编辑我的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-03
      • 2019-04-03
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多