使用Python子进程模块进行git filter-branch

3 投票
2 回答
796 浏览
提问于 2025-04-17 12:07

我正在尝试写一个脚本,帮助我把一些旧用户映射到几个Git仓库中的新用户。现在我遇到的问题是关于subprocess模块的。像“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中执行,所有的东西都能正常工作。任何帮助或建议都将非常感激。

2 个回答

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)
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"这个选项。

撰写回答