Git别名与位置参数

基本上我试图别名:

git files 9fa3 

执行命令:

 git diff --name-status 9fa3^ 9fa3 

但是git并没有将位置parameter passing给别名命令。 我努力了:

 [alias] files = "!git diff --name-status $1^ $1" files = "!git diff --name-status {1}^ {1}" 

…和其他一些人,但没有工作。

退化的情况是:

 $ git echo_reverse_these_params abcde edcba 

…我怎么做这个工作?

最明显的方法是使用shell函数:

 [alias] files = "!f() { git diff --name-status \"$1^\" \"$1\"; }; f" 

别名没有! 被视为Git命令; 例如commit-all = commit -a

随着! ,它在shell中作为自己的命令运行,让你使用这样更强大的魔法。

你也可以直接引用sh (而不是创build一个函数):

 [alias] files = !sh -c 'git diff --name-status $1^ $1' - 

(注意行尾的破折号 – 你会需要的。)

您正在寻找的别名是:

 files = "!git diff --name-status \"$1\"^ \"$1\" #" 

通过参数validation:

 files = "![ x$# != x1 ]&&echo "commit-ish required" >&2 || git diff --name-status \"$1\"^ \"$1\" #" 

最后的#很重要 – 它阻止了shell处理所有用户提供的参数(它将它们注释掉)。

注意: git将所有用户提供的参数放在命令行的末尾。 要看到这个动作,请尝试: GIT_TRACE=2 git files abcd

转义(由于嵌套) 引号对于包含空格的文件名很重要,或者"; rm -rf --no-preserve-root /;

使用git手册页中描述的GIT_TRACE = 1来使别名处理透明:

 $ git config alias.files !git diff --name-status $1^ $1 $ GIT_TRACE=1 git files 1d49ec0 trace: exec: 'git-files' '1d49ec0' trace: run_command: 'git-files' '1d49ec0' trace: run_command: 'git diff --name-status $1^ $1' '1d49ec0' trace: exec: '/bin/sh' '-c' 'git diff --name-status $1^ $1 "$@"' 'git diff --name-status $1^ $1' '1d49ec0' trace: built-in: git 'diff' '--name-status' '1d49ec0^' '1d49ec0' '1d49ec0' trace: run_command: 'less -R' trace: exec: '/bin/sh' '-c' 'less -R' 'less -R' MM TODO 

您的原始命令与git 1.8.3.4版本一起工作(Eimantas在1.8.2.1中指出了这一点)。

sh -c '..' --f() {..}; f f() {..}; f选项以不同的方式干净地处理“$ @”参数(参见GIT_TRACE)。 追加“#”到一个别名也将允许位置参数而不离开尾随的参数。

如上面的Drealmer所述( https://stackoverflow.com/a/3322412/2955802

“ 小心, ! 将运行在版本库的根目录下,所以在调用你的别名时使用相对path不会给你所期望的结果。 – Drealmer 13年8月8日在16:28»

Git_PREFIX被git设置到你所在的子目录,你可以通过改变目录来绕过这个:

git alias ls ='! cd $ {GIT_PREFIX: – 。}; ls -al'

我想用别名做到这一点:

 git checkout $1; git merge --ff-only $2; git branch -d $2; 

最后,我创build了一个名为git-m的shell脚本,它具有以下内容:

 #!/bin/bash -x set -e #by naming this git-m and putting it in your PATH, git will be able to run it when you type "git m ..." if [ "$#" -ne 2 ] then echo "Wrong number of arguments. Should be 2, was $#"; exit 1; fi git checkout $1; git merge --ff-only $2; git branch -d $2; 

这有一个好处,它更清晰,因为它在多行。 另外我喜欢用-xset -e来调用bash。 你也许可以把这个事情做成一个别名,但是这将是超级难看的,难以维护。

因为这个文件被命名为git-m你可以像这样运行它: git m foo bar

刚碰上类似的东西, 希望这是奥克张贴我的笔记。 有一件事让我对使用参数的git别名感到困惑,可能来自git help config (我有git 1.7.9.5版本):

如果别名扩展以感叹号为前缀,则将被视为shell命令。 例如,定义“alias.new =!gitk – all – not ORIG_HEAD”,调用“git new”相当于运行shell命令“gitk – all – not ORIG_HEAD”。 请注意,shell命令将从存储库的顶级目录(可能不一定是当前目录)执行。 […]

我看到它的方式 – 如果一个别名“将被视为一个shell命令”的前缀感叹号 – 为什么我需要使用一个函数,或sh -c与参数; 为什么不直接写我的命令呢?

我仍然不知道答案,但我认为结果实际上有些微差别。 这里有一个小testing – 扔在你的.git/config~/.gitconfig

 [alias] # ... ech = "! echo rem: " shech = "! sh -c 'echo rem:' " fech = "! f() { echo rem: ; }; f " # must have ; after echo! echargs = "! echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ " fechargs = "! f() { echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ ; }; f " 

这是我运行这些别名:

 $ git ech word1 word2 rem: word1 word2 $ git shech word1 word2 rem: $ git fech word1 word2 rem: $ git echargs word1 word2 0[[ echo 0[["$0"]] 1-"$1"/ A-$@/ ]] 1-word1/ A-word1 word2/ word1 word2 $ git fechargs word1 word2 0[[ f() { echo 0[["$0"]] 1-"$1"/ A-$@/ ; }; f ]] 1-word1/ A-word1 word2/ 

…或者:当你使用“plain”命令后! git alias中的“as-is” – 然后git自动将参数列表附加到该命令! 一种避免这种情况的方法确实是将脚本称为函数 – 或者作为sh -c参数。

另一个有趣的事情(对我来说)是,在一个shell脚本中,通常需要自动variables$0作为脚本的文件名。 但是对于一个git别名函数, $0参数基本上是指定该命令的整个string的内容(如在configuration文件中input的那样)。

这就是为什么我猜,如果你碰巧错误的 – 在下面的情况下,这将是逃避外双引号:

 [alias] # ... fail = ! \"echo 'A' 'B'\" 

… – 然后git会失败(对我来说,至less)有些神秘的信息:

 $ git fail "echo 'A' 'B'": 1: echo 'A' 'B': not found fatal: While expanding alias 'fail': ' "echo 'A' 'B'"': No such file or directory 

我想,因为git “看到”整个string只是一个参数! – 它试图运行它作为一个可执行文件; 并相应地找不到"echo 'A' 'B'"作为文件。

在任何情况下,在上面的git help config引用的上下文中,我推测这是更准确的状态像这样:“ …调用”git new“相当于运行shell命令”gitk –all – -not ORIG_HEAD $ @“,其中$ @是在运行时从命令行传递给git命令别名的参数。 ” 我认为这也可以解释为什么OP中的“直接”方法不适用于位置参数。