Esperienze del modulo Python Git? [chiuso]


172

Quali sono le esperienze delle persone con uno qualsiasi dei moduli Git per Python? (Conosco GitPython, PyGit e Dulwich - sentiti libero di menzionare gli altri se ne conosci.)

Sto scrivendo un programma che dovrà interagire (aggiungere, eliminare, eseguire il commit) con un repository Git, ma non ho esperienza con Git, quindi una delle cose che sto cercando è la facilità d'uso / comprensione nei confronti di Git.

Le altre cose che mi interessano principalmente sono la maturità e la completezza della biblioteca, una ragionevole mancanza di bug, lo sviluppo continuo e la disponibilità della documentazione e degli sviluppatori.

Se pensi a qualcos'altro che potrei desiderare / aver bisogno di sapere, non esitare a menzionarlo.


25
Possiamo trasformare questa domanda in un wiki della comunità? Sento che la risposta migliore cambierà nel tempo.
Rilasciato il

4
@relet: non può essere creato wiki finché è chiuso.
PTBNL

Risposte:


119

Mentre questa domanda è stata posta qualche tempo fa e non conosco lo stato delle librerie a quel punto, vale la pena menzionare per i ricercatori che GitPython fa un buon lavoro di astrazione degli strumenti della riga di comando in modo che non sia necessario utilizzare sottoprocesso. Ci sono alcune utili astrazioni integrate che puoi usare, ma per tutto il resto puoi fare cose come:

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

Tutto il resto in GitPython semplifica la navigazione. Sono abbastanza soddisfatto di questa libreria e apprezzo che sia un wrapper sugli strumenti git sottostanti.

AGGIORNAMENTO : Sono passato all'utilizzo del modulo sh non solo per git ma la maggior parte delle utility da riga di comando di cui ho bisogno in Python. Per replicare quanto sopra farei invece questo:

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
L'eccellente strumento Legit utilizza GitPython: github.com/kennethreitz/legit/blob/develop/legit/scm.py
forivall

9
Sulla base di questa risposta, ho appena tentato la fortuna con git-python. Trovo che l'API sia strana da gestire. La maggior parte delle volte è necessario ricorrere all'interfaccia generale repo.git. * E anche a volte non funziona correttamente (ad es. repo.git.branch(b=somebranch)Funziona, ma repo.git.branch(D=somebranch)non perché manca uno spazio). Immagino che implementerò io stesso una funzione generale basata su sottoprocessi. Sono triste, avevo grandi speranze. : - /
Christoph,

6
sono passato all'utilizzo del modulo sh ora con git = sh.git.bake(_cwd=repopath). funziona meravigliosamente.
underrun

10
link a sh: amoffat.github.io/sh dovrebbe davvero far parte di python stdlib.
g33kz0r,

4
L'ultima versione di python sh non funziona su Windows. Completamente fallito.
void.pointer

81

Ho pensato di rispondere alla mia domanda, dato che sto prendendo una strada diversa da quella suggerita nelle risposte. Tuttavia, grazie a coloro che hanno risposto.

Innanzitutto, una breve sinossi delle mie esperienze con GitPython, PyGit e Dulwich:

  • GitPython : Dopo il download, ho importato questo e inizializzato l'oggetto appropriato. Tuttavia, provare a fare ciò che è stato suggerito nel tutorial ha portato a errori. In mancanza di ulteriore documentazione, mi sono rivolto altrove.
  • PyGit : Questo non sarebbe nemmeno importato e non ho trovato documentazione.
  • Dulwich : sembra essere il più promettente (almeno per quello che volevo e vedevo). Ho fatto qualche progresso con esso, più che con GitPython, dal momento che il suo uovo viene fornito con sorgente Python. Tuttavia, dopo un po ', ho deciso che potrebbe essere più semplice provare quello che ho fatto.

Inoltre, StGit sembra interessante, ma avrei bisogno della funzionalità estratta in un modulo separato e non voglio aspettare che ciò accada in questo momento.

In (molto) meno tempo di quanto ho passato a cercare di far funzionare i tre moduli sopra, sono riuscito a far funzionare i comandi git tramite il modulo di sottoprocesso, ad es.

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

Questo non è ancora completamente incorporato nel mio programma, ma non sto anticipando un problema, tranne forse la velocità (poiché a volte elaborerò centinaia o addirittura migliaia di file).

Forse non ho avuto la pazienza di far andare le cose con Dulwich o GitPython. Detto questo, spero che i moduli avranno più sviluppo e saranno presto più utili.


25
Questa risposta sta invecchiando.
Alex Chamberlain,

3
Sì, sarei interessato a un aggiornamento.
JosefAssad,

GitPython funziona molto bene ed è ampiamente documentato.
Arthur,

1
@Arthur Non sono d'accordo, dato che sono almeno 3 ore nella documentazione StackOverflow e GitPython solo per comprendere le basi di git pull, aggiungere, eseguire il commit e il push in un repository remoto che lo utilizza. La documentazione presenta alcuni casi d'uso avanzati, ma manca di base. Fondamentalmente mi arrendo e utilizzo anche il sottoprocesso.
Daniel Lavedonio de Lima,

31

Consiglierei pygit2 - usa gli eccellenti collegamenti libgit2


1
Offre anche il miglior accesso all'impianto idraulico git.
pielgrzym,

pygit2è una libreria davvero utile e non vedo l'ora che si espanda in futuro!
Alex Chamberlain,

2
Allo stato attuale, è necessario scaricare e compilare / impostare manualmente versioni semi-stabili di entrambi libgite pygit2, prendendo il sorgente da GitHub. Il problema è che i rami principali hanno test falliti e l'ultima installazione "stabile" non riesce ... Non è una soluzione adatta se l'affidabilità è importante e devi implementarla in una varietà di ambienti ... :(
mac

1
stai lontano da questa combinazione se pianifichi di usare client con cygwin. pygit2 è un wrapper per libgit2 e libgit2 ha abbandonato tutto il supporto cygwin. Il commento che ho ricevuto da uno degli sviluppatori, "Puoi provarci, ma sarebbe un miracolo se costruisce" una bellissima API, sì, ma metà dei miei clienti sono cygwin quindi non posso usarlo. Probabilmente andare su GitPython.
scphantm,

2
Nota che non supportano cygwin perché si concentrano invece sul supporto nativo di Windows . Quindi, sebbene sia corretto che libgit2 non sia supportato su cygwin, ciò non significa che gli utenti Windows siano esclusi dal freddo.
Xiong Chiamiov

19

Questa è una domanda piuttosto vecchia e, mentre cercavo le librerie Git, ne ho trovata una creata quest'anno (2013) chiamata Gittle .

Ha funzionato alla grande per me (dove gli altri che ho provato erano traballanti) e sembra coprire la maggior parte delle azioni comuni.

Alcuni esempi dal 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
non mi piace che tu "metta in scena" i file invece di "aggiungerli" all'indice. cambiare i nomi di operazioni comuni / importanti sembra confondere.
underrun

3
L'aggiunta di @underrun sta aggiungendo file allo stage. Non è lo stesso con i file di gestione temporanea?
Jimmy Kane,

l'aggiunta di file è la gestione temporanea dei file da impegnare (li sta aggiungendo all'indice). l'operazione è la stessa ma alla riga di comando digiterai in git add other1.txt other2.txtmodo che non segua ciò che ci si aspetterebbe.
underrun

1
Concordato sulla superiorità di questo pacchetto. Sono stato anche in grado di usarlo all'interno dell'app Pythonista dopo aver installato StaSh, con il quale è stato impacchettato. Inoltre, vale la pena notare che la tua risposta è l'ultima delle ultime risposte a questa domanda.
Chris Redford,

1
In realtà, sembra funzionare solo per me su Pythonista. Ottenere la password per autenticare un clone di un repository bitbucket privato sul mio Mac è stato un incubo a cui alla fine ho rinunciato.
Chris Redford,

17

Forse aiuta, ma Bazaar e Mercurial usano entrambi Dulwich per la loro interoperabilità Git.

Dulwich è probabilmente diverso dall'altro nel senso che è una reimplementazione di git in Python. L'altro potrebbe essere solo un involucro attorno ai comandi di Git (quindi potrebbe essere più semplice da usare da un punto di vista di alto livello: commit / add / delete), probabilmente significa che la loro API è molto vicina alla riga di comando di git quindi avrai bisogno per acquisire esperienza con Git.


Risposta molto utile, non sapevo che Mercurial usasse Dulwich, grazie!
kissgyorgy,


7

Una risposta aggiornata che riflette i tempi modificati:

GitPython è attualmente il più semplice da usare. Supporta il wrapping di molti comandi idraulici git e ha un database di oggetti innestabile (dulwich è uno di questi) e, se un comando non è implementato, fornisce un'API semplice per sgusciare fuori dalla riga di comando. Per esempio:

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

Questo chiama:

bash$ git checkout -b new_branch

Anche Dulwich è buono ma di livello molto più basso. È un po 'una seccatura da usare perché richiede di operare su oggetti git a livello dell'impianto idraulico e non ha una bella porcellana che normalmente vorresti fare. Tuttavia, se hai intenzione di modificare parti di git o usi git-rece-pack e git-upload-pack, devi usare dulwich.


2

Ecco un'implementazione molto rapida di "stato 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
Non consiglierei l'analisigit status
Ehtesh Choudhury,

1
L'analisi git status --shortsarebbe più semplice e penso che l' --shortoutput abbia meno probabilità di cambiare.
Ben Page

2
Usa git status --porcelainper questo--porcelain: Give the output in a stable, easy-to-parse format for scripts...
estani,

O ancora meglio, usa --zinvece di --porcelain. Diversamente --porcelain, --znon sfugge ai nomi dei file.
Vojislav Stojkovic,

2

La risposta di PTBNL è abbastanza perfetta per me. Faccio un po 'di più per l'utente di 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
Vedo molte ripetizioni di codice ...: p
Ciasto piekarz,

0

La parte della libreria di interazione git di StGit è in realtà piuttosto buona. Tuttavia, non è suddiviso in un pacchetto separato, ma se l'interesse è sufficiente, sono sicuro che può essere risolto.

Ha delle astrazioni molto belle per rappresentare commit, alberi ecc. E per creare nuovi commit e alberi.


-3

Per la cronaca, nessuna delle librerie Git Python sopra menzionate sembra contenere un equivalente dello "stato git", che è davvero l'unica cosa che vorrei, dal momento che gestire il resto dei comandi git tramite sottoprocesso è così semplice.


3
con GitPython: git.Repo (repoDir) .git.status ()
underrun
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.