You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Gitlab提交创建功能遇文件重命名时失效问题求助

解决python-gitlab复制提交时文件重命名操作失败的问题

我通过GitLab派生(fork)创建了目标仓库,使用python-gitlab编写脚本同步源仓库的提交。脚本在处理文件修改、删除操作时能正常创建提交,但遇到文件重命名场景时失效,抛出错误:

gitlab.exceptions.GitlabCreateError: 400: A file with this name doesn't exist

原脚本代码:

def copying_commit():
    tag = source_project.tags.get('v0.0.8')
    commit_sha = tag.commit['id']
    source_commit = source_project.commits.get(commit_sha)
    destination_project = gl.projects.get(project_id)
    source_branch = 'sub_dev'

    # Initialize a list to store actions for the commit
    commit_actions = []

    # Iterate through file changes and accumulate actions
    for file_change in source_commit.diff():
        print(file_change)
        print(file_change['new_path'])
        print(file_change['old_path'])
        if file_change['deleted_file']:
            action_type = 'delete'
        elif file_change['new_file']:
            action_type = 'create'
        else:
            action_type = 'update'


        commit_actions.append({
            'action': action_type,
            'file_path': file_change['new_path'] if action_type != 'delete' else file_change['old_path'],
            'content': source_project.files.raw(file_path=file_change['new_path'],
                                                ref=source_branch_info.name).decode('UTF-8')
            if action_type != 'delete' else None
        })


    commit = destination_project.commits.create({
        'branch': 'sub_dev',
        'commit_message': f' v0.0.8 Merge changes from{source_project.web_url} {source_branch}',
        'actions': commit_actions
    })
    destination_project.tags.create({
        'tag_name': 'v0.0.8',  
        'ref': commit.id,
        'message': f'Tag v0.0.8 for commit {commit.id}'
    })

问题原因

GitLab提交的diff中,文件重命名会同时返回old_path和new_path,且deleted_file、new_file都为false。原脚本会将这种情况判定为update操作,但目标仓库中不存在new_path对应的文件,导致执行update时触发文件不存在的错误。另外,GitLab API支持专门的rename动作来处理文件重命名,不需要传入文件内容。

修改后的脚本

def copying_commit():
    tag = source_project.tags.get('v0.0.8')
    commit_sha = tag.commit['id']
    source_commit = source_project.commits.get(commit_sha)
    destination_project = gl.projects.get(project_id)
    source_branch = 'sub_dev'

    # Initialize a list to store actions for the commit
    commit_actions = []

    # Iterate through file changes and accumulate actions
    for file_change in source_commit.diff():
        print(file_change)
        print(file_change['new_path'])
        print(file_change['old_path'])
        
        # 判断是否为文件重命名
        if file_change['old_path'] != file_change['new_path'] and not file_change['deleted_file'] and not file_change['new_file']:
            action_type = 'rename'
            commit_actions.append({
                'action': action_type,
                'file_path': file_change['new_path'],
                'previous_path': file_change['old_path']
            })
        elif file_change['deleted_file']:
            action_type = 'delete'
            commit_actions.append({
                'action': action_type,
                'file_path': file_change['old_path']
            })
        elif file_change['new_file']:
            action_type = 'create'
            commit_actions.append({
                'action': action_type,
                'file_path': file_change['new_path'],
                'content': source_project.files.raw(file_path=file_change['new_path'],
                                                    ref=source_branch).decode('UTF-8')
            })
        else:
            action_type = 'update'
            commit_actions.append({
                'action': action_type,
                'file_path': file_change['new_path'],
                'content': source_project.files.raw(file_path=file_change['new_path'],
                                                    ref=source_branch).decode('UTF-8')
            })


    commit = destination_project.commits.create({
        'branch': 'sub_dev',
        'commit_message': f' v0.0.8 Merge changes from {source_project.web_url} {source_branch}',
        'actions': commit_actions
    })
    destination_project.tags.create({
        'tag_name': 'v0.0.8',  
        'ref': commit.id,
        'message': f'Tag v0.0.8 for commit {commit.id}'
    })

修改说明

  1. 新增文件重命名判断逻辑:当old_path与new_path不同,且既不是新文件也不是删除文件时,判定为重命名操作
  2. 重命名动作使用GitLab API的rename类型,只需指定新路径file_path和原路径previous_path,无需传入文件内容
  3. 拆分不同动作的处理逻辑,避免原脚本中content赋值的冗余判断,同时修正了原脚本中source_branch_info.name的笔误(改为source_branch)

内容的提问来源于stack exchange,提问作者Chitrangda Pandya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 10:40:23