Doświadczenia z modułem Python Git? [Zamknięte]

172

Jakie są doświadczenia ludzi z którymkolwiek z modułów Git dla Pythona? (Znam GitPython, PyGit i Dulwich - nie wahaj się wspomnieć o innych, jeśli je znasz.)

Piszę program, który będzie musiał wchodzić w interakcje (dodawać, usuwać, zatwierdzać) z repozytorium Git, ale nie mam doświadczenia z Git, więc jedną z rzeczy, których szukam, jest łatwość użytkowania / zrozumienia w odniesieniu do Git.

Innymi rzeczami, które interesują mnie przede wszystkim, są dojrzałość i kompletność biblioteki, rozsądny brak błędów, ciągły rozwój oraz przydatność dokumentacji i programistów.

Jeśli myślisz o czymś innym, co chciałbym / chciałbym wiedzieć, nie wahaj się o tym wspomnieć.

PTBNL
źródło
25
Czy możemy zamienić to pytanie w wiki społeczności? Czuję, że najlepsza odpowiedź z czasem ulegnie zmianie.
ponowne opublikowanie
4
@relet: Nie można utworzyć wiki, dopóki jest zamknięte.
PTBNL

Odpowiedzi:

119

Chociaż to pytanie zostało zadane jakiś czas temu i nie znam stanu bibliotek w tamtym momencie, warto wspomnieć osobom wyszukującym, że GitPython dobrze radzi sobie z abstrakcją narzędzi wiersza poleceń, aby nie trzeba było używać podproces. Istnieje kilka użytecznych abstrakcji, których możesz użyć, ale w przypadku wszystkiego innego możesz wykonać takie czynności, jak:

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

Wszystko inne w GitPythonie po prostu ułatwia nawigację. Jestem dość zadowolony z tej biblioteki i doceniam, że jest ona opakowaniem podstawowych narzędzi git.

AKTUALIZACJA : Przerzuciłem się na używanie modułu sh dla nie tylko git, ale większości narzędzi wiersza poleceń, których potrzebuję w Pythonie. Aby powtórzyć powyższe, zrobiłbym to zamiast tego:

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()
underrun
źródło
2
Doskonałe narzędzie Legit wykorzystuje GitPython: github.com/kennethreitz/legit/blob/develop/legit/scm.py
forivall
9
Bazując na tej odpowiedzi, po prostu spróbowałem szczęścia z git-pythonem. Uważam, że API jest dziwne. W większości przypadków musisz wrócić do ogólnego interfejsu repo.git. *, A nawet to czasami nie działa poprawnie (np. repo.git.branch(b=somebranch)Działa, ale repo.git.branch(D=somebranch)nie działa, ponieważ brakuje miejsca). Myślę, że sam zaimplementuję ogólną funkcję opartą na podprocesach. Jestem smutny, miałem duże nadzieje. : - /
Christoph
6
przeszedłem na używanie modułu sh teraz z git = sh.git.bake(_cwd=repopath). działa niesamowicie.
poniżej
10
link do sh: amoffat.github.io/sh naprawdę powinien być częścią standardowego biblioteki Pythona.
g33kz0r
4
Najnowsza wersja Pythona sh nie działa w systemie Windows. Całkowita porażka.
void.pointer
81

Pomyślałem, że odpowiem na własne pytanie, ponieważ podążam inną drogą niż sugerowano w odpowiedziach. Niemniej jednak dziękuję tym, którzy odpowiedzieli.

Najpierw krótkie streszczenie moich doświadczeń z GitPythonem, PyGit i Dulwich:

  • GitPython : Po pobraniu zaimportowałem to i zainicjowałem odpowiedni obiekt. Jednak próba zrobienia tego, co sugerowano w samouczku, doprowadziła do błędów. Z braku większej dokumentacji poszedłem gdzie indziej.
  • PyGit : To by się nawet nie zaimportowało i nie mogłem znaleźć żadnej dokumentacji.
  • Dulwich : Wydaje się, że jest najbardziej obiecujący (przynajmniej ze względu na to, co chciałem i widziałem). Zrobiłem w nim pewien postęp, większy niż w przypadku GitPythona, ponieważ jego jajko jest dostarczane ze źródłem Pythona. Jednak po pewnym czasie zdecydowałem, że może być łatwiej spróbować tego, co zrobiłem.

Również StGit wygląda interesująco, ale potrzebowałbym funkcji wyodrębnionej w osobnym module i nie chcę czekać, aż to się stanie teraz.

W (dużo) mniej czasu niż spędziłem na próbach uruchomienia trzech powyższych modułów, udało mi się uzyskać polecenia git działające za pośrednictwem modułu podprocesu, np.

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

Nie jest to jeszcze w pełni włączone do mojego programu, ale nie przewiduję problemu, może z wyjątkiem szybkości (ponieważ będę przetwarzać setki lub nawet tysiące plików czasami).

Może po prostu nie miałem cierpliwości, aby wszystko działało z Dulwich lub GitPythonem. To powiedziawszy, mam nadzieję, że moduły będą bardziej rozbudowywane i wkrótce będą bardziej przydatne.

PTBNL
źródło
25
Ta odpowiedź się starzeje.
Alex Chamberlain
3
Tak, byłbym zainteresowany aktualizacją.
JosefAssad
GitPython działa bardzo dobrze i jest obszernie udokumentowany.
Arthur,
1
@Arthur Nie zgadzam się, ponieważ jestem co najmniej 3 godziny na dokumentacji StackOverflow i GitPython tylko po to, aby zrozumieć podstawy git pull, add, commit i push do zdalnego repozytorium za jego pomocą. Dokumentacja ma kilka zaawansowanych przypadków użycia, ale brakuje jej bardzo podstawowych. Po prostu poddaję się i używam podprocesu.
Daniel Lavedonio de Lima
31

Polecam pygit2 - wykorzystuje doskonałe libgit2 powiązania

tamale
źródło
1
Zapewnia również najlepszy dostęp do hydrauliki Git.
pielgrzym
pygit2jest naprawdę użyteczną biblioteką i nie mogę się doczekać jej rozbudowy w przyszłości!
Alex Chamberlain
2
Jak to jest teraz, należy ręcznie pobrać i skompilować / skonfigurować półstabilne wersje obu libgiti pygit2, biorąc źródło z GitHub. Problem w tym, że główne gałęzie mają zepsute testy, a ostatnia "stabilna" instalacja zakończyła się niepowodzeniem ... Nie jest to odpowiednie rozwiązanie, jeśli ważna jest niezawodność i musisz wdrożyć w różnych środowiskach ... :(
mac
1
trzymaj się z dala od tej kombinacji, jeśli kiedykolwiek planujesz korzystać z klientów korzystających z Cygwin. pygit2 jest opakowaniem dla libgit2, a libgit2 porzuciło całą obsługę cygwin. Komentarz, który dostałem od jednego z deweloperów: „Możesz spróbować, ale będzie cudem, jeśli zbuduje” piękne API, tak, ale połowa moich klientów to cygwin, więc nie mogę go używać. Prawdopodobnie przechodzę do GitPython.
scphantm
2
Zauważ, że nie obsługują cygwin, ponieważ zamiast tego koncentrują się na natywnej obsłudze systemu Windows . Więc chociaż jest prawdą, że libgit2 nie jest obsługiwana na cygwin, nie oznacza to, że użytkownicy systemu Windows są pozostawieni na lodzie .
Xiong Chiamiov,
19

To dość stare pytanie i szukając bibliotek Git, znalazłem taką, która została stworzona w tym roku (2013) o nazwie Gittle .

Działało świetnie dla mnie (gdzie inne, których próbowałem, były niestabilne) i wydaje się, że obejmuje większość typowych działań.

Kilka przykładów z 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="[email protected]", 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()
gak
źródło
2
Nie podoba mi się to, że „wystawiasz” pliki zamiast „dodawać” je do indeksu. zmiana nazw typowych / ważnych operacji wydaje się być myląca.
poniżej
3
Dodawanie @underrun to dodawanie plików na scenę. Czy to nie to samo z plikami tymczasowymi?
Jimmy Kane,
dodawanie plików to przemieszczanie plików do zatwierdzenia (to dodawanie ich do indeksu). operacja jest taka sama, ale w wierszu poleceń wpiszesz, git add other1.txt other2.txtwięc nie jest zgodna z oczekiwaniami.
poniżej
1
Zgodzili się na wyższość tego pakietu. Mogłem go nawet używać w aplikacji Pythonista po zainstalowaniu StaSh, z którym był w pakiecie. Warto również zauważyć, że Twoja odpowiedź jest ostatnią zaktualizowaną z odpowiedzi na to pytanie.
Chris Redford,
1
Właściwie wydaje mi się , że działa tylko dla mnie na Pythonista. Doprowadzenie go do uwierzytelnienia za pomocą hasła klonu prywatnego repozytorium bitbucket na moim Macu było koszmarem, z którego w końcu się poddałem.
Chris Redford,
17

Może to pomaga, ale Bazaar i Mercurial używają Dulwich ze względu na interoperacyjność Git.

Dulwich prawdopodobnie różni się od innych w tym sensie, że jest to reimplementacja gita w Pythonie. Drugi może być po prostu otoką wokół poleceń Gita (więc może być prostszy w użyciu z wysokiego poziomu: zatwierdzanie / dodawanie / usuwanie), prawdopodobnie oznacza to, że ich API jest bardzo zbliżone do wiersza poleceń gita, więc będziesz potrzebować zdobyć doświadczenie z Git.

tonfa
źródło
Bardzo przydatna odpowiedź, nie wiedziałem, że Mercurial używa Dulwich, dziękuję!
kissgyorgy
7

Ze względu na kompletność, http://github.com/alex/pyvcs/ jest warstwą abstrakcji dla wszystkich dvcs. Używa dulwich, ale zapewnia współdziałanie z innymi dvcs.

Justin Abrahms
źródło
7

Zaktualizowana odpowiedź odzwierciedlająca zmienione czasy:

Obecnie GitPython jest najłatwiejszy w użyciu. Obsługuje zawijanie wielu poleceń git hydraulicznych i ma podłączalną bazę danych obiektów (jedną z nich jest dulwich), a jeśli polecenie nie jest zaimplementowane, zapewnia łatwy interfejs API do wyrzucania do wiersza poleceń. Na przykład:

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

To wywołuje:

bash$ git checkout -b new_branch

Dulwich jest również dobry, ale znacznie niższy poziom. Jest to trochę uciążliwe w użyciu, ponieważ wymaga operowania na przedmiotach git na poziomie hydraulicznym i nie ma ładnej porcelany, którą normalnie chciałbyś zrobić. Jeśli jednak planujesz modyfikować jakąkolwiek część git lub używasz git-otrzymasz-pack i git-upload-pack, musisz użyć dulwich.

Jon Chu
źródło
2

Oto naprawdę szybka implementacja „statusu 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() )
Shane Geiger
źródło
5
Nie polecałbym analizowaniagit status
Ehtesh Choudhury,
1
Parsowanie git status --shortbyłoby łatwiejsze i myślę, że --shortwynik jest mniej prawdopodobny.
Ben Page
2
Użyj git status --porcelaindo tego--porcelain: Give the output in a stable, easy-to-parse format for scripts...
estani
Lub jeszcze lepiej, użyj --zzamiast --porcelain. W przeciwieństwie do --porcelain, --znie zmienia znaczenia nazw plików.
Vojislav Stojkovic
2

Odpowiedź PTBNL jest dla mnie idealna. Robię trochę więcej dla użytkownika 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)
Billy Jin
źródło
4
Widzę dużo powtórzeń kodu ...: p
Ciasto piekarz
0

Część biblioteki interakcji git w StGit jest w rzeczywistości całkiem dobra. Nie jest to jednak oddzielny pakiet, ale jeśli jest wystarczające zainteresowanie, jestem pewien, że można to naprawić.

Ma bardzo ładne abstrakcje do reprezentowania zatwierdzeń, drzew itp. Oraz do tworzenia nowych zatwierdzeń i drzew.

dkagedal
źródło
-3

Dla przypomnienia, żadna z wyżej wymienionych bibliotek Git Python nie wydaje się zawierać odpowiednika "git status", co jest jedyną rzeczą, jakiej bym chciał, ponieważ radzenie sobie z resztą poleceń git za pośrednictwem podprocesu jest tak łatwe.

xdissent
źródło
3
z GitPython: git.Repo (repoDir) .git.status ()
przeciwnajazdowego