如何使用 GitPython 进行拉取?

Rbt*_*tnk 3 python git gitpython

我正在使用 GitPython 从 Gitlab 服务器克隆存储库。

git.Repo.clone_from(gitlab_ssh_URL, local_path)
Run Code Online (Sandbox Code Playgroud)

后来我有另一个脚本试图更新这个 repo。

try:
    my_repo = git.Repo(local_path)
    my_repo .remotes.origin.pull()

except (git.exc.InvalidGitRepositoryError, git.exc.NoSuchPathError):
    print("Invalid repository: {}".format(local_path)
Run Code Online (Sandbox Code Playgroud)

这很好用,除非我在中间结帐这样的标签:

tag_id = choose_tag()    # Return the position of an existing tag in my_repo.tags
my_repo .head.reference = my_repo.tags[tag_id]
my_repo .head.reset(index=True, working_tree=True)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我在拉取时收到 GitCommandError:

git.exc.GitCommandError: 'git pull -v origin' returned with exit code 1
Run Code Online (Sandbox Code Playgroud)

我已经阅读了两次文档,但我不知道问题出在哪里。特别是因为如果我尝试使用像 SourceTree 这样的专用工具来拉这个 repo,它可以正常工作而不会出现错误或警告。我不明白即使使用分离的 HEAD 签出标记版本的事实如何阻止我拉。

  1. 在这种情况下我该怎么做才能拉?
  2. 这里发生了什么,我想念什么?

编辑:作为建议,我试图查看 exception.stdout 和 exception.sterr,这里没有任何用处(分别是 b'' 和 None)。这就是为什么我很难理解出了什么问题。

mbd*_*vpl 5

我认为最好首先了解更多关于正在发生的事情(问题 2:发生了什么?),这应该会引导您找到问题 1 的答案(如何解决这个问题?)。

要了解更多关于什么地方出了错,您可以打印出来stdout,并stderr从异常。Git 通常会将错误详细信息打印到控制台,因此某些内容应该在stdout或 中stderr

try:
    git.Repo.clone_from(gitlab_ssh_URL, local_path)
except git.GitCommandError as exception:
    print(exception)
    if exception.stdout:
        print('!! stdout was:')
        print(exception.stdout)
    if exception.stderr:
        print('!! stderr was:')
        print(exception.stderr)
Run Code Online (Sandbox Code Playgroud)

作为旁注,当我git.Repo在使用对象与后端(即它git本身)交互之前对对象进行许多操作时,我自己也遇到了一些问题。在我看来,有时 GitPython 端似乎存在一些数据缓存问题,并且存储库(.git目录)中的数据与git.Repo对象中的数据结构之间缺乏同步。

编辑

好的,问题似乎在于拉扯分离的头部 - 这可能不是你想要做的。

不过,您可以解决您的问题。因为从分离的头部你git checkout master只是为了做git pull然后你回到分离的头部,你可以跳过拉动,而是git fetch <remote> <source>:<destination>像这样使用:git fetch origin master:master。这将获取远程并将您的本地master分支与跟踪分支合并而无需检查它,因此您可以一直保持分离的头部状态而不会出现任何问题。有关 fetch 命令的非常规使用的更多详细信息,请参阅此 SO 答案:https : //stackoverflow.com/a/23941734/4973698

使用 GitPython,代码可能如下所示:

my_repo = git.Repo(local_path)
tag_id = choose_tag() # Return the position of an existing tag in my_repo.tags
my_repo.head.reference = my_repo.tags[tag_id]
my_repo.head.reset(index=True, working_tree=True)
fetch_info = my_repo.remotes.origin.fetch('master:master')
for info in fetch_info:
    print('{} {} {}'.format(info.ref, info.old_commit, info.flags))
Run Code Online (Sandbox Code Playgroud)

它会打印如下内容:

master 11249124f123a394132523513 64 
Run Code Online (Sandbox Code Playgroud)

... 所以标志相等64。这是什么意思?当你这样做时print(git.FetchInfo.FAST_FORWARD),结果是64这样意味着获取是快进类型的,因此你的本地分支成功地与远程跟踪分支合并,即你在git pull origin master没有检查主节点的情况下执行了。

重要提示:只有当您的分支可以使用快进合并与远程分支合并时,这种获取才有效。