Python Git模块的经验?[关闭]


172

人们对Python的任何Git模块有何经验?(我知道GitPython,PyGit和Dulwich-如果您知道其他人,请随意提及。)

我正在编写一个程序,该程序必须与Git存储库进行交互(添加,删除,提交),但是没有使用Git的经验,所以我要寻找的一件事是关于Git的易用性/理解性。

我主要感兴趣的其他内容是库的成熟度和完整性,合理的错误缺失,持续的开发以及文档和开发人员的帮助。

如果您有其他我想/需要知道的事情,请随时提及。


25
我们可以把这个问题变成社区维基吗?我觉得最好的答案会随着时间而改变。
转租

4
@relet:只要关闭,就不能成为Wiki。
PTBNL

Answers:


119

虽然这个问题是在不久前提出的,但我当时还不知道库的状态,但是值得搜索的人提到,GitPython在抽象命令行工具方面做得很好,因此您无需使用子流程。您可以使用一些有用的内置抽象,但是对于其他所有事情,您都可以执行以下操作:

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工具的包装。

更新:我已经切换到不仅使用git,而且还使用python中需要的大多数命令行实用程序使用sh模块。为了复制上面的内容,我将改为执行以下操作:

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()


9
基于这个答案,我刚刚尝试了git-python的运气。我觉得该API很奇怪。在大多数情况下,您必须退回到repo.git。*常规接口,即使这样有时也无法正常工作(例如,repo.git.branch(b=somebranch)可以工作,但repo.git.branch(D=somebranch)由于缺少空格而无法正常工作)。我想我会自己实现一个基于子流程的通用功能。我很难过,我寄予厚望。:-/
Christoph

6
我现在已经切换到使用sh模块git = sh.git.bake(_cwd=repopath)。它很棒。
2013年

10
链接到sh:amoffat.github.io/sh 确实应该是python stdlib的一部分。
g33kz0r 2013年

4
最新的python sh版本在Windows上不起作用。完全失败。
void.pointer 2014年

80

我以为我会回答自己的问题,因为我所采取的途径与答案中所建议的不同。尽管如此,感谢那些回答。

首先,简要介绍一下我在GitPython,PyGit和Dulwich的经验:

  • GitPython:下载后,我将其导入并初始化了适当的对象。但是,尝试执行本教程中建议的操作会导致错误。缺乏更多文档,我转向其他地方。
  • PyGit:这甚至都不会导入,而且我找不到任何文档。
  • 德威:似乎是最有前途的(至少就我想要和看到的而言)。与GitPython相比,我在其中取得了一些进步,因为它的卵来自Python源。但是,过了一会儿,我决定尝试做一下可能会更容易。

同样,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')

这还没有完全集成到我的程序中,但是除了速度(我有时会处理数百甚至数千个文件)之外,我没有预料到任何问题。

也许我只是没有耐心让Dulwich或GitPython正常运行。就是说,我希望这些模块能够得到更多的开发并且很快会有用。


25
这个答案越来越老了。
亚历克斯·张伯伦

3
是的,我会对更新​​感兴趣。
JosefAssad 2012年

GitPython工作得很好,并有大量文档记录。
亚瑟

1
@Arthur我不同意,因为我至少要花3个小时阅读StackOverflow和GitPython文档,才能了解git pull,add,commit和push到使用它的远程仓库的基础。该文档的确有一些高级用例,但缺少非常基本的用例。我基本上是放弃并使用子流程。
Daniel Lavedonio de Lima

30

我建议pygit2-它使用出色的libgit2绑定


1
它也为git管道提供了最佳访问。
pielgrzym 2012年

pygit2是一个非常有用的库,我希望它将来能够扩展!
亚历克斯·张伯伦

2
现在,必须手动下载和编译/设置和的半稳定版本,libgitpygit2从GitHub中获取源代码。问题是,分支机构的测试失败,并且最新的“稳定”安装失败...如果可靠性很重要并且您需要在各种环境中进行部署,则不是合适的解决方案... :(
mac

1
如果您曾经计划使用cygwin的客户,请远离这种组合。pygit2是libgit2的包装器,而libgit2删除了所有cygwin支持。我从一位开发人员那里得到的评论是:“您可以尝试,但是如果它可以构建,这将是一个奇迹”漂亮的API,是的,但是我一半的客户是cygwin,因此我无法使用它。可能要去GitPython了。
scphantm

2
请注意,他们不支持cygwin,因为他们的重点是对Windows的本机支持。因此,虽然cygwin不支持libgit2是正确的,但这并不意味着Windows用户会被冷落。
熊加米奥夫

19

这是一个非常老的问题,在寻找Git库时,我发现了今年(2013年)制造的一个名为Gittle的库

它对我很有用(我尝试过的其他地方都比较薄弱),而且似乎涵盖了大多数常见操作。

自述文件中的一些示例:

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()

2
我不喜欢您“登台”文件,而不是“添加”文件到索引。更改常用/重要操作的名称似乎很令人困惑。
2014年

3
@underrun添加是将文件添加到舞台。暂存文件不是吗?
吉米·凯恩

添加文件是暂存要提交的文件(它将文件添加到索引中)。操作是相同的,但是在命令行中您将键入,git add other1.txt other2.txt因此不会遵循预期。
2014年

1
同意这种包装的优越性。安装StaSh打包后,我什至可以在Pythonista应用程序中使用它。另外,值得注意的是,您的答案是该问题答案中最新的。
克里斯·雷德福德

1
实际上,它似乎对我适用于Pythonista。最终我放弃了将它用作密码来认证我的Mac上一个私人bitbucket存储库克隆的克隆。
克里斯·雷德福德

17

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

Dulwich在某种意义上可能与另一个有所不同,因为它是python中git的重新实现。另一个可能只是Git命令的包装器(因此从较高的角度来看,它可能更易于使用:commit / add / delete),这可能意味着它们的API与git的命令行非常接近,因此您需要获得有关Git的经验。


答案非常有用,我不知道Mercurial使用德威,谢谢!
kissgyorgy

7

更新的答案反映了更改的时间:

GitPython当前是最容易使用的。它支持许多git plumbing命令的包装,并具有可插入的对象数据库(其中的一个是德威奇),并且如果未实现命令,则提供了一个简单的api,可以用于命令行。例如:

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

这调用:

bash$ git checkout -b new_branch

德威也不错,但水平要低得多。使用它有点痛苦,因为它需要在管道级上对git对象进行操作,并且没有通常想要的精美瓷器。但是,如果您打算修改git的任何部分,或者使用git-receive-pack和git-upload-pack,则需要使用dulwich。



2

这是“ 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() )

5
我不建议您解析git status
Ehtesh Choudhury 2011年

1
解析git status --short会更容易,而且我认为--short输出更改的可能性较小。
本·佩奇

2
git status --porcelain用于此用途--porcelain: Give the output in a stable, easy-to-parse format for scripts...
estani 2012年

甚至更好,使用--z代替--porcelain。不同于--porcelain--z不会转义文件名。
Vojislav Stojkovic

2

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)

4
我看到很多代码重复...:p
Ciasto piekarz 2014年

0

StGit的git交互库部分实际上非常好。但是,它不是作为单独的软件包分解的,但是,如果有足够的兴趣,我相信可以解决。

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


-3

记录下来,前面提到的Git Python库似乎都没有包含“ git status”等效项,这实际上是我唯一想要的,因为通过子进程处理其余git命令非常容易。


3
使用GitPython:git.Repo(repoDir).git.status()
欠载
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.