Git别名 - 多个命令和参数

249

我试图创建一个别名(alias),该别名需要同时使用多个Git命令和位置参数。有关每个部分的Stackoverflow页面,看起来很明显可以同时完成两者,但是我遇到了一些问题。

例如,我想切换到foo分支并执行状态(status)。因此,在我的.gitconfig中,我有:

  [alias] 
     chs = !sh -c 'git checkout $0 && git status'

以下代码无法正常工作。而像这样的代码可以正常工作。

chs = !sh -c 'git checkout $0'

echoes = !sh -c 'echo hi && echo bye'

希望能得到任何有益的见解。


我的别名:git config --global alias.go '!git commit -a && git pull --rebase && git push && git status'。 注意:使用单引号。 - Marcus Becker
此外,您始终可以在“bash”配置中创建别名选项。 - Sławomir Lenart
12个回答

199

这将有效(在zsh和bash上测试通过):

[alias] chs = !git checkout $1 && git status

32
有趣的是,现在git在shell别名中确实填充了位置变量。但它仍然有问题,因为它也将它们附加为参数。当使用参数'foo'调用echo $1 && echo done别名时,它将输出"foo"和"done foo"。 - Lily Ballard
4
哇... 不幸的是,这全是一个版本问题。我使用了Git 1.7.3,但这些方法都没用。我升级到1.7.6之后,一切都正常了。谢谢大家! - Stella
9
git 第一次调用时,前面的感叹号是做什么用的? - Elijah Lynn
39
在 git 别名中,前面加上 ! 表示将整个命令传递给 shell 执行。否则,它会认为你要运行另一个 git 命令,并将其作为参数传递给 git 二进制文件。 - Lily Ballard
3
@Brondahl 聪明。我建议使用;:而不是&& :。在Unix上也可以正常工作。 - Lily Ballard
显示剩余5条评论

135

这是针对Windows批处理 / msysgit bash的; 可能在其他环境中不起作用。

正如Olivier Verdier和Lily Ballard所说

[alias] chs = !git checkout $1 && git status

几乎可以工作,但会多出一个错误的参数插入...

git chs demo -> git checkout demo && git status demo

但是如果您在别名末尾添加&& :,那么多余的参数将被消耗为位置标记。

因此

[alias] chs = !git checkout $1 && git status && :

给出正确的输出...

git chs demo -> git checkout demo && git status

19
&& : 是关键,使得这种解决方案在需要避免额外参数的命令上可行。 - Clay
6
@Clay(或其他人)-能否有人解释一下对于Bash命令不熟悉的人,&& :是什么意思?&& : 是一个 Bash 中的控制流语句。它表示如果前面的命令成功执行,即返回零退出状态码(zero exit status),则执行一个空命令 ":",并返回其退出状态码。这个空命令实际上什么也不做,但是可以用来确保前面的命令成功运行后程序继续执行。 - Justin Morgan
13
@JustinMorgan && 的意思是,如果前一个命令返回状态值 0(成功),则运行 && 后面的命令。冒号“:”是一个 shell 内置命令,除了扩展参数以及执行重定向并返回状态值 0 外,没有其他作用。以下是一些用法:1. a=123;$a 会出错,但是 a=123; : $a 不会。2. : > hello.txt 可以清空 hello.txt 文件内容。3. if [ "$a" = "hello" ];then : ;fi 可以正常运行,但是没有 : 则会报错。它类似于 Python 中的 pass。4. : this is a comment,冒号后加上空格可以像注释一样使用,类似于 # - ElpieKay
6
这是一个很有用的技巧... Git 应该接受多个命令模式。 - kchoi
1
如果您使用引号,以注释结束别名会更好:[alias] chs = !"git checkout $1 && git status #" - 这将把额外的参数转换为不起作用的注释。 - Bernardo Dal Corno
显示剩余4条评论

95
您可以定义一个shell函数。
[alias] chs = "!f(){ git checkout \"$1\" && git status; };f"

2
哇...不幸的是,这全都是版本问题。我使用的是Git 1.7.3,但这两种方法都不起作用。我升级到了1.7.6,然后一切都正常了。谢谢大家! - Stella
5
如果使用Windows,我认为您需要用双引号 " 将shell函数定义括起来。 - drzaus
5
使用参数(OSX)时,Olivier的答案对我无效。这个方法完美地解决了我的问题。 - Ohad Schneider
哦,我想知道为什么会有所不同。我将更新我的答案以包括引号。看起来 git config 在第一次写入值时默认会加上引号。 - Lily Ballard
哎呀,我刚刚浪费了20分钟来解决这个问题。关键是要使用单引号'而不是双引号"才能让它正常工作。 - Vedran Mandić
显示剩余5条评论

39

我能够创建多行和相当复杂的git别名。它们在Windows上运作良好,但我认为它们在其他地方也可以工作,例如:

safereset = "!f() { \
                trap 'echo ERROR: Operation failed; return' ERR; \
                echo Making sure there are no changes...; \
                last_status=$(git status --porcelain);\
                if [[ $last_status != \"\" ]]; then\
                    echo There are dirty files:;\
                    echo \"$last_status\";\
                    echo;\
                    echo -n \"Enter Y if you would like to DISCARD these changes or W to commit them as WIP: \";\
                    read dirty_operation;\
                    if [ \"$dirty_operation\" == \"Y\" ]; then \
                        echo Resetting...;\
                        git reset --hard;\
                    elif [ \"$dirty_operation\" == \"W\" ]; then\
                        echo Comitting WIP...;\
                        git commit -a --message='WIP' > /dev/null && echo WIP Comitted;\
                    else\
                        echo Operation cancelled;\
                        exit 1;\
                    fi;\
                fi;\
            }; \
            f"

我写了一篇文章,这里有更多的例子


3
这段内容的翻译如下:对此的一个改进是在其中添加!f() { : reset},以便从reset命令中获取补全。具体位置在https://github.com/git/git/blob/master/contrib/completion/git-completion.bash#L25。 - a user
干得好!这篇文章是以什么许可证发布的?如果我翻译其中的部分到俄语并在StackOverflow上发布,你介意吗? - Nick Volynkin
@NickVolynkin 抱歉回复晚了。谢谢你,当然,请继续 :) - VitalyB
@NickVolynkin,你最终翻译了它吗? - Alexander Malakhov
对于这样的东西,将其作为一个shell脚本可能更容易维护。然后,您的别名将是类似于safereset = !bash ~/safereset.sh,其中bash是您想要的任何shell,或者如果该脚本可执行并且您想在用户的登录shell中运行它,则为safereset = !~/safereset.sh。使用绝对路径可能是个好主意,尽管~似乎也可以很好地处理。 - Shibumi

28
[alias]
chs = !git branch && git status

13
! 是什么作用? - AutonomousApps
5
我找不到关于!的文档,但据我所见,默认情况下,git会假定别名是一个git命令,因此t = status将起作用。然而,如果您尝试t = git status,它将无法工作(会显示“git”命令未找到)。这时需要使用!,它告诉git将该命令作为shell运行。通常,当您在别名中有多个git命令时,需要使用此符号,例如t = !git status && git log,它将正常工作。 - laurent
1
这是一个关于Git别名中感叹号(!)的StackOverflow问题:https://dev59.com/omEi5IYBdhLWcg3wptl_。 - Jacob Lockard
2
如果别名扩展以感叹号为前缀,则它将被视为shell命令。https://git-scm.com/docs/git-config - Rohim Chou

13
[alias]
      chs = !git checkout && git status
      ac = !git add . && git commit -m 

什么是!?

如果在别名扩展前加上感叹号,它将被视为shell命令。感叹号在git配置别名中的含义是什么?

从.gitconfig文件中调用别名。

git chs
git ac "write_your_commit_message" 

在git中,alias对于add和commit更有用,可以让你更快地完成操作。

Gif show more datails

7

你可以通过在每行结尾添加 \ 来创建多行的 Git 别名。

[alias] 
   chs = "!git checkout $1 \ 
          ; git status     \
         "

2
谢谢!对于我的别名,我使用 "!git fetch --prune --all; git pull --rebase upstream master; git push origin master" 没有任何问题。 - yurisich

7
尝试这个:
[alias]
    chs = "!sh -c 'git checkout \"$0\" && git status'"

使用以下方式调用:git chs master


5
这里的问题是位置参数似乎被发送到shell命令两次(截至git1.9.2)。要查看我的意思,请尝试以下操作:
[alias]
  test = !git echo $*

接下来,执行git test this is my testing string命令。你会看到如下输出结果(这里为了清晰起见,最后两行做了修改):

03:41:24 (release) ~/Projects/iOS$ git test this is my testing string
this is my testing string this is my testing string
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
          #1                         #2

有一个解决这个问题的方法是:
[alias]
  chs = !git checkout $1 && git status && git echo x >/dev/null

这将会消耗额外的位置参数,因为它被应用到了最后一个echo命令上,并且对结果没有影响。

你的示例将扩展到: git echo 这是我的测试字符串这是我的测试字符串在末尾添加#将修复它(不要忘记在命令别名周围加上双引号)。 - imme
在 .gitconfig 文件中添加以下内容:a0 = "!echo $" 和 a1 = "!echo $ #"。测试它们的方法是:运行 git a0 hallo daar;运行 git a1 hallo daar。 - imme
@imme 在结尾处的 # 是什么作用?它对我有用,但我想了解一下。 - Kramer
请查看此“演示” https://dev59.com/fGsz5IYBdhLWcg3w-85v#63890372(似乎git在用定义的别名替换别名后添加参数,使用$*在别名中已经将参数放入其中,因此应忽略其余部分,这是通过在末尾添加#来实现的,使命令的其余部分成为注释。 - imme

3

一个示例,适合想尝试不同别名的人。

将此内容放入GIT配置文件的别名部分(例如~/.gitconfig):

[alias]
    a0 = "!echo $*"
    a1 = "!echo $* #"
    a2 = "!f () { echo \"$*\"; }; f "
    a3 = "!f () { echo \"$*\"; }; f #"
    a4 = "!f () { echo \"$*\"; }; f \"$*\" #"
    a5 = "!f () { echo \"$*\"; }; f \"$@\" #"
    a6 = "!f () { echo \"$*\"; }; f \"$1\" #"

然后执行这个命令:

cat ~/.gitconfig | grep --extended-regexp -- '(a[0-9])|(alias)' ; \
echo "" ; \
export CMD ; \
for I in {0..6} ; \
do \
    CMD="a""${I}" ; \
    echo -n "Executing alias.${CMD} = " ; \
    git config --global alias."${CMD}" ; \
    git $CMD 'hoi daar' en nu ; \
    git $CMD hoi daar en nu ; \
    echo "" ; \
done ; \
unset CMD ;

应该输出如下内容:
[alias]
    a0 = "!echo $*"
    a1 = "!echo $* #"
    a2 = "!f () { echo \"$*\"; }; f "
    a3 = "!f () { echo \"$*\"; }; f #"
    a4 = "!f () { echo \"$*\"; }; f \"$*\" #"
    a5 = "!f () { echo \"$*\"; }; f \"$@\" #"
    a6 = "!f () { echo \"$*\"; }; f \"$1\" #"

Executing alias.a0 = !echo $*
hoi daar en nu hoi daar en nu
hoi daar en nu hoi daar en nu

Executing alias.a1 = !echo $* #
hoi daar en nu
hoi daar en nu

Executing alias.a2 = !f () { echo "$*"; }; f 
hoi daar en nu
hoi daar en nu

Executing alias.a3 = !f () { echo "$*"; }; f #



Executing alias.a4 = !f () { echo "$*"; }; f "$*" #
hoi daar en nu
hoi daar en nu

Executing alias.a5 = !f () { echo "$*"; }; f "$@" #
hoi daar en nu
hoi daar en nu

Executing alias.a6 = !f () { echo "$*"; }; f "$1" #
hoi daar
hoi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接