由于解析器错误,无法将更复杂的脚本添加为 Git 别名

Adding more complex scripts as Git aliases doesn't work due to parser errors

在Git中,为了方便,我想添加一些全局别名。

命令

git config --global alias.unstage 'reset HEAD --'

如文档中所述,工作正常。所以我尝试使用相同的语法,在命令前加上 ! 到 运行 外部更复杂的脚本:

# release-major
latest=$(git describe --abbrev=0 --tags 2>/dev/null); latest=${latest:-v0.0.0}; components=(${latest//./ }); major=${components[0]}; major=${major//v/}; minor=${components[1]}; patch=${components[2]}; major=$((major+1)); minor=0; patch=0; next='v'$major'.'$minor'.'$patch; git tag -a $next -m ""

# release-minor
latest=$(git describe --abbrev=0 --tags 2>/dev/null); latest=${latest:-v0.0.0}; components=(${latest//./ }); major=${components[0]}; major=${major//v/}; minor=${components[1]}; patch=${components[2]}; minor=$((minor+1)); patch=0; next='v'$major'.'$minor'.'$patch; git tag -a $next -m ""

# release-patch
latest=$(git describe --abbrev=0 --tags 2>/dev/null); latest=${latest:-v0.0.0}; components=(${latest//./ }); major=${components[0]}; major=${major//v/}; minor=${components[1]}; patch=${components[2]}; patch=$((patch+1)); next='v'$major'.'$minor'.'$patch; git tag -a $next -m ""

如果我尝试使用以下语法添加这三个脚本

git config --global alias.my-alias-name '!my-alias-code'

但是,它不起作用。结果始终是解析器错误。

我尝试了所有我能想到的引号、非引号、单引号和双引号的变体。我什至尝试将它们直接添加到 .gitconfig 文件中。 None 有效。

我错过了什么?如何修复这些脚本以便我可以将它们添加为别名?

您在脚本中使用了 bash 特定的语法(例如 $(( )) 用于算术)。但是,git 以 ! 开头的别名默认由 /bin/sh 执行。由于 /bin/sh 只是一个普通的 POSIX shell,它的语法中没有任何这些功能。

幸运的是,这很容易解决。只需将 #!/bin/bash 添加到脚本的开头即可。 (如果它是一个单独的文件。)

如果您正在使用这些内联,那么您可能必须直接调用 bash。这可能是一个令人头疼的引用问题,但您的示例看起来不会是一个大问题。我认为这可能会做到:

# release-major
bash -c "latest=$(git describe --abbrev=0 --tags 2>/dev/null); latest=${latest:-v0.0.0}; components=(${latest//./ }); major=${components[0]}; major=${major//v/}; minor=${components[1]}; patch=${components[2]}; major=$((major+1)); minor=0; patch=0; next='v'$major'.'$minor'.'$patch; git tag -a $next -m ''"

# release-minor
bash -c "latest=$(git describe --abbrev=0 --tags 2>/dev/null); latest=${latest:-v0.0.0}; components=(${latest//./ }); major=${components[0]}; major=${major//v/}; minor=${components[1]}; patch=${components[2]}; minor=$((minor+1)); patch=0; next='v'$major'.'$minor'.'$patch; git tag -a $next -m ''"

# release-patch
bash -c "latest=$(git describe --abbrev=0 --tags 2>/dev/null); latest=${latest:-v0.0.0}; components=(${latest//./ }); major=${components[0]}; major=${major//v/}; minor=${components[1]}; patch=${components[2]}; patch=$((patch+1)); next='v'$major'.'$minor'.'$patch; git tag -a $next -m ''"

您可以取消bash您的单行脚本。让我们以这个为例:

latest=$(git describe --abbrev=0 --tags 2>/dev/null)
latest=${latest:-v0.0.0}
components=(${latest//./ })

这是您的第一个 bash-ism:您正在用用空格替换点(然后分解)的值制作一个数组。 Plain shell 没有数组;相反,我们使用位置参数,用 $IFS 分解它们,使用 set。为了保持干净,我们需要在一个函数中使用它(每个函数都有自己的私有位置),但是如果所有位置参数都已经被捕获到局部变量中,我们可以覆盖它们:

set -- $(echo $latest | sed "s/\./ /g")

(回到你的代码)

major=${components[0]}
major=${major//v/}
minor=${components[1]}
patch=${components[2]}

现在我们将在这里使用 $1、$2 和 $3。我们不妨将 v 替换移动到上面的 sed 中(POSIX sh 可以执行此替换,但我说让 sed 执行它,因为它更明显 and/or 更有效):

set -- $(echo $latest | sed -e s/v// -e "s/\./ /g")
major=
minor=
patch=

回到你原来的代码:

major=$((major+1))
minor=0
patch=0
next='v'$major'.'$minor'.'$patch
git tag -a $next -m ""

这都是有效的 POSIX sh,所以我们完成了这个转换。