为方便起见,本文中的所有内容都可以作为Bash命令运行。
我的following script基于GitHub's own:
cat <<EOF > git-unite
#!/usr/bin/env bash
# Usage:
#
# git-unite "User Name" "new@email.com" \
# "old1@email.com" \
# "old2@email.com" \
# ...
name="$1"
email="$2"
git config user.name "$name"
git config user.email "$email"
shift 2
for old_email in $*; do
echo "changing $old_email"
git filter-branch --force --env-filter '
if [ "$GIT_COMMITTER_EMAIL" = "$(echo $old_email)" ]
then
export GIT_COMMITTER_NAME="$(echo $name)"
export GIT_COMMITTER_EMAIL="$(echo $email)"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$(echo $old_email)" ]
then
export GIT_AUTHOR_NAME="$(echo $name)"
export GIT_AUTHOR_EMAIL="$(echo $email)"
fi
' --tag-name-filter cat -- --branches --tags
done
EOF
chmod u+x git-unite
然而,当我在test repository上运行脚本时,我已经设置了:
git clone https://gist.github.com/dc896ccd9a272a126436.git
cd dc896ccd9a272a126436
git-unite "Test Author" "new@email.com" "hehe2" "hehe"
没有任何改变。有什么麻烦?
changing hehe2 Rewrite be8d35aca918caaa86035ab8f8011d5ff6131939 (3/3) WARNING: Ref 'refs/heads/master' is unchanged changing hehe Rewrite be8d35aca918caaa86035ab8f8011d5ff6131939 (3/3) WARNING: Ref 'refs/heads/master' is unchanged
Using exports,问题可以解决。有没有办法在不导出这些变量的情况下做到这一点?
答案 0 :(得分:3)
如果你需要&#34;注射&#34; $name
和$email
,您可以在 git filter-branch
之前将其导出,或者您可以使用printf
生成bash脚本。
注意: $(echo $old_email)
与使用"$old_email"
的结果相同,您可以无需分叉进程(如果使用内置函数,则使用bash fork)。< / p>
您还可以使用printf
:我的想法是使用%q
以引用形式转储不同的变量(适合在bash脚本或eval中使用)。您还可以利用分割脚本来有效地更改运行git命令的用户名/电子邮件。
#action.bash:
declare -r _NEW_NAME="%q"
declare -r _NEW_EMAIL="%q"
declare -r _OLD_EMAIL="%q"
if [ "$GIT_COMMITTER_EMAIL" = %v ]
then
export GIT_COMMITTER_NAME="${_NEW_NAME}"
export GIT_COMMITTER_EMAIL="${_NEW_EMAIL}"
fi
if [ "$GIT_AUTHOR_EMAIL" = "${_OLD_EMAIL}" ]
then
export GIT_AUTHOR_NAME="${_NEW_NAME}"
export GIT_AUTHOR_EMAIL="${_NEW_EMAIL}"
fi
在你的剧本中:
git filter-branch --force --env-filter $(printf "$(<action.bash)" \
"$name" "$email" "$old_email") --tag-name-filter cat -- --branches --tags
<强>注意:强>
$(<foobar)
执行与cat foobar
相同的工作。当您使用cat
时,除了bash之外,您可以创建一个子流程,而不只是阅读文件foobar
。git filter-branch
(\
)行以避免水平滚动条。 这个例子很好,但在考虑了一下之后,我认为你不应该这样做,而是以更猛烈的方式:
#action.bash:
declare -r _NEW_NAME="$1"
declare -r _NEW_EMAIL="$2"
declare -r _OLD_EMAIL="$3"
if [ "$GIT_COMMITTER_EMAIL" = %v ]
then
export GIT_COMMITTER_NAME="${_NEW_NAME}"
export GIT_COMMITTER_EMAIL="${_NEW_EMAIL}"
fi
if [ "$GIT_AUTHOR_EMAIL" = "${_OLD_EMAIL}" ]
then
export GIT_AUTHOR_NAME="${_NEW_NAME}"
export GIT_AUTHOR_EMAIL="${_NEW_EMAIL}"
fi
而是:
git filter-branch --force --env-filter "$(printf 'action.bash "%q" "%q" "%q"' \
"$name" "$email" "$old_email")" --tag-name-filter cat -- --branches --tags
这样,即使脚本什么都不做,如果您以静态方式需要它,它仍然可以工作:
git filter-branch --force --env-filter 'action.bash name email old_email' \
--tag-name-filter cat -- --branches --tags