带有位置参数的 Git 别名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3321492/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 08:48:38  来源:igfitidea点击:

Git alias with positional parameters

gitcommandparameterspositionalias

提问by user400575

Basically I'm trying to alias:

基本上我试图别名:

git files 9fa3

...to execute the command:

...执行命令:

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

but git doesn't appear to pass positional parameters to the alias command. I have tried:

但 git 似乎没有将位置参数传递给 alias 命令。我试过了:

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

...and a few others but those didn't work.

...和其他一些,但那些没有用。

The degenerate case would be:

退化的情况是:

$ git echo_reverse_these_params a b c d e
e d c b a

...how can I make this work?

......我怎样才能做到这一点?

回答by Cascabel

The most obvious way is to use a shell function:

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

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

An alias without !is treated as a Git command; e.g. commit-all = commit -a.

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

With the !, it's run as its own command in the shell, letting you use stronger magic like this.

使用!,它会在 shell 中作为自己的命令运行,让您可以像这样使用更强大的魔法。

UPD
Because commands are executed at the root of repository you may use ${GIT_PREFIX}variable when referring to the file names in commands

UPD
因为命令是在存储库的根目录执行的,所以${GIT_PREFIX}在引用命令中的文件名时可以使用变量

回答by mipadi

You can also reference shdirectly (instead of creating a function):

您也可以sh直接引用(而不是创建函数):

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

(Note the dash at the end of the line -- you'll need that.)

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

回答by Tom Hale

The alias you are looking for is:

您要查找的别名是:

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

With argument validation:

使用参数验证:

files = "!cd -- \"${GIT_PREFIX:-.}\" && [ x$# != x1 ] && echo commit-ish required >&2 || git diff --name-status \"\"^ \"\" #"

The final #is important - it prevents all the user-supplied arguments from being processed by the shell (it comments them out).

最终#是重要-它可以防止所有的用户提供的参数从由所述外壳(它评论出来)被处理。

Note: gitputs all user-supplied arguments at the end of the command line. To see this in action, try: GIT_TRACE=2 git files a b c d

注意:git将所有用户提供的参数放在命令行的末尾。要查看此操作,请尝试:GIT_TRACE=2 git files a b c d

The escaped (due to nesting) quotesare important for filenames containing spaces or "; rm -rf --no-preserve-root /;)

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

回答by bsb

Use GIT_TRACE=1 described on the git man page to make the alias processing transparent:

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

$ git config alias.files
!git diff --name-status ^ 
$ GIT_TRACE=1 git files 1d49ec0
trace: exec: 'git-files' '1d49ec0'
trace: run_command: 'git-files' '1d49ec0'
trace: run_command: 'git diff --name-status ^ ' '1d49ec0'
trace: exec: '/bin/sh' '-c' 'git diff --name-status ^  "$@"' 'git diff --name-status ^ ' '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

Your original commands work with git version 1.8.3.4 (Eimantas noted this changed in 1.8.2.1).

您的原始命令适用于 git 版本 1.8.3.4(Eimantas 指出这在 1.8.2.1 中发生了变化)。

The sh -c '..' --and f() {..}; foptions both cleanly handle the "$@" parameters in different ways (see with GIT_TRACE). Appending "#" to an alias would also allow positional parameters without leaving the trailing ones.

sh -c '..' --f() {..}; f选项都处理干净的“$ @”以不同的方式参数(请参阅使用GIT_TRACE)。将“#”附加到别名还允许位置参数不留下尾随参数。

回答by Pierre-Olivier Vares

As stated by Drealmer above:

正如上面Drealmer所说

? Be careful, ! will run at the root of the repository, so using relative paths when calling your alias will not give the results you might expect. – Drealmer Aug 8 '13 at 16:28 ?

? 当心, !将在存储库的根目录下运行,因此在调用别名时使用相对路径不会给出您可能期望的结果。– Drealmer 2013 年 8 月 8 日 16:28 ?

GIT_PREFIXbeing set by git to the subdirectory you're in, you can circumvent this by first changing the directory :

GIT_PREFIX由 git 设置为您所在的子目录,您可以通过首先更改目录来规避此问题:

git config --global alias.ls '!cd "${GIT_PREFIX:-.}";ls -al'

git config --global alias.ls '! cd "${GIT_PREFIX:-.}"; ls -al'

回答by Daniel Kaplan

I wanted to do this with an alias that does this:

我想用一个别名来做到这一点:

git checkout ;
git merge --ff-only ;
git branch -d ;

In the end, I created a shell script named git-mthat has this content:

最后,我创建了一个名为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 ;
git merge --ff-only ;
git branch -d ;

This has the benefit that it's muchmore legible because it's on multiple lines. Plus I like being able to call bash with -xand set -e. You can probably do this whole thing as an alias, but it would be super ugly and difficult to maintain.

这有它的好处很多更清晰,因为它是多条线路上。另外,我喜欢能够用-x和调用 bash set -e。您可能可以将这整个事情作为别名来完成,但这将非常丑陋且难以维护。

Because the file is named git-myou can run it like this: git m foo bar

由于文件已命名,因此git-m您可以像这样运行它:git m foo bar

回答by sdaau

Just bumped into something similar; hope it's oK to post my notes. One thing that confuses me about gitaliases with arguments, probably comes from the git help config(I have git version 1.7.9.5):

刚碰到类似的东西;希望可以发布我的笔记。一件事让我对git别名和参数感到困惑,可能来自git help config(我有 git 版本 1.7.9.5):

If the alias expansion is prefixed with an exclamation point, it will be treated as a shell command. For example, defining "alias.new = !gitk --all --not ORIG_HEAD", the invocation "git new" is equivalent to running the shell command "gitk --all --not ORIG_HEAD". Note that shell commands will be executed from the top-level directory of a repository, which may not necessarily be the current directory. [...]

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

The way I see it - if an alias "will be treated as a shell command" when prefixed with exclamation point - why would I need to use a function, or sh -cwith arguments; why not just write my command as-is?

我的看法——如果一个别名在前缀为感叹号时“将被视为 shell 命令”——为什么我需要使用函数或sh -c参数;为什么不按原样写我的命令?

I still don't know the answer - but I think actually there is a slight difference in outcome. Here's a little test - throw this in your .git/configor your ~/.gitconfig:

我仍然不知道答案 - 但我认为实际上结果略有不同。这是一个小测试 - 将其放入您.git/config或您的~/.gitconfig

[alias]
  # ...
  ech = "! echo rem: "
  shech = "! sh -c 'echo rem:' "
  fech = "! f() { echo rem: ; }; f " # must have ; after echo!
  echargs = "! echo 0[[\"
$ git ech word1 word2
rem: word1 word2

$ git shech word1 word2
rem:

$ git fech word1 word2
rem:

$ git echargs word1 word2
0[[ echo 0[["
[alias]
  # ...
  fail = ! \"echo 'A' 'B'\"
"]] 1-""/ A-$@/ ]] 1-word1/ A-word1 word2/ word1 word2 $ git fechargs word1 word2 0[[ f() { echo 0[["
$ git fail
 "echo 'A' 'B'": 1: echo 'A' 'B': not found
fatal: While expanding alias 'fail': ' "echo 'A' 'B'"': No such file or directory
"]] 1-""/ A-$@/ ; }; f ]] 1-word1/ A-word1 word2/
\"]] 1-\"\"/ A-"$@"/ " fechargs = "! f() { echo 0[[\"##代码##\"]] 1-\"\"/ A-"$@"/ ; }; f "

Here is what I get running these aliases:

这是我运行这些别名的结果:

##代码##

... or: when you're using a "plain" command after the !"as-is" in a gitalias - then gitautomatically appends the arguments list to that command! A way to avoid it, is indeed, to call your script as either a function - or as argument to sh -c.

...或:当您!git别名中的“原样”之后使用“普通”命令时- 然后git自动将参数列表附加到该命令!一种避免它的方法确实是将您的脚本作为函数或作为sh -c.

Another interesting thing here (for me), is that in a shell script, one typically expects the automatic variable $0to be the filename of the script. But for a gitalias function, the $0argument is, basically, the content of the entirestring specifying that command (as entered in the config file).

另一个有趣的事情(对我来说)是,在 shell 脚本中,人们通常期望自动变量$0是脚本的文件名。但是对于git别名函数,$0参数基本上是指定该命令的整个字符串的内容(在配置文件中输入)。

Which is why, I guess, if you happen to misquote - in the below case, that would be escaping the outer double quotes:

这就是为什么,我想,如果您碰巧引用错误 - 在下面的情况下,这将转义外部双引号:

##代码##

... - then gitwould fail with (for me, at least) somewhat cryptic message:

... - 然后git会失败(至少对我来说)有点神秘的消息:

##代码##

I think, since git"saw" a whole string as only one argument to !- it tried to run it as an executable file; and correspondingly it failed finding "echo 'A' 'B'"as a file.

我认为,由于git“看到”整个字符串仅作为一个参数!- 它试图将其作为可执行文件运行;相应地,它无法"echo 'A' 'B'"作为文件找到。

In any case, in context of the git help configquote above, I'd speculate that it's more accurate to state something like: " ... the invocation "git new" is equivalent to running the shell command "gitk --all --not ORIG_HEAD $@", where $@ are the arguments passed to the git command alias from command line at runtime. ...". I think that would also explain, why the "direct" approach in OP doesn't work with positional parameters.

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