是否可以在 Git 中对 shell 的内置命令使用别名扩展?
Is it possible to use alias expansion with shell's builtin commands in Git?
我的 .gitconfig
中有以下别名:
freq = !history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5
它应该显示我最常用的 5 个 git 命令。取自这里:http://alblue.bandlem.com/2011/04/git-tip-of-week-aliases.html(我知道这篇文章是旧的)
当我运行命令时,它没有输出任何东西:
$ git freq
$
但是如果我运行history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5
,给出的输出是:
$ history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n
5 git log
5 git status
5 git current
5 git co master
4 git co other-branch
我猜这是因为 history
是一个 shell 内置命令,如果我更改 freq
别名,例如至:
freq = !history
我得到:
$ git freq
error: cannot run history: No such file or directory
fatal: While expanding alias 'freq': 'history': No such file or directory
$
有没有办法让它起作用?
原因
看完问题后,我也认为问题是由于 history
是一个 shell 内置的。
调试git
Git命令可以通过设置GIT_TRACE
环境变量来调试
至 true
(有关详细信息,请参阅 Scott Chacon 的 Git 书中关于 Git Internals - Environment Variables 的相关部分)。
$ GIT_TRACE=true git freq
10:14:11.901296 git.c:554 trace: exec: 'git-freq'
10:14:11.901296 run-command.c:341 trace: run_command: 'git-freq'
10:14:11.932496 run-command.c:341 trace: run_command: 'history | tail'
10:14:11.963697 run-command.c:192 trace: exec: '/bin/sh' '-c' 'history | tail' 'history | tail'
Checking the source 显示外部命令由调用 sane_execvp
的 execv_shell_cmd
函数处理,这是 execvp
[=87 的一个更用户友好的前端=]standard library 函数——如果命令名称不包含斜杠——搜索 PATH 中的每个目录以查找与命令同名的可执行文件。由于 history
是一个 shell 内置的,它永远不会被发现,所以它 returns 是一个错误。参见
- execvp man page
- How does execvp run a command?
- execvpe.c
我不是一个听之任之的人,后来我使用其他 shell 内置插件进行了进一步的实验,这些实验成功了,所以我认为它一定是别的东西:
没有非交互式 shells
的历史记录
阅读 Bash 手册解释说 Bash History Facilities are only used in interactive shells 而 shell 由 exec
调用启动是非交互式的。这就是为什么 运行 宁 history
内置不打印任何输出。
解决方案
选项 1:在非交互式中打开历史功能 shell
感谢Gilles on Unix and Linux,原来非交互shell中的历史特征可以通过设置HISTFILE
shell变量开启,然后运行ning set -o history
可以看出 运行ning:
bash -c "HISTFILE=~/.bash_history; set -o history; history"
在 .gitconfig
中设置以下别名将起作用:
freq = "!HISTFILE=$HOME/.bash_history; set -o history; history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5"
注意:如果您使用 shell 而不是 Bash,您需要指定 shell 保存其命令历史记录的文件的名称。如果您使用 Bash,可能 HISTFILE
shell 变量设置为 $HOME/.bash_history
.
以外的值
此外,shell 变量(例如 HISTFILE
不应作为环境变量导出(可用于 git),这就是我在这里没有使用它的原因。
选项 2:从历史文件中读取
一个更简单的解决方案是直接从 shell 历史文件中读取:
freq = !grep ^git $HOME/.bash_history | sort | uniq -c | sort -n -r | head -n 5
这将给出与 运行 在新的交互式 shell 中使用 history
命令相同的结果,因为当新的 shell 启动时,它没有命令它的历史不同于它从历史文件中读取的内容。
此外,直接从历史文件中读取时不需要cut
命令。
选项 3:Bash别名
另一种选择是忘记使用 Git 别名,而只使用 Bash 别名:
alias git-freq='history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n
使 shell 历史文件保持最新
我想添加以下有用的辅助信息。请注意,它适用于交互式 Bash shell,它可能适用于也可能不适用于其他现代 shell。
我经常在同一台主机上同时 运行 多个 shell 并且我不希望在退出 shell 时覆盖保存的历史命令。这是我的 .bashrc
设置,可确保在每个命令后写入 shell 历史文件:
# Append history entries on logout - instead of over-writing the history file.
shopt -s histappend
# Don't store duplicate lines in the history.
# Ignore any commands that begin with a space.
HISTCONTROL=ignoredups:ignorespace
# Use a very large history file to store lots of commands.
# See http://mywiki.wooledge.org/BashFAQ/088
HISTFILESIZE=5000
# Keeping a large history requires system resources
HISTSIZE=3000
# Append to the history file after every command.
PROMPT_COMMAND="history -a"
我的 .gitconfig
中有以下别名:
freq = !history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5
它应该显示我最常用的 5 个 git 命令。取自这里:http://alblue.bandlem.com/2011/04/git-tip-of-week-aliases.html(我知道这篇文章是旧的)
当我运行命令时,它没有输出任何东西:
$ git freq
$
但是如果我运行history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5
,给出的输出是:
$ history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n
5 git log
5 git status
5 git current
5 git co master
4 git co other-branch
我猜这是因为 history
是一个 shell 内置命令,如果我更改 freq
别名,例如至:
freq = !history
我得到:
$ git freq
error: cannot run history: No such file or directory
fatal: While expanding alias 'freq': 'history': No such file or directory
$
有没有办法让它起作用?
原因
看完问题后,我也认为问题是由于 history
是一个 shell 内置的。
调试git
Git命令可以通过设置GIT_TRACE
环境变量来调试
至 true
(有关详细信息,请参阅 Scott Chacon 的 Git 书中关于 Git Internals - Environment Variables 的相关部分)。
$ GIT_TRACE=true git freq
10:14:11.901296 git.c:554 trace: exec: 'git-freq'
10:14:11.901296 run-command.c:341 trace: run_command: 'git-freq'
10:14:11.932496 run-command.c:341 trace: run_command: 'history | tail'
10:14:11.963697 run-command.c:192 trace: exec: '/bin/sh' '-c' 'history | tail' 'history | tail'
Checking the source 显示外部命令由调用 sane_execvp
的 execv_shell_cmd
函数处理,这是 execvp
[=87 的一个更用户友好的前端=]standard library 函数——如果命令名称不包含斜杠——搜索 PATH 中的每个目录以查找与命令同名的可执行文件。由于 history
是一个 shell 内置的,它永远不会被发现,所以它 returns 是一个错误。参见
- execvp man page
- How does execvp run a command?
- execvpe.c
我不是一个听之任之的人,后来我使用其他 shell 内置插件进行了进一步的实验,这些实验成功了,所以我认为它一定是别的东西:
没有非交互式 shells
的历史记录阅读 Bash 手册解释说 Bash History Facilities are only used in interactive shells 而 shell 由 exec
调用启动是非交互式的。这就是为什么 运行 宁 history
内置不打印任何输出。
解决方案
选项 1:在非交互式中打开历史功能 shell
感谢Gilles on Unix and Linux,原来非交互shell中的历史特征可以通过设置HISTFILE
shell变量开启,然后运行ning set -o history
可以看出 运行ning:
bash -c "HISTFILE=~/.bash_history; set -o history; history"
在 .gitconfig
中设置以下别名将起作用:
freq = "!HISTFILE=$HOME/.bash_history; set -o history; history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5"
注意:如果您使用 shell 而不是 Bash,您需要指定 shell 保存其命令历史记录的文件的名称。如果您使用 Bash,可能 HISTFILE
shell 变量设置为 $HOME/.bash_history
.
此外,shell 变量(例如 HISTFILE
不应作为环境变量导出(可用于 git),这就是我在这里没有使用它的原因。
选项 2:从历史文件中读取
一个更简单的解决方案是直接从 shell 历史文件中读取:
freq = !grep ^git $HOME/.bash_history | sort | uniq -c | sort -n -r | head -n 5
这将给出与 运行 在新的交互式 shell 中使用 history
命令相同的结果,因为当新的 shell 启动时,它没有命令它的历史不同于它从历史文件中读取的内容。
此外,直接从历史文件中读取时不需要cut
命令。
选项 3:Bash别名
另一种选择是忘记使用 Git 别名,而只使用 Bash 别名:
alias git-freq='history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n
使 shell 历史文件保持最新
我想添加以下有用的辅助信息。请注意,它适用于交互式 Bash shell,它可能适用于也可能不适用于其他现代 shell。
我经常在同一台主机上同时 运行 多个 shell 并且我不希望在退出 shell 时覆盖保存的历史命令。这是我的 .bashrc
设置,可确保在每个命令后写入 shell 历史文件:
# Append history entries on logout - instead of over-writing the history file.
shopt -s histappend
# Don't store duplicate lines in the history.
# Ignore any commands that begin with a space.
HISTCONTROL=ignoredups:ignorespace
# Use a very large history file to store lots of commands.
# See http://mywiki.wooledge.org/BashFAQ/088
HISTFILESIZE=5000
# Keeping a large history requires system resources
HISTSIZE=3000
# Append to the history file after every command.
PROMPT_COMMAND="history -a"