带有位置参数的 Git 别名

发布于 2024-09-11 16:04:05 字数 447 浏览 3 评论 0原文

基本上我试图别名:

git files 9fa3

...来执行命令:

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

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

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

...以及其他一些尝试,但这些都不起作用。

退化的情况是:

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

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

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:

[alias]
    files = "!git diff --name-status $1^ $1"
    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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

黑凤梨 2024-09-18 16:04:05

shell 函数可以帮助解决这个问题:

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

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

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

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

A shell function could help on this:

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

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

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

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

時窥 2024-09-18 16:04:05

您正在寻找的别名是:

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

带参数验证:

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

final # 很重要 - 它阻止 shell 处理所有用户提供的参数(它注释它们)出去)。

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

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

The alias you are looking for is:

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

With argument validation:

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

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

Note: git puts 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

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

旧时模样 2024-09-18 16:04:05

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

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

(请注意行末尾的破折号 - 您将需要它。)

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

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

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

遥远的她 2024-09-18 16:04:05

使用 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 选项都以不同的方式干净地处理“$@”参数(请参阅 GIT_TRACE)。将“#”附加到别名也将允许位置参数而不留下尾随参数。

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

$ 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

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

The sh -c '..' -- and f() {..}; f options 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.

乜一 2024-09-18 16:04:05

正如Drealmer上面所述:

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

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

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

As stated by Drealmer above:

« 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 »

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

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

撩起发的微风 2024-09-18 16:04:05

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

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

最后,我创建了一个名为 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

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

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

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

#!/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;

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

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

只为守护你 2024-09-18 16:04:05

刚刚遇到类似的事情;希望可以发布我的笔记。让我对带有参数的 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有论据;为什么不直接写我的命令呢?

我仍然不知道答案 - 但我认为实际上结果略有不同。这是一个小测试 - 将其放入您的 .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/

...或者:当您在 git 别名中的 !“as-is”之后使用“plain”命令 - 然后 git 自动将参数列表附加到那个命令!事实上,避免这种情况的一种方法是将脚本作为函数调用,或者作为 sh -c 的参数来调用。

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

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

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

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

$ 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 “看到”整个字符串只是 ! 的一个参数 - 它试图将其作为可执行文件运行;相应地,它无法找到 "echo 'A' 'B'" 作为文件。

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

Just bumped into something similar; hope it's oK to post my notes. One thing that confuses me about git aliases with arguments, probably comes from the git help config (I have git version 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. [...]

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

I still don't know the answer - but I think actually there is a slight difference in the outcome. Here's a little test - throw this in your .git/config or your ~/.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 "

Here is what I get running these aliases:

$ 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/

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

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

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

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

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

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

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.

In any case, in the context of the git help config quote 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 the command line at runtime. ... ". I think that would also explain, why the "direct" approach in OP doesn't work with positional parameters.

我只土不豪 2024-09-18 16:04:05

一个对我有用的简单解决方案可能是使用:

df1 = "!git diff -- \"$1\" | diff-so-fancy"

结果你得到:
git 别名结果

One simple solution, that works for me could be to use:

df1 = "!git diff -- \"$1\" | diff-so-fancy"

as a result you get:
git alias result

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文