如何在Python中调用“ git pull”?


77

使用github webhooks,我希望能够将任何更改拉到远程开发服务器。此刻,在适当的目录中时,git pull需要进行任何更改。但是,我不知道如何在Python中调用该函数。我尝试了以下方法:

import subprocess
process = subprocess.Popen("git pull", stdout=subprocess.PIPE)
output = process.communicate()[0]

但这导致以下错误

追溯(最近一次通话最后一次):init文件“ /usr/lib/python2.7/subprocess.py”中第1行的文件“”,init中的第679行 errread,errwrite的,)“ / usr / lib / python2”中的文件。 7 / subprocess.py“,行1249,在_execute_child中引发child_exception OSError:[Errno 2]没有这样的文件或目录

有没有一种方法可以在Python内部调用此bash命令?



4
@Brandon并非如此,还有许多其他解决方案,更好。
jleahy

1
git可执行文件是否在PATH中?

1
@jleahy,也许据我所知,celecnius实际上是在问“我如何运行bash命令”。这已经被问过很多次了。
ceptno 2013年

1
这是一个老问题,但是我认为subprocess.Popen现在有一个cwd关键字参数,它将在指定目录中执行命令。例如:subprocess.Popen(['git', 'pull', '-v', 'origin', 'master'], cwd='/path/to/git/repo', ...)
Sparrow1029

Answers:


143

您是否考虑过使用GitPython?它旨在为您处理所有这些废话。

import git 

g = git.cmd.Git(git_dir)
g.pull()

https://github.com/gitpython-developers/GitPython


7
git_dir是您拥有的任何源代码控制的目录(包含.git文件夹)
Mercury

它提示输入密码。我该如何传递密码?
拉维·香克·雷迪

您可以使用ssh建立密钥,因此不需要密码身份验证
acaruci

msg = g.pull()告诉你发生了什么。msg是,''或者'Updating ... Fast-forward README.md | 1 + 1 file changed, 1 insertion(+)'是否成功拉出,并且'Already up-to-date.'是否已经更新。
假设

3
这是使用GitPython的一种非常糟糕的方法-它几乎不处理任何垃圾,仅转换为subprocess.check_output(['git', 'pull'], cwd=git_dir),让您自己来解析“ git瓷”命令的输出,而您不应该这样做
Eric

48

subprocess.Popen需要程序名称和参数的列表。您要向其传递单个字符串,该字符串(具有默认值shell=False)等效于:

['git pull']

这意味着子进程尝试查找按字面意义命名的程序git pull,但未能成功:在Python 3.3中,您的代码引发异常FileNotFoundError: [Errno 2] No such file or directory: 'git pull'。而是传递一个列表,如下所示:

import subprocess
process = subprocess.Popen(["git", "pull"], stdout=subprocess.PIPE)
output = process.communicate()[0]

顺便说一下,在Python 2.7+中,您可以使用check_output便捷函数来简化此代码:

import subprocess
output = subprocess.check_output(["git", "pull"])

另外,要使用git功能,则无需调用git二进制文件(尽管简单且可移植)。考虑使用git-pythonDulwich


根据文档:“ args应该是程序参数的序列,或者是单个字符串。” (强调我的)。您确定吗,因为它适合我?

@poke是的,文档尚不清楚。如果要传递字符串,则必须传递shell=True
phihag 2013年

嗯,正如我所说,它仅对我而言subprocess.Popen("git pull", stdout=subprocess.PIPE).communicate()(在Windows上为3.3和2.7)起作用。-嗯,进一步阅读了一下,该文档解释,这只会在Unix上工作的时候没有传递任何参数..算了,然后^^

1
@poke虽然您对单字符串的情况是正确的,但我最初的解释是错误的。事实证明,你可以传递一个字符串,但(引用): If args is a string, the interpretation is platform-dependent。添加了更多详细信息。在Python 3.3中,错误消息要好得多。
phihag 2013年

需要autocrlf时,这在Windows上不起作用。从cmd调用git与从sh.exe调用git不同。自动crfl替换不会被使用,这就是为什么git status不起作用的原因
Tomas Kubes,2014年

19

使用GitPython接受的答案比直接使用更好subprocess

这种方法的问题在于,如果您想解析输出,最终会看到“瓷器”命令的结果,这是一个坏主意

以这种方式使用GitPython就像获得一个闪亮的新工具箱,然后将其用作将其固定在一起而不是内部工具的一堆螺丝钉。API的设计用途如下:

import git
repo = git.Repo('Path/to/repo')
repo.remotes.origin.pull()

如果要检查是否有所更改,可以使用

current = repo.head.commit
repo.remotes.origin.pull()
if current != repo.head.commit:
    print("It changed")

3

这是一个示例食谱,我在一个项目中一直在使用。同意尽管有多种方法可以做到这一点。:)

>>> import subprocess, shlex
>>> git_cmd = 'git status'
>>> kwargs = {}
>>> kwargs['stdout'] = subprocess.PIPE
>>> kwargs['stderr'] = subprocess.PIPE
>>> proc = subprocess.Popen(shlex.split(git_cmd), **kwargs)
>>> (stdout_str, stderr_str) = proc.communicate()
>>> return_code = proc.wait()

>>> print return_code
0

>>> print stdout_str
# On branch dev
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   file1
#   file2
nothing added to commit but untracked files present (use "git add" to track)

>>> print stderr_str

代码的问题是,您没有传递数组subprocess.Popen(),因此试图运行一个名为的二进制文件git pull。相反,它需要git在第一个参数为的情况下执行二进制文件pull,依此类推。


1
并不是split真正应该这样shlex.split,并且代码不必要地复杂-您不需要waitafter communicate,并且在大多数使用情况下,check_output已经具有正确的字符串。
phihag 2013年

根据我的需要,我使用wait()来收集进程的返回码。如果OP对返回码检查不感兴趣,则这是可选的。同意shlex.split虽然使用。是的,如果您对获取stdout或stderr不感兴趣,可以跳过这些内容。提供替代解决方案没什么错,它可以让您做更多的事情,而不是标准的python文档示例;)
Tuxdude 2013年

正如您所提到的,check_output仅从2.7开始才添加,所以我也需要在具有比python版本更早的python环境中运行脚本。
Tuxdude

虽然wait有效,但proc.pid更容易理解。而且由于check_output是纯Python,因此只需复制它就可以在较旧的Python版本上使用它。
phihag 2013年

哦太好了!是的,check_output似乎也更强大:)
Tuxdude

1

如果你正在使用Python 3.5+喜欢subprocess.runsubprocess.Popen了场景,它可以处理。例如:

import subprocess
subprocess.run(["git", "pull"], check=True, stdout=subprocess.PIPE).stdout

-3

尝试:

subprocess.Popen("git pull", stdout=subprocess.PIPE, shell=True)

3
但这会不必要地产生外壳,不是吗?
phihag 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.