Python Git модуль досвіду? [зачинено]


172

Який досвід людей щодо будь-якого з модулів Git для Python? (Я знаю про GitPython, PyGit і Dulwich - сміливо згадуйте інших, якщо ви знаєте про них.)

Я пишу програму, яка повинна буде взаємодіяти (додавати, видаляти, фіксувати) зі сховищем Git, але не маю досвіду роботи з Git, тому одна з речей, яку я шукаю, - це простота використання / розуміння щодо Git.

Інші речі, які мене насамперед цікавлять, - це зрілість та повнота бібліотеки, розумна відсутність помилок, подальший розвиток та корисність документації та розробників.

Якщо ви думаєте про щось інше, що я, можливо, захочу / мушу знати, будь ласка, не соромтесь це згадати.


25
Чи можемо ми перетворити це питання на вікі спільноти? Я відчуваю, що найкраща відповідь зміниться з часом.
relet

4
@relet: Вікі не можна робити, поки він закритий.
PTBNL

Відповіді:


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.

ОНОВЛЕННЯ : Я перейшов на використання модуля sh не просто для git, але і більшості утилітів командного рядка, які мені потрібні в 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)не відбувається, оскільки місця не вистачає). Напевно, я сам реалізую загальну функцію на основі підпроцесу. Мені сумно, я покладав великі надії. : - /
Крістоф

6
я перейшов на використання модуля sh зараз git = sh.git.bake(_cwd=repopath). це працює приголомшливо.
недоїдання

10
посилання на sh: amoffat.github.io/sh дійсно має бути частиною python stdlib.
g33kz0r

4
Остання версія python sh не працює в Windows. Повний повний провал.
void.pointer

81

Я думав, що відповім на власне запитання, оскільки я йду іншим шляхом, ніж пропонується у відповідях. Тим не менше, дякую тим, хто відповів.

По-перше, короткий конспект мого досвіду роботи з 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
Так, мені було б цікаво оновлення.
ЙозефАссад

GitPython працює дуже добре і широко документований.
Артур

1
@Arthur Я не згоден, оскільки я принаймні 3 години переглядаю документацію на StackOverflow та GitPython просто для того, щоб зрозуміти основи git тягнути, додавати, виконувати та натискати на віддалене репо, використовуючи його. У документації є декілька випадків розширеного використання, але вони відсутні дуже основними. Я в основному відмовляюся і використовую також підпроцес.
Даніель Лаведоніо де Ліма

31

Я рекомендую pygit2 - він використовує чудові прив'язки libgit2


1
Він також забезпечує найкращий доступ до сантехніки.
pielgrzym

pygit2це дійсно корисна бібліотека, і я з нетерпінням чекаю її розширення в майбутньому!
Алекс Чемберлен

2
Як зараз, потрібно завантажувати та компілювати / налаштовувати напівстабільні версії обох libgitта вручну pygit2, беручи джерело з GitHub. Проблема полягає в тому, що головні відділення зламали тести, а останній "стабільний" збій не встановлений ... Не підходить рішення, якщо надійність важлива і вам потрібно розгорнути в різних середовищах ... :(
mac

1
тримайтеся подалі від цієї комбінації, якщо ви коли-небудь плануєте клієнтів, які використовують cygwin. pygit2 - обгортка для libgit2, а libgit2 відмовився від усієї підтримки cygwin. Коментар, який я отримав від одного з розробників, "Ви можете спробувати, але це диво, якщо він будує" прекрасний 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
мені не подобається, що ви "стадієте" файли, а не "додаєте" їх до індексу. зміна назв загальних / важливих операцій просто здається, що це буде заплутано.
недоріг

3
@underrun додавання - це додавання файлів на сцену. Хіба це не те саме з постановочними файлами?
Джиммі Кейн

додавання файлів - це постановка файлів, які потрібно зробити (додавання їх до індексу). операція така ж, але в командному рядку ви введете, git add other1.txt other2.txtщоб вона не відповідала очікуваному.
недоріг

1
Домовились про перевагу цього пакету. Мені навіть вдалося використовувати його в додатку Pythonista після встановлення StaSh, до якого він був упакований. Також варто відзначити, що ваша відповідь - це нещодавно оновлений з відповідей на це питання.
Кріс Редфорд

1
На насправді, це , здається, тільки працювати для мене на Pythonista. Отримати його паролем для автентифікації клону приватного репортажу на bitbucket на моєму Mac було кошмаром, від якого я нарешті відмовився.
Кріс Редфорд

17

Можливо, це допомагає, але Bazaar і Mercurial обидва використовують dulwich для своєї сумісності з Git.

Dulwich, мабуть, відрізняється від інших в тому сенсі, що це повторне здійснення git в python. Інший може бути просто обгорткою навколо команд Git (тому його можна простіше використовувати з точки зору високого рівня: фіксувати / додавати / видаляти), ймовірно, це означає, що їх API дуже близький до командного рядка git, тому вам знадобиться щоб отримати досвід роботи з Git.


Дуже корисна відповідь, я не знав, що Mercurial використовує Dulwich, дякую!
kissgyorgy


7

Оновлена ​​відповідь, що відображає змінені часи:

На даний момент GitPython є найпростішим у використанні. Він підтримує обгортання багатьох команд git сантехніка та має підключувану базу даних об’єктів (dulwich є однією з них), а якщо команда не реалізована, надає простий api для обстрілу з командного рядка. Наприклад:

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

Це дзвінки:

bash$ git checkout -b new_branch

Дульвіч також хороший, але набагато нижчий рівень. Дещо болісно використовувати, оскільки це вимагає роботи над git об'єктами на рівні сантехніки і не має гарного фарфору, який ви зазвичай хочете робити. Однак якщо ви плануєте модифікувати будь-які частини git або використовувати git-rece-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
розбиратися

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не уникає.
Воєслав Стойкович

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 насправді дуже гарна. Однак він не розбивається як окремий пакет, але якщо є достатній інтерес, я впевнений, що це можна виправити.

Він має дуже хороші абстракції для представлення комітетів, дерев тощо, а також для створення нових комітетів та дерев.


-3

Натомість, жодна з вищезгаданих бібліотек Git Python, здається, не містить еквівалента "статусу git", що насправді є єдиним, що я хотів би, оскільки працювати з рештою команд git через підпроцес так просто.


3
з GitPython: git.Repo (repoDir) .git.status ()
спустошення
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.