Python Git 模块体验?

人们对 Python 的 Git 模块有什么体验?(我知道 gitPython、 PyGit 和达利奇——如果你知道它们,请随意提及。)

我正在编写一个程序,它必须与 Git 存储库进行交互(添加、删除、提交) ,但是没有使用 Git 的经验,所以我想要的东西之一就是易于使用/理解 Git。

我主要感兴趣的其他事情是库的成熟性和完整性、合理的缺陷、持续的开发以及文档和开发人员的帮助。

如果你想到什么我可能想知道/需要知道的事情,请随时告诉我。

125057 次浏览

也许这会有所帮助,但是 Bazaar 和 Mercurial 都在使用 dulwich 来实现 Git 互操作性。

达利奇可能与其他的不同之处在于它是在 python 中重新实现了 git。另一个可能只是 Git 命令的一个包装器(所以从高层次的角度使用它可能更简单: 提交/添加/删除) ,这可能意味着他们的 API 非常接近 Git 的命令行,所以你需要获得使用 Git 的经验。

StGit 的 git 交互库部分实际上相当不错。然而,它不是作为一个单独的一揽子计划,但如果有足够的利息,我相信这是可以解决的。

它有非常好的抽象来表示提交、树等,以及创建新的提交和树。

我认为我应该回答我自己的问题,因为我正在走一条与答案中建议的不同的道路。尽管如此,还是要感谢那些接电话的人。

首先,简要概括一下我使用 gitPython、 PyGit 和达利奇的经历:

另外,StGit看起来很有趣,但是我需要将这些功能提取到一个单独的模块中,并且不希望等到现在才发生这种情况。

比起让上面的三个模块工作所花的时间要少得多,我设法让 git 命令通过子流程模块工作,例如。

def gitAdd(fileName, repoDir):
cmd = ['git', 'add', fileName]
p = subprocess.Popen(cmd, cwd=repoDir)
p.wait()


gitAdd('exampleFile.txt', '/usr/local/example_git_repo_dir')

这还没有完全融入到我的程序中,但是我并没有预料到会出现问题,除了速度(因为我会时不时地处理数百甚至数千个文件)。

也许我只是没有耐心去处理达利奇或者 gitPython 的事情。也就是说,我希望这些模块能够得到更多的开发,并且很快变得更加有用。

根据记录,前面提到的 Git Python 库似乎没有一个包含“ Git status”等价物,这实际上是我唯一想要的东西,因为通过子进程处理其余的 Git 命令非常容易。

为了完整起见,abc0是所有 dvcs 的抽象层。它使用达利奇,但提供与其他 dvcs 的互操作。

下面是“ git status”的一个快速实现:

import os
import string
from subprocess import *


repoDir = '/Users/foo/project'


def command(x):
return str(Popen(x.split(' '), stdout=PIPE).communicate()[0])


def rm_empty(L): return [l for l in L if (l and l!="")]


def getUntracked():
os.chdir(repoDir)
status = command("git status")
if "# Untracked files:" in status:
untf = status.split("# Untracked files:")[1][1:].split("\n")
return rm_empty([x[2:] for x in untf if string.strip(x) != "#" and x.startswith("#\t")])
else:
return []


def getNew():
os.chdir(repoDir)
status = command("git status").split("\n")
return [x[14:] for x in status if x.startswith("#\tnew file:   ")]


def getModified():
os.chdir(repoDir)
status = command("git status").split("\n")
return [x[14:] for x in status if x.startswith("#\tmodified:   ")]


print("Untracked:")
print( getUntracked() )
print("New:")
print( getNew() )
print("Modified:")
print( getModified() )

PTBNL 的答案对我来说非常完美。 我为 Windows 用户多做了一点。

import time
import subprocess
def gitAdd(fileName, repoDir):
cmd = 'git add ' + fileName
pipe = subprocess.Popen(cmd, shell=True, cwd=repoDir,stdout = subprocess.PIPE,stderr = subprocess.PIPE )
(out, error) = pipe.communicate()
print out,error
pipe.wait()
return


def gitCommit(commitMessage, repoDir):
cmd = 'git commit -am "%s"'%commitMessage
pipe = subprocess.Popen(cmd, shell=True, cwd=repoDir,stdout = subprocess.PIPE,stderr = subprocess.PIPE )
(out, error) = pipe.communicate()
print out,error
pipe.wait()
return
def gitPush(repoDir):
cmd = 'git push '
pipe = subprocess.Popen(cmd, shell=True, cwd=repoDir,stdout = subprocess.PIPE,stderr = subprocess.PIPE )
(out, error) = pipe.communicate()
pipe.wait()
return


temp=time.localtime(time.time())
uploaddate= str(temp[0])+'_'+str(temp[1])+'_'+str(temp[2])+'_'+str(temp[3])+'_'+str(temp[4])


repoDir='d:\\c_Billy\\vfat\\Programming\\Projector\\billyccm' # your git repository , windows your need to use double backslash for right directory.
gitAdd('.',repoDir )
gitCommit(uploaddate, repoDir)
gitPush(repoDir)

虽然这个问题已经提出一段时间了,我不知道当时库的状态,但是值得一提的是,GitPython 在抽象命令行工具方面做得很好,因此您不需要使用 subprocess。你可以使用一些有用的内置抽象,但是对于其他任何事情,你可以这样做:

import git
repo = git.Repo( '/home/me/repodir' )
print repo.git.status()
# checkout and track a remote branch
print repo.git.checkout( 'origin/somebranch', b='somebranch' )
# add a file
print repo.git.add( 'somefile' )
# commit
print repo.git.commit( m='my commit message' )
# now we are one commit ahead
print repo.git.status()

GitPython 其他地方的一切都让驾驶变得更加容易。我对这个库非常满意,并且感谢它是底层 git 工具的包装器。

更新 : 我已经切换到使用 sh 模块,不仅用于 git,还用于 Python 中需要的大多数命令行实用程序。为了复制上述情况,我会这样做:

import sh
git = sh.git.bake(_cwd='/home/me/repodir')
print git.status()
# checkout and track a remote branch
print git.checkout('-b', 'somebranch')
# add a file
print git.add('somefile')
# commit
print git.commit(m='my commit message')
# now we are one commit ahead
print git.status()

我建议使用 Pygit2-它使用优秀的 Libgit2绑定

反映时代变化的最新答案:

GitPython 目前是最容易使用的。它支持包装许多 git 管道命令,并具有可插入的对象数据库(多利奇是其中之一) ,如果一个命令没有实现,提供了一个简单的 api 支持命令行。例如:

repo = Repo('.')
repo.checkout(b='new_branch')

这叫做:

bash$ git checkout -b new_branch

达利奇也不错,但水平要低得多。使用起来有点痛苦,因为它需要在管道水平上对 Git 对象进行操作,而且没有你通常想要的漂亮瓷器。但是,如果您计划修改 git 的任何部分,或者使用 git 接收包和 git 上传包,则需要使用 ulwich。

这是一个相当古老的问题,在寻找 Git 库时,我发现了一个今年(2013年)制作的名为 小家伙的库。

它对我非常有效(我尝试过的其他方法都很古怪) ,而且似乎涵盖了大多数常见的行为。

一些来自 README 的例子:

from gittle import Gittle


# Clone a repository
repo_path = '/tmp/gittle_bare'
repo_url = 'git://github.com/FriendCode/gittle.git'
repo = Gittle.clone(repo_url, repo_path)


# Stage multiple files
repo.stage(['other1.txt', 'other2.txt'])


# Do the commit
repo.commit(name="Samy Pesse", email="samy@friendco.de", message="This is a commit")


# Authentication with RSA private key
key_file = open('/Users/Me/keys/rsa/private_rsa')
repo.auth(pkey=key_file)


# Do push
repo.push()