Trải nghiệm mô-đun Python Git? [đóng cửa]


172

Trải nghiệm của mọi người với bất kỳ mô-đun Git nào cho Python? (Tôi biết về GitPython, PyGit và Dulwich - vui lòng đề cập đến những người khác nếu bạn biết về họ.)

Tôi đang viết một chương trình sẽ phải tương tác (thêm, xóa, cam kết) với kho Git, nhưng không có kinh nghiệm với Git, vì vậy một trong những điều tôi đang tìm kiếm là dễ sử dụng / hiểu về Git.

Những thứ khác tôi chủ yếu quan tâm là sự trưởng thành và đầy đủ của thư viện, thiếu lỗi hợp lý, tiếp tục phát triển và sự hữu ích của tài liệu và nhà phát triển.

Nếu bạn nghĩ về điều gì khác mà tôi có thể muốn / cần biết, xin vui lòng đề cập đến nó.


25
Chúng ta có thể biến câu hỏi này thành wiki cộng đồng không? Tôi cảm thấy câu trả lời tốt nhất sẽ thay đổi theo thời gian.
relet

4
@relet: Không thể tạo wiki miễn là nó bị đóng.
PTBNL

Câu trả lời:


119

Mặc dù câu hỏi này đã được hỏi cách đây một thời gian và tôi không biết trạng thái của các thư viện vào thời điểm đó, điều đáng nói với những người tìm kiếm là GitPython thực hiện tốt việc trừu tượng hóa các công cụ dòng lệnh để bạn không cần sử dụng quy trình con. Có một số tóm tắt hữu ích mà bạn có thể sử dụng, nhưng đối với mọi thứ khác, bạn có thể làm những việc như:

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

Mọi thứ khác trong GitPython chỉ giúp điều hướng dễ dàng hơn. Tôi khá hài lòng với thư viện này và đánh giá cao rằng nó là một trình bao bọc trên các công cụ git cơ bản.

CẬP NHẬT : Tôi đã chuyển sang sử dụng mô-đun sh không chỉ cho git mà hầu hết các tiện ích dòng lệnh tôi cần trong python. Để nhân rộng ở trên, tôi sẽ làm điều này thay vào đó:

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

2
Công cụ Legit tuyệt vời sử dụng GitPython: github.com/kennethreitz/legit/blob/develop/legit/scm.py
forivall

9
Dựa trên câu trả lời này, tôi vừa thử vận ​​may với git-python. Tôi thấy API lạ để giải quyết. Hầu hết thời gian bạn phải quay lại giao diện repo.git. * Và thậm chí đôi khi nó không hoạt động chính xác (ví dụ: repo.git.branch(b=somebranch)hoạt động nhưngrepo.git.branch(D=somebranch) không vì thiếu một khoảng trống). Tôi đoán tôi sẽ tự thực hiện một chức năng chung dựa trên quy trình con. Tôi buồn, tôi đã hy vọng cao. : - /
Christoph

6
Tôi đã chuyển sang sử dụng mô-đun sh bây giờ với git = sh.git.bake(_cwd=repopath). nó hoạt động khủng khiếp
underrun

10
liên kết đến sh: amoffat.github.io/sh thực sự nên là một phần của python stdlib.
g33kz0r

4
Phiên bản python sh mới nhất không hoạt động trên Windows. Hoàn toàn thất bại.
void.pulum

81

Tôi nghĩ rằng tôi sẽ trả lời câu hỏi của riêng mình, vì tôi đang đi một con đường khác với đề xuất trong câu trả lời. Tuy nhiên, cảm ơn những người đã trả lời.

Đầu tiên, một bản tóm tắt ngắn gọn về những trải nghiệm của tôi với GitPython, PyGit và Dulwich:

  • GitPython : Sau khi tải xuống, tôi đã nhập cái này và đối tượng thích hợp được khởi tạo. Tuy nhiên, cố gắng làm những gì được đề xuất trong hướng dẫn đã dẫn đến lỗi. Thiếu thêm tài liệu, tôi chuyển sang nơi khác.
  • PyGit : Điều này thậm chí sẽ không nhập và tôi không thể tìm thấy tài liệu nào.
  • Dulwich : Có vẻ là hứa hẹn nhất (ít nhất là cho những gì tôi muốn và thấy). Tôi đã thực hiện một số tiến bộ với nó, hơn cả với GitPython, vì trứng của nó đi kèm với nguồn Python. Tuy nhiên, sau một thời gian, tôi quyết định có thể dễ dàng hơn để thử những gì tôi đã làm.

Ngoài ra, StGit có vẻ thú vị, nhưng tôi sẽ cần chức năng được trích xuất thành một mô-đun riêng biệt và không muốn chờ đợi điều đó xảy ra ngay bây giờ.

Trong (nhiều) ít thời gian hơn tôi đã cố gắng để làm cho ba mô-đun ở trên hoạt động, tôi đã quản lý để có được các lệnh git hoạt động thông qua mô-đun quy trình con, ví dụ:

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

Điều này chưa được tích hợp hoàn toàn vào chương trình của tôi, nhưng tôi không lường trước được vấn đề, ngoại trừ có thể là tốc độ (vì tôi sẽ xử lý hàng trăm hoặc thậm chí hàng nghìn tệp mỗi lần).

Có lẽ tôi không đủ kiên nhẫn để làm mọi thứ với Dulwich hoặc GitPython. Điều đó nói rằng, tôi hy vọng các mô-đun sẽ được phát triển nhiều hơn và sớm hữu ích hơn.


25
Câu trả lời này đang già đi.
Alex Chamberlain

3
Có, tôi sẽ quan tâm đến một bản cập nhật.
JosefAssad

GitPython hoạt động rất tốt và được ghi lại rộng rãi.
Arthur

1
@Arthur Tôi không đồng ý, vì tôi có ít nhất 3 giờ vào tài liệu StackOverflow và GitPython chỉ để hiểu những điều cơ bản về git pull, thêm, cam kết và đẩy vào repo từ xa bằng cách sử dụng nó. Các tài liệu có một số trường hợp sử dụng nâng cao, nhưng thiếu cơ bản. Về cơ bản, tôi đang từ bỏ và sử dụng quy trình con.
Daniel Lavedonio de Lima

31

Tôi muốn giới thiệu pygit2 - nó sử dụng các liên kết libgit2 tuyệt vời


1
Nó cho phép truy cập tốt nhất để hệ thống ống nước git cũng.
pielgrzym

pygit2là một thư viện thực sự hữu ích và tôi mong muốn nó sẽ mở rộng trong tương lai!
Alex Chamberlain

2
Như hiện tại, người ta phải tải xuống thủ công và biên dịch / thiết lập các phiên bản bán ổn định của cả hai libgitpygit2, lấy nguồn từ GitHub. Vấn đề là, các nhánh đầu đã thử nghiệm bị hỏng và cài đặt thất bại "ổn định" mới nhất ... Không phải là giải pháp phù hợp nếu độ tin cậy là quan trọng và bạn cần triển khai trong nhiều môi trường khác nhau ... :(
mac

1
tránh xa sự kết hợp này nếu bạn từng có kế hoạch cho khách hàng sử dụng cygwin. pygit2 là một trình bao bọc cho libgit2 và libgit2 đã bỏ tất cả hỗ trợ cygwin. Nhận xét tôi nhận được từ một trong những nhà phát triển, "Bạn có thể thử, nhưng thật kỳ diệu nếu nó xây dựng" API đẹp, vâng, nhưng một nửa khách hàng của tôi là cygwin do đó tôi không thể sử dụng nó. Có lẽ sẽ đến GitPython.
scphantm

2
Lưu ý rằng họ không hỗ trợ cygwin vì trọng tâm của họ là hỗ trợ Windows gốc . Vì vậy, mặc dù đúng là libgit2 không được hỗ trợ trên cygwin, nhưng điều đó không có nghĩa là người dùng Windows bị bỏ rơi trong giá lạnh.
Xiong Chiamiov

19

Đây là một câu hỏi khá cũ và trong khi tìm kiếm các thư viện Git, tôi đã tìm thấy một câu hỏi được thực hiện trong năm nay (2013) có tên là Gittle .

Nó hoạt động rất tốt đối với tôi (nơi mà những người khác tôi đã thử là không ổn), và dường như bao trùm hầu hết các hành động thông thường.

Một số ví dụ từ 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()

2
Tôi không thích rằng bạn "giai đoạn" các tập tin thay vì "thêm" chúng vào chỉ mục. thay đổi tên của các hoạt động phổ biến / quan trọng có vẻ như sẽ gây nhầm lẫn.
underrun

3
@underrun thêm là thêm tập tin vào giai đoạn. Điều đó không giống với các tập tin dàn sao?
Jimmy Kane

việc thêm tệp là sắp xếp các tệp được cam kết (đó là thêm chúng vào chỉ mục). Hoạt động là như nhau nhưng tại dòng lệnh bạn sẽ nhập git add other1.txt other2.txtđể nó không tuân theo những gì được mong đợi.
underrun

1
Đồng ý về tính ưu việt của gói này. Tôi thậm chí đã có thể sử dụng nó trong ứng dụng Pythonista sau khi cài đặt StaSh, ứng dụng được đóng gói. Ngoài ra, điều đáng chú ý là câu trả lời của bạn được cập nhật gần đây nhất trong số các câu trả lời cho câu hỏi này.
Chris Redford

1
Trên thực tế, nó dường như chỉ hoạt động với tôi trên Pythonista. Bắt nó với mật khẩu xác thực một bản sao của repo bitbucket riêng trên máy Mac của tôi là một cơn ác mộng cuối cùng tôi đã từ bỏ.
Chris Redford

17

Có thể nó giúp, nhưng Bazaar và Mercurial đều sử dụng dulwich cho khả năng tương tác Git của họ.

Dulwich có lẽ khác với người khác theo nghĩa đó là sự tái hiện của git trong trăn. Cái kia có thể chỉ là một trình bao bọc xung quanh các lệnh của Git (vì vậy có thể sử dụng đơn giản hơn từ quan điểm cấp cao: commit / add / xóa), điều đó có thể có nghĩa là API của chúng rất gần với dòng lệnh của git nên bạn sẽ cần để có kinh nghiệm với Git.


Câu trả lời rất hữu ích, tôi không biết rằng Mercurial sử dụng Dulwich, cảm ơn bạn!
Kissgyorgy


7

Một câu trả lời cập nhật phản ánh thời gian thay đổi:

GitPython hiện là dễ sử dụng nhất. Nó hỗ trợ gói nhiều lệnh hệ thống ống nước git và có cơ sở dữ liệu đối tượng có thể cắm được (dulwich là một trong số đó) và nếu một lệnh không được thực thi, sẽ cung cấp một api dễ dàng để tách ra khỏi dòng lệnh. Ví dụ:

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

Cuộc gọi này:

bash$ git checkout -b new_branch

Dulwich cũng tốt nhưng trình độ thấp hơn nhiều. Nó hơi khó sử dụng vì nó đòi hỏi phải hoạt động trên các vật thể git ở cấp ống nước và không có đồ sứ đẹp mà bạn thường muốn làm. Tuy nhiên, nếu bạn có kế hoạch sửa đổi bất kỳ phần nào của git hoặc sử dụng git-receive-pack và git-upload-pack, bạn cần sử dụng dulwich.


2

Đây là một triển khai thực sự nhanh chóng của "trạng thái git":

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
Tôi không khuyên bạn nên phân tích cú phápgit status
Ehtesh Choudhury

1
Phân tích cú pháp git status --shortsẽ dễ dàng hơn và tôi nghĩ --shortđầu ra ít có khả năng thay đổi.
Ben Trang

2
Sử dụng git status --porcelaincho việc này--porcelain: Give the output in a stable, easy-to-parse format for scripts...
estani

Hoặc thậm chí tốt hơn, sử dụng --zthay vì --porcelain. Không giống như --porcelain, --zkhông thoát khỏi tên tập tin.
Vojislav Stojkovic

2

Câu trả lời của PTBNL khá hoàn hảo đối với tôi. Tôi làm thêm một chút cho người dùng 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
Tôi thấy rất nhiều sự lặp lại mã ...: p
Ciasto piekarz 15/03/2016

0

Phần thư viện tương tác git của StGit thực sự khá tốt. Tuy nhiên, nó không được chia thành một gói riêng biệt nhưng nếu có đủ tiền lãi, tôi chắc chắn rằng nó có thể được sửa chữa.

Nó có những tóm tắt rất hay để thể hiện các xác nhận, cây, v.v. và để tạo các xác nhận và cây mới.


-3

Đối với bản ghi, không có thư viện Git Python nào nói trên dường như có chứa "trạng thái git" tương đương, đây thực sự là điều duy nhất tôi muốn vì việc xử lý các lệnh git còn lại thông qua quy trình con rất dễ dàng.


3
với GitPython: git.Repo (repoDir) .git.status ()
ngầm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.