使用Python subprocess模块和git filter-branch命令进行操作

3
我正在尝试编写一个脚本,帮助我将一些旧用户映射到少量的Git存储库中的新用户。我遇到的问题与子进程模块有关。简单的命令,如“git status”,似乎可以正常工作,但是更复杂的“git filter-branch”命令则失败了。
filter_history函数
def filter_history(old, new, name, repoPath):

command = """ filter-branch --env-filter '
        an="$GIT_AUTHOR_NAME"
        am="$GIT_AUTHOR_EMAIL"
        cn="$GIT_COMMITTER_NAME"
        cm="$GIT_COMMITTER_EMAIL"

        if [[ "$GIT_COMMITTER_EMAIL" == |old|* ]]
        then
            cn="|name|"
            cm="|new|"
        fi
        if [[ "$GIT_AUTHOR_EMAIL" == |old|* ]]
        then
            an="|name|"
            am="|new|"
        fi

        export GIT_AUTHOR_NAME="$an"
        export GIT_AUTHOR_EMAIL="$am"
        export GIT_COMMITTER_NAME="$cn"
        export GIT_COMMITTER_EMAIL="$cm"
    '
"""

#Do string replace
command = command.replace("|old|", old)
command = command.replace("|new|", new)
command = command.replace("|name|", name)

subprocess.Popen(['/usr/bin/git', command], cwd=os.path.dirname(repoPath), shell=False)

一些示例输出:

fatal: cannot exec 'git- filter-branch --env-filter '
        an="$GIT_AUTHOR_NAME"
        am="$GIT_AUTHOR_EMAIL"
        cn="$GIT_COMMITTER_NAME"
        cm="$GIT_COMMITTER_EMAIL"

        if [[ "$GIT_COMMITTER_EMAIL" == jacks* ]]
        then
            cn="Jack Slingerland"
            cm="jacks-teamddm"
        fi
        if [[ "$GIT_AUTHOR_EMAIL" == jacks* ]]
        then
            an="Jack Slingerland"
            am="jacks-teamddm"
        fi

        export GIT_AUTHOR_NAME="$an"
        export GIT_AUTHOR_EMAIL="$am"
        export GIT_COMMITTER_NAME="$cn"
        export GIT_COMMITTER_EMAIL="$cm"
    '
': File name too long

我注意到一些事情,就是在git命令后面添加了一个连字符,这对我来说不太合理。另外,如果我从打印的命令中删除额外的连字符并在repoPath中执行它,一切都正常。如有任何帮助或指导将不胜感激。


@VonC 我将命令更改为在每行后包括反引号,但似乎没有任何变化。 - Jack Slingerland
反引号(http://en.wikipedia.org/wiki/Backtick)?我在想反斜杠(\:http://en.wikipedia.org/wiki/Backslash),不是反引号。 - VonC
@VonC “按我的想法做,不要照我打的。” 添加反斜杠没有帮助。相反,它只会使命令折叠成一行,这并不受 Bash 的喜爱。 - Jack Slingerland
@对...我应该在完成其他任务时打注释,抱歉。我没有看到我的初始注释。既然问题仍然存在,你尝试过其他方法吗?比如将 --env-filter 参数外部化到一个外部脚本中?(和/或极大地简化脚本以查看错误信息是否仍然存在?) - VonC
2个回答

2
这应该可以正常工作:(我正在使用Linux)
def filter_history(old, new, name, repoPath):
    command = """'
        an="$GIT_AUTHOR_NAME"
        am="$GIT_AUTHOR_EMAIL"
        cn="$GIT_COMMITTER_NAME"
        cm="$GIT_COMMITTER_EMAIL"

        if [[ "$GIT_COMMITTER_EMAIL" == |old|* ]]
        then
            cn="|name|"
            cm="|new|"
        fi
        if [[ "$GIT_AUTHOR_EMAIL" == |old|* ]]
        then
            an="|name|"
            am="|new|"
        fi

        export GIT_AUTHOR_NAME="$an"
        export GIT_AUTHOR_EMAIL="$am"
        export GIT_COMMITTER_NAME="$cn"
        export GIT_COMMITTER_EMAIL="$cm"
    '
    """

#Do string replace
    command = command.replace("|old|", old)
    command = command.replace("|new|", new)
    command = command.replace("|name|", name)

    subprocess.Popen(['git filter-branch --env-filter', command],cwd=os.path.dirname(repoPath), shell=True)

请注意,在subprocess.Popen函数中使用"shell=True"。

1

对于任何来到这里的人,我想提供一些信息。@xueyymusic 给出了最接近的答案。最终我使用了以下代码:

def filter_history(old, new, name, repoPath):

command = """--env-filter '
        an="$GIT_AUTHOR_NAME"
        am="$GIT_AUTHOR_EMAIL"
        cn="$GIT_COMMITTER_NAME"
        cm="$GIT_COMMITTER_EMAIL"

        if [[ "$GIT_COMMITTER_EMAIL" == |old|* ]]
        then
            cn="|name|"
            cm="|new|"
        fi

        if [[ "$GIT_AUTHOR_EMAIL" == |old|* ]]
        then
            an="|name|"
            am="|new|"
        fi

        export GIT_AUTHOR_NAME="$an"
        export GIT_AUTHOR_EMAIL="$am"
        export GIT_COMMITTER_NAME="$cn"
        export GIT_COMMITTER_EMAIL="$cm"
'
"""

#DO string replace
command = command.replace("|old|", old)
command = command.replace("|new|", new)
command = command.replace("|name|", name)

process = subprocess.Popen(['git filter-branch', command],cwd=os.path.dirname(repoPath), shell=True)

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