【问题标题】:Is it possible to use alias expansion with shell's builtin commands in Git?是否可以在 Git 中将别名扩展与 shell 的内置命令一起使用?
【发布时间】:2015-09-17 08:04:42
【问题描述】:

我的.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
$

有没有办法让它工作?

【问题讨论】:

    标签: git shell alias


    【解决方案1】:

    原因

    看了这个问题后,我也认为问题是由于history是一个shell内置的。

    调试 git

    可以通过设置GIT_TRACE环境变量来调试Git命令 到true(有关更多信息,请参阅 Scott Chacon 的 Git Book 中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_execvpexecv_shell_cmd 函数处理,这是execvp 的更用户友好的前端标准库 函数——如果命令名称不包含斜线 - 在 PATH 中的每个目录中搜索与该命令同名的可执行文件。由于history 是一个内置的shell,它永远不会被发现,所以它返回一个错误。见


    我不是一个放手的人,后来我使用其他 shell 内置函数进行了进一步的实验,这些实验成功了,所以我认为它一定是别的东西:

    非交互式 shell 没有历史记录

    阅读 Bash 手册说明 Bash History Facilities 仅用于 interactive shells 而由 exec 调用启动的 shell 是非交互式的。这就是为什么运行 history 内置函数不会打印任何输出的原因。


    解决方案

    选项 1:在非交互式 shell 中开启历史记录功能

    感谢Gilles on Unix and Linux,原来非交互式shell中的历史功能可以通过设置HISTFILE shell变量然后运行set -o history来开启,运行可以看到:

    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"
    

    【讨论】:

    • .bash_history 读取似乎与history 给出的结果不同。当别名设置为您的解决方法时,我没有得到任何输出(我检查了我的 ~/.bash_history 并且实际上没有 git 命令)。但是,如果我运行$ history,我可以看到我之前发出的一些git 命令......所以也许我可以使用!bash -c "history" 之类的东西?
    • 我试过了:freq = !bash -c "history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5" 但它似乎也不起作用......
    • 感谢您的更新。 # Don't store duplicate lines in the history. 是不是表示如果我输入一次git log 然后再重新输入一次,在.bash_history 里面只会存储一次?
    • @tonix。这是正确的。你可能想要也可能不想要这种行为。
    • 是的,很抱歉缺席,我有一些事情要做。感谢您的帮助,我现在将使用alias
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 2018-09-03
    • 2014-04-07
    • 1970-01-01
    • 2014-08-10
    • 2017-05-24
    相关资源
    最近更新 更多