2014-09-10 34 views
1

爲方便起見,本文中的所有內容均可作爲Bash命令運行。使用git-filter-branch重命名提交作者的便捷腳本

我有一個基於關的GitHub's ownfollowing script

cat <<EOF > git-unite 
#!/usr/bin/env bash 

# Usage: 
# 
# git-unite "User Name" "[email protected]" \ 
#   "[email protected]" \ 
#   "[email protected]" \ 
#   ... 

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" "[email protected]" "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

如果您從該過濾器分支腳本中打印出'$ email',它是否有任何價值? (爲什麼'$(echo $ name)'和'$(echo $ email)'而不是'$ name'和'$ email'?) – 2014-09-10 19:26:36

+0

我之前沒有使用'echo',但它沒有工作。我相信這是因爲命令是在某種子shell中運行的(我並不真正知道這裏的術語),並且這些變量都丟失了。我寧願不將它們導出,因爲它們對其他人沒有意義。經過測試,似乎'$ email'是空的,無論如何。 – 2014-09-10 19:29:22

+0

當我導出時,'name'仍然是空的,我得到空的ident錯誤。 – 2014-09-10 19:31:32

回答

3

如果你需要「注入」的$name$email,你可以將其導出之前git filter-branch,或者您也可以使用產生一個printf bash腳本。

注意:$(echo $old_email)做了同樣的結果比使用"$old_email",你可以創建一個進程白白(當然,如果bash的叉子當您使用內建)。

您也可以使用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 

注意:

  1. $(<foobar)做了同樣的工作,cat foobar一樣。當你使用cat時,你可能會除了bash創建一個子進程而不是僅僅讀取文件foobar
  2. 我截斷了git filter-branch\)行以避免橫向滾動條。

這個例子是好的,但想着這一點後,我想你不應該那樣做,但在更多的bash方式:

#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 

這樣一來,即使腳本做什麼都沒有,它仍然會如果你需要它以靜態方式工作

+0

是的,這基本上是一個引用問題。我沒有時間寫一個完整的備選答案,只是注意'--env-filter'... $ x''在單引號內有'$ x',這使得它不能被擴展。 – torek 2014-09-10 19:41:36

+0

謝謝!問題:這是今天我第二次看到'$( 2014-09-10 19:43:55

+2

與'貓'相同。 – NoDataFound 2014-09-10 19:46:10