简体   繁体   English

使用git-filter-branch重命名提交作者的便捷脚本

[英]Convenience script for renaming commit authors with git-filter-branch

For convenience, everything in this post is runnable as a Bash command. 为方便起见,本文中的所有内容都可以作为Bash命令运行。

I have the following script based off of GitHub's own : 我有以下基于GitHub自己的 脚本

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

Yet, when I run the script on a test repository I've set up: 然而,当我在测试存储库上运行脚本时,我已经设置了:

git clone https://gist.github.com/dc896ccd9a272a126436.git
cd dc896ccd9a272a126436
git-unite "Test Author" "new@email.com" "hehe2" "hehe"

nothing is changed. 没有任何改变。 What is the trouble? 有什么麻烦?

 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 , the problem can be solved. 使用出口 ,问题可以解决。 Is there any way to do this without exporting these variables? 有没有办法在不导出这些变量的情况下这样做?

If you need to "inject" the $name and $email , you can export it before git filter-branch , or you can generate a bash script using printf . 如果你需要“注入” $name$email ,你可以 git filter-branch 之前导出它,或者你可以使用printf生成一个bash脚本。

Notice: the $(echo $old_email) does the same result than using "$old_email" and you could fork a process for nothing (well, if bash fork when you use builtins). 注意: $(echo $old_email)与使用"$old_email"结果相同,你可以在没有任何东西的情况下分叉一个进程(好吧,如果使用内置"$old_email" ,则使用bash fork)。

You can also use printf : the idea is to use the %q to dump the different variable in a quoted form (suitable for use in a bash script, or in eval). 您还可以使用printf :我们的想法是使用%q以引用形式转储不同的变量(适合在bash脚本或eval中使用)。 You also gain the advantage to split the script that effectively change the user name/email from the one that run the git command. 您还可以获得分割脚本的优势,该脚本可以有效地更改运行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

And in your script: 在你的脚本中:

git filter-branch --force --env-filter $(printf "$(<action.bash)" \
   "$name" "$email" "$old_email") --tag-name-filter cat -- --branches --tags

Notice: 注意:

  1. $(<foobar) does the same work that cat foobar does. $(<foobar)cat foobar做的工作相同。 When you use cat , you might however except bash to create a sub-process instead of just reading the file foobar . 当你使用cat ,除了bash之外你可能会创建一个子进程而不是只读取文件foobar
  2. I truncated the git filter-branch (the \\ ) line to avoid horizontal scrollbars. 我截断了git filter-branch\\ )行以避免水平滚动条。

This example is fine, but after thinking about it a little, I think you should not do it like that, but in a more bash way: 这个例子很好,但在考虑了一点之后,我认为你不应该这样做,但是以更猛烈的方式:

#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

And instead: 而是:

git filter-branch --force --env-filter "$(printf 'action.bash "%q" "%q" "%q"' \
   "$name" "$email" "$old_email")" --tag-name-filter cat -- --branches --tags

That way, even if the script does nothing at all, it would still work if you needed it in a static way: 这样,即使脚本什么都不做,如果您以静态方式需要它,它仍然可以工作:

git filter-branch --force --env-filter 'action.bash name email old_email' \
  --tag-name-filter cat -- --branches --tags

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM