如何以编程方式模拟解决与 GitPython 的合并冲突?

问题描述 投票:0回答:2

根据我最近关于“使用 GitPython 合并分支”的问题,我正在尝试对那里的解决方案进行单元测试。为此,我需要模拟用户打开合并工具,解决冲突并提交结果。 如果我使用 CLI 手动执行此操作,则一切似乎都有效:

echo 'Something to resolve the conflict' > conflicted_file.txt git add conflicted_file.txt git commit -m "Conflict resolved"

我尝试使用 GitPython 模拟相同的过程:

filename = 'conflicted_file.txt' with open(filename, 'w') as f: f.write('Some combined content which resolves the merge issue') # repo is a git.Repo instance repo.index.add([filename]) repo.index.commit("Simulating user resolving a conflict"+filename)

..但这对我来说只是一个例外:

Traceback (most recent call last): File "C:\Projects\grit\test_Gritter.py", line 240, in test_MergeConflicts repo.index.commit("Simulating user resolving a conflict"+filename) File "C:\Python34\lib\site-packages\git\index\base.py", line 934, in commit tree = self.write_tree() File "C:\Python34\lib\site-packages\git\index\base.py", line 531, in write_tree binsha, tree_items = write_tree_from_cache(entries, mdb, slice(0, len(entries))) File "C:\Python34\lib\site-packages\git\index\fun.py", line 234, in write_tree_from_cache raise UnmergedEntriesError(entry) git.exc.UnmergedEntriesError: 100644 fd05580faebf11aee13944da595112eced471664 2 conflicted_file.txt

我还需要将其标记为已解决吗?

编辑 - 关于我正在尝试自动化的更多背景知识

因此,为了清楚起见,我希望尽可能轻松地合并已更新到远程功能分支的远程主分支中的更改,从而解决任何合并冲突。

据我所知,正确的方法是:

创建本地功能分支
  1. 做一些改变
  2. 将我的更改推送到遥控器
  3. ...同时其他人将他们的更改合并到远程主控中,所以我现在需要将这些更改合并到我的功能分支中...
  4. 切换到master(在我本地结账时)
  5. 从远程主机拉取以更新我的本地副本
  6. 切换到我的本地功能分支
  7. 尝试合并
  8. 解决任何冲突
  9. 将合并推送到远程功能分支
  10. 我现在已经在一个 Python 脚本中完成了大部分内容,但是这个问题涉及的问题是模拟上述步骤中的步骤 9。

python git git-merge gitpython
2个回答
1
投票

最终,这成功了:

g = git.Git('my/repo') g.execute(["git","add","conflicted_file.txt"]) g.execute(["git","commit","-m", "Conflict resolved"])



0
投票

这里,

workdir

是一些临时目录,

repository_url
是你的存储库URL,
source_branch
是我们需要合并的地方,
target_branch
是我们需要合并的地方,
process_conflicts
是解决冲突的函数(例如,使用正确的内容更新冲突的文件)。
注意,这个示例显式创建了合并提交(就像使用 

--no-ff

一样),但当然可以根据需要更改为需要,只需在调用

no_ff=True
时删除
repo.heads[target_branch], 
.merge()
即可。
import os
import shutil

import git
from git.exc import GitCommandError
from git.remote import PushInfo, PushInfoList

# cleanup workdir
shutil.rmtree(workdir, ignore_errors=True)
os.makedirs(workdir, exist_ok=True)

# clone
repo: git.Repo = git.Repo.clone_from(
    url=repository_url, to_path=workdir, branch=target_branch, filter="blob:none"
)

# warm up working trees
repo.git.checkout(source_branch)
repo.git.checkout(target_branch)
message = "My fancy merge commit message"

# merge
try:
    repo.git.merge(
        [repo.heads[target_branch], repo.heads[source_branch]], no_ff=True, m=message
    )
except GitCommandError as ex:
    if not "CONFLICT" in ex.stdout:
        raise ex
    conflicted_files = [
        os.path.join(workdir, line.split(" ")[-1])
        for line in ex.stdout.split("\n")
        if line.startswith("CONFLICT")
    ]
    # here we process conflict, e.g. write new contents of our files
    process_conflicts(conflicted_files)

    # now for the magic part
    repo.index.reset()
    repo.index.add([workdir])
    repo.index.commit(
        message=message, 
        parent_commits=[repo.heads[target_branch].commit, repo.heads[source_branch].commit]  # type: ignore
    ) 

# all set, push it
push_result: PushInfoList = repo.remote("origin").push(target_branch)
push_result.raise_if_error()

© www.soinside.com 2019 - 2024. All rights reserved.