我的 .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 |切-c 8- | grep ^git |排序 | uniq-c |排序-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 builtin。
调试 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
标准更友好的前端library 函数,如果命令名称不包含斜杠,则在 PATH 中的每个目录中搜索与命令同名的可执行文件。由于 history
是一个内置的 shell,它永远不会被发现,所以它会返回一个错误。见
我不是一个听之任之的人,后来我使用其他 shell 内置插件进行了进一步的实验,这些实验成功了,所以我认为它一定是别的东西:
没有非交互式 shell 的历史记录
阅读 Bash 手册解释了 Bash History Facilities仅用于 interactive shells而由 exec
调用启动的 shell 是非交互式的。这就是为什么运行 history
内置函数不打印任何输出的原因。
解决方案
选项 1:在非交互式 shell 中打开历史记录功能
感谢Gilles on Unix and Linux ,事实证明,可以通过设置 HISTFILE
shell 变量然后运行 set -o history
来打开非交互式 shell 中的历史功能,如下所示运行:
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"
注意:如果您使用的是 Bash 以外的 shell,则需要指定 shell 将其命令历史记录保存到的文件的名称。如果您使用的是 Bash,则 HISTFILE
shell 变量可能设置为 $HOME/.bash_history
以外的值。
此外,诸如 HISTFILE
之类的 shell 变量不应作为环境变量导出(可用于 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"
关于git - 是否可以在 Git 中对 shell 的内置命令使用别名扩展?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32625352/