如何合并 `git diff --name-status` 和 `git diff --stat` 命令的输出?
How to combine output of `git diff --name-status` and `git diff --stat` commands?
使用 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 命令让我从终端看到这些差异?
快捷方式是使用 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]
选项设置 insertion/deletion 的 start/end 的分隔符。
-n
确保输出是按行的......这在传递 -[w-z]
时可能无关紧要,但通常是 wdiff
的好习惯。
从理论上讲,如果您的文件名与行中的其他任何内容相似,这很容易出错。幸运的是,好的做法倾向于避免使用 M
、|
、19
和 +++++++++++--------
这样的文件名
更正确的方法是使用 paste
,但这需要通过 sed
传递输出以删除重复的部分。
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'
或者,完全 POSIX 在 ~/.gitconfig
的 [alias]
部分
ndiff = "!f() { TAB=`printf '\t'`; COLUMNS=`stty size|cut -d' ' -f2`; cd $GIT_PREFIX; git diff --name-status | sort -k2 > /tmp/.tmpgitndiff ; git diff --stat=$COLUMNS,800 |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 ++
您还可以使用 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 在评论中提到的,tail -n
不适用于 macOS 上的负整数。有两种解决方法:
- 要么安装 ghead:
brew install coreutils
(感谢 jchook 在 this answer 中的评论)
- 或者用
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。你也可以使用 tail -r
而不是 tac
,但这并不适用于所有系统,并且你松散了对齐(请参阅@Shersh 的评论,无法在我的系统上测试)。
使用 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 命令让我从终端看到这些差异?
快捷方式是使用 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]
选项设置 insertion/deletion 的 start/end 的分隔符。
-n
确保输出是按行的......这在传递 -[w-z]
时可能无关紧要,但通常是 wdiff
的好习惯。
从理论上讲,如果您的文件名与行中的其他任何内容相似,这很容易出错。幸运的是,好的做法倾向于避免使用 M
、|
、19
和 +++++++++++--------
更正确的方法是使用 paste
,但这需要通过 sed
传递输出以删除重复的部分。
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'
或者,完全 POSIX 在 ~/.gitconfig
[alias]
部分
ndiff = "!f() { TAB=`printf '\t'`; COLUMNS=`stty size|cut -d' ' -f2`; cd $GIT_PREFIX; git diff --name-status | sort -k2 > /tmp/.tmpgitndiff ; git diff --stat=$COLUMNS,800 |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 ++
您还可以使用 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 在评论中提到的,tail -n
不适用于 macOS 上的负整数。有两种解决方法:
- 要么安装 ghead:
brew install coreutils
(感谢 jchook 在 this answer 中的评论) - 或者用
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。你也可以使用 tail -r
而不是 tac
,但这并不适用于所有系统,并且你松散了对齐(请参阅@Shersh 的评论,无法在我的系统上测试)。