โมดูล Python Git ประสบ? [ปิด]


172

ประสบการณ์ของผู้คนกับโมดูล Git ใด ๆ สำหรับ Python คืออะไร (ฉันรู้ GitPython, PyGit และ Dulwich - อย่าลังเลที่จะพูดถึงคนอื่นถ้าคุณรู้จักพวกเขา)

ฉันกำลังเขียนโปรแกรมที่จะต้องโต้ตอบ (เพิ่มลบกระทำ) กับที่เก็บ Git แต่ไม่มีประสบการณ์กับ Git ดังนั้นสิ่งหนึ่งที่ฉันกำลังมองหาคือความง่ายในการใช้ / ทำความเข้าใจเกี่ยวกับ Git

สิ่งอื่น ๆ ที่ฉันสนใจเป็นหลักคือความสมบูรณ์และความสมบูรณ์ของห้องสมุดการขาดข้อบกพร่องที่สมเหตุสมผลการพัฒนาอย่างต่อเนื่องและความเป็นประโยชน์ของเอกสารและนักพัฒนา

หากคุณนึกถึงอย่างอื่นที่ฉันอาจต้องการ / จำเป็นต้องรู้โปรดอย่าลังเลที่จะพูดถึงมัน


25
เราสามารถเปลี่ยนคำถามนี้เป็นวิกิชุมชนหรือไม่ ฉันรู้สึกว่าคำตอบที่ดีที่สุดจะเปลี่ยนไปตามกาลเวลา
relet

4
@relet: มันไม่สามารถทำ wiki ได้ตราบใดที่มันถูกปิด
PTBNL

คำตอบ:


119

ในขณะที่คำถามนี้ถูกถามเมื่อไม่นานมานี้และฉันไม่ทราบสถานะของไลบรารีในตอนนั้น แต่ก็คุ้มค่าที่จะกล่าวถึงสำหรับผู้ค้นหาว่า GitPython ทำงานได้ดีในการสรุปเครื่องมือบรรทัดคำสั่งเพื่อให้คุณไม่จำเป็นต้องใช้ กระบวนการย่อย มีบางส่วนที่เป็นประโยชน์ที่สร้างขึ้นใน abstractions ที่คุณสามารถใช้ได้ แต่สำหรับทุกสิ่งอื่นคุณสามารถทำสิ่งต่าง ๆ เช่น:

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 ช่วยให้นำทางง่ายขึ้น ฉันค่อนข้างพอใจกับห้องสมุดนี้เป็นอย่างมากและขอขอบคุณว่านี่เป็นเสื้อคลุมสำหรับเครื่องมือคอมไพล์พื้นฐาน

UPDATE : ฉันเปลี่ยนมาใช้โมดูล sh ไม่ใช่แค่คอมไพล์ แต่ยูทิลิตี้ commandline ส่วนใหญ่ที่ฉันต้องการใน 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()

2
เครื่องมือ Legit ที่ยอดเยี่ยมใช้ GitPython: github.com/kennethreitz/legit/blob/develop/legit/scm.py
forivall

9
จากคำตอบนี้ฉันแค่ลองเสี่ยงโชคกับ git-python ฉันพบว่า API แปลกที่จะจัดการกับ เวลาส่วนใหญ่คุณต้องถอยกลับไปที่ repo.git. * ส่วนต่อประสานทั่วไปและถึงแม้จะไม่ได้ทำงานอย่างถูกต้องในบางครั้ง (เช่นใช้repo.git.branch(b=somebranch)งานrepo.git.branch(D=somebranch)ได้ ฉันเดาว่าฉันจะใช้ฟังก์ชั่นทั่วไปที่ใช้ subprocess ด้วยตัวเอง ฉันเสียใจฉันมีความหวังสูง : - /
Christoph

6
git = sh.git.bake(_cwd=repopath)ฉันได้เปลี่ยนไปใช้โมดูลการดวลจุดโทษในขณะนี้ด้วย มันทำงานได้ดีมาก
ตกหล่น

10
ลิงก์ไปยัง sh: amoffat.github.io/sh ควรเป็นส่วนหนึ่งของ python stdlib
g33kz0r

4
งูหลามรุ่นล่าสุดไม่ทำงานบน Windows เสร็จสิ้นการล้มเหลว
void.pointer

81

ฉันคิดว่าฉันจะตอบคำถามของตัวเองเนื่องจากฉันใช้เส้นทางที่แตกต่างจากคำแนะนำในคำตอบ อย่างไรก็ตามขอบคุณผู้ที่ตอบ

ก่อนอื่นสังเขปประสบการณ์สั้น ๆ ของฉันกับ GitPython, PyGit และ Dulwich:

  • GitPython : หลังจากดาวน์โหลดฉันได้รับการนำเข้านี้และวัตถุที่เหมาะสมเริ่มต้น อย่างไรก็ตามการพยายามทำสิ่งที่แนะนำในการสอนทำให้เกิดข้อผิดพลาด ฉันไม่มีเอกสารเพิ่มเติมฉันหันไปที่อื่น
  • PyGit : สิ่งนี้จะไม่นำเข้าและฉันไม่สามารถหาเอกสารได้
  • Dulwich : ดูเหมือนว่าจะมีแนวโน้มมากที่สุด (อย่างน้อยสำหรับสิ่งที่ฉันต้องการและเห็น) ฉันใช้ความก้าวหน้ามากกว่ากับ 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

GitPython ทำงานได้ดีมาก & มีการบันทึกไว้อย่างกว้างขวาง
Arthur

1
@ ฉันไม่เห็นด้วยเนื่องจากฉันใช้เวลาอย่างน้อย 3 ชั่วโมงในเอกสาร StackOverflow และ GitPython เพื่อทำความเข้าใจพื้นฐานของการดึง git, เพิ่ม, ส่งและส่งไปยัง repo ระยะไกลโดยใช้มัน เอกสารประกอบมีกรณีการใช้งานขั้นสูงบางกรณี แต่ขาดพื้นฐานที่จำเป็น ฉันยอมแพ้และใช้ subprocess ด้วยเช่นกัน
Daniel Lavedonio de Lima

31

ฉันแนะนำpygit2 - ใช้การผูกlibgit2 ที่ยอดเยี่ยม


1
มันให้การเข้าถึงที่ดีที่สุดในการประปา git ด้วย
pielgrzym

pygit2เป็นห้องสมุดที่มีประโยชน์จริง ๆ และฉันหวังว่าจะขยายในอนาคต!
อเล็กซ์แชมเบอร์เลน

2
ตามที่เป็นอยู่ตอนนี้เราต้องดาวน์โหลดและคอมไพล์ / เซ็ตอัพเวอร์ชั่นกึ่งเสถียรทั้งสองแบบด้วยตนเองlibgitและpygit2รับแหล่งจาก GitHub ปัญหาคือกิ่งก้านใหญ่มีการทดสอบที่ล้มเหลวและการติดตั้งล้มเหลว "เสถียร" ล่าสุด ... ไม่ใช่วิธีแก้ปัญหาที่เหมาะสมหากความน่าเชื่อถือเป็นสิ่งสำคัญและคุณต้องปรับใช้ในสภาพแวดล้อมที่หลากหลาย ... :(
mac

1
อยู่ห่างจากชุดค่าผสมนี้หากคุณเคยวางแผนลูกค้าที่ใช้ cygwin pygit2 เป็น wrapper สำหรับ libgit2 และ libgit2 ได้ลดการสนับสนุน cygwin ทั้งหมด ความคิดเห็นที่ฉันได้รับจากหนึ่งใน dev ของ "คุณสามารถลอง แต่มันเป็นปาฏิหาริย์ถ้ามันสร้าง" API ที่สวยงามใช่ แต่ลูกค้าของฉันครึ่งหนึ่งเป็น cygwin ดังนั้นฉันจึงไม่สามารถใช้งานได้ อาจไปที่ GitPython
scphantm

2
โปรดทราบว่าพวกเขาไม่สนับสนุน Cygwin เพราะโฟกัสของพวกเขาอยู่ในการสนับสนุนของ Windows พื้นเมืองแทน ดังนั้นในขณะที่มันถูกต้องที่ libgit2 ไม่ได้รับการสนับสนุนใน cygwin แต่ก็ไม่ได้หมายความว่าผู้ใช้ Windows จะถูกทิ้งให้อยู่ในความเย็น
Xiong Chiamiov

19

นี่คือคำถามที่เก่าสวยและในขณะที่มองหาห้องสมุด Git ฉันพบหนึ่งที่ถูกสร้างขึ้นในปีนี้ (2013) เรียกว่าGittle

มันใช้งานได้ดีสำหรับฉัน (ซึ่งคนอื่น ๆ ที่ฉันพยายามเป็นขุย) และดูเหมือนว่าจะครอบคลุมการกระทำทั่วไปส่วนใหญ่

ตัวอย่างจาก 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
ฉันไม่ชอบที่คุณ "ไฟล์" เวทีแทน "เพิ่ม" พวกเขาไปยังดัชนี การเปลี่ยนชื่อของการดำเนินงานทั่วไป / สำคัญดูเหมือนว่าจะทำให้สับสน
underrun

3
การเพิ่ม @underrun กำลังเพิ่มไฟล์ไปยังสเตจ มันไม่เหมือนกับไฟล์ staging ใช่ไหม
Jimmy Kane

การเพิ่มไฟล์คือไฟล์ staging ที่จะถูกคอมมิต (กำลังเพิ่มลงในดัชนี) การดำเนินการเหมือนกัน แต่ที่บรรทัดคำสั่งคุณจะพิมพ์git add other1.txt other2.txtดังนั้นจึงไม่ปฏิบัติตามสิ่งที่คาดหวัง
underrun

1
เห็นด้วยกับความเหนือกว่าของแพ็คเกจนี้ ฉันสามารถใช้งานได้ในแอพ Pythonista หลังจากติดตั้ง StaSh ซึ่งบรรจุด้วย นอกจากนี้ยังเป็นที่น่าสังเกตว่าคำตอบของคุณเป็นคำตอบล่าสุดสำหรับคำถามนี้
Chris Redford

1
ที่จริงแล้วดูเหมือนว่าจะใช้ได้กับฉันใน Pythonista เท่านั้น การใช้รหัสผ่านรับรองความถูกต้องของการโคลนของ repo bitbucket ส่วนตัวบน Mac ของฉันเป็นฝันร้ายที่ในที่สุดฉันก็ยอมแพ้
Chris Redford

17

อาจช่วยได้ แต่ Bazaar และ Mercurial ต่างก็ใช้ดัลวิชในการทำงานร่วมกันของ Git

ดัลวิชอาจจะแตกต่างจากคนอื่น ๆ ในแง่ที่ว่ามันเป็นการปรับใช้คอมไพล์ในไพ ธ อน อีกอันอาจเป็น wrapper รอบคำสั่งของ Git (ดังนั้นมันจึงง่ายกว่าที่จะใช้จากมุมมองระดับสูง: commit / add / delete) มันอาจหมายความว่า API ของพวกเขานั้นใกล้กับบรรทัดคำสั่งของ git มากดังนั้นคุณต้อง เพื่อรับประสบการณ์กับ Git


คำตอบที่มีประโยชน์มากฉันไม่ทราบว่า Mercurial ใช้ Dulwich ขอบคุณ!
kissgyorgy


7

คำตอบที่อัปเดตซึ่งสะท้อนถึงเวลาที่เปลี่ยนแปลง:

ปัจจุบัน GitPython ใช้งานง่ายที่สุด สนับสนุนการตัดคำสั่ง git plumbing จำนวนมากและมีฐานข้อมูลวัตถุที่ถอดได้ (ดัลวิชเป็นหนึ่งในนั้น) และหากคำสั่งไม่ได้ถูกใช้ ตัวอย่างเช่น:

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

สายนี้:

bash$ git checkout -b new_branch

ดัลวิชยังดี แต่ระดับต่ำกว่ามาก มันค่อนข้างเจ็บปวดที่จะใช้เพราะมันต้องใช้งานกับวัตถุ git ที่ระดับการประปาและไม่มีเครื่องลายครามที่ดีที่ปกติคุณต้องการจะทำ อย่างไรก็ตามหากคุณวางแผนที่จะแก้ไขส่วนใดส่วนหนึ่งของ git หรือใช้ git-receive-pack และ git-upload-pack คุณต้องใช้ dulwich


2

นี่คือการใช้งานอย่างรวดเร็วของ "สถานะ 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
ฉันจะไม่แนะนำให้ทำการแยกวิเคราะห์git status
Ehtesh Choudhury

1
การแยกวิเคราะห์git status --shortจะง่ายขึ้นและฉันคิดว่า--shortผลผลิตมีแนวโน้มที่จะเปลี่ยนแปลงน้อยลง
เบ็นหน้า

2
ใช้git status --porcelainสำหรับสิ่งนี้--porcelain: Give the output in a stable, easy-to-parse format for scripts...
estani

หรือดียิ่งขึ้นใช้แทน--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

0

ส่วนไลบรารีปฏิสัมพันธ์ git ของ StGit นั้นค่อนข้างดีทีเดียว อย่างไรก็ตามมันไม่ได้แยกออกเป็นแพคเกจแยกต่างหาก แต่หากมีความสนใจเพียงพอฉันแน่ใจว่าสามารถแก้ไขได้

มันมี abstractions ที่ดีมากสำหรับการทำคอมมิชชันต้นไม้เป็นต้นและสำหรับการสร้างคอมมิทและต้นไม้ใหม่


-3

สำหรับบันทึกแล้วไม่มีไลบรารี Git Python ดังกล่าวข้างต้นที่ดูเหมือนจะมี "สถานะ git" ซึ่งเป็นสิ่งเดียวที่ฉันต้องการตั้งแต่จัดการกับคำสั่ง git ที่เหลือผ่าน subprocess นั้นง่ายมาก


3
ด้วย GitPython: git.Repo (repoDir) .git.status ()
ต่ำ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.