Experiências do módulo Git do Python? [fechadas]


172

Quais são as experiências das pessoas com qualquer um dos módulos Git para Python? (Eu conheço GitPython, PyGit e Dulwich - fique à vontade para mencionar outras pessoas, se você souber delas.)

Estou escrevendo um programa que terá que interagir (adicionar, excluir, confirmar) com um repositório Git, mas não tem experiência com o Git, portanto, uma das coisas que estou procurando é a facilidade de uso / compreensão em relação ao Git.

As outras coisas nas quais estou interessado principalmente são maturidade e integridade da biblioteca, uma razoável falta de bugs, desenvolvimento contínuo e utilidade da documentação e dos desenvolvedores.

Se você pensa em outra coisa que eu queira / precise saber, sinta-se à vontade para mencionar.


25
Podemos transformar essa pergunta em um wiki da comunidade? Sinto que a melhor resposta mudará com o tempo.
relet 18/04

4
@eletro: Não pode ser feito wiki enquanto estiver fechado.
PTBNL

Respostas:


119

Embora essa pergunta tenha sido feita há um tempo e eu não conheço o estado das bibliotecas naquele momento, vale a pena mencionar para os pesquisadores que o GitPython faz um bom trabalho abstraindo as ferramentas de linha de comando para que você não precise usar subprocesso. Existem algumas abstrações úteis úteis que você pode usar, mas para todo o resto você pode fazer coisas como:

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

Tudo o resto no GitPython facilita a navegação. Estou bastante satisfeito com esta biblioteca e compreendo que ela é um invólucro nas ferramentas git subjacentes.

UPDATE : Eu mudei para usar o módulo sh não apenas para o git, mas também para a maioria dos utilitários de linha de comando que eu preciso em python. Para replicar o acima, eu faria isso:

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
A excelente ferramenta Legit usa GitPython
forivall

9
Com base nesta resposta, tentei a sorte com o git-python. Acho a API estranha de se lidar. Na maioria das vezes, você precisa voltar à interface geral repo.git. * E até mesmo isso não funciona corretamente às vezes (por exemplo, repo.git.branch(b=somebranch)funciona, mas repo.git.branch(D=somebranch)não, porque falta um espaço). Acho que vou implementar uma função geral baseada em subprocessos. Estou triste, tinha grandes esperanças. : - /
Christoph

6
Eu mudei para usar o módulo sh agora com git = sh.git.bake(_cwd=repopath). funciona incrivelmente.
underrun

10
O link para sh: amoffat.github.io/sh realmente deve fazer parte do python stdlib.
g33kz0r

4
A versão mais recente do python sh não funciona no Windows. Falha total completa.
void.pointer

81

Pensei em responder minha própria pergunta, pois estou seguindo um caminho diferente do sugerido nas respostas. No entanto, obrigado a quem respondeu.

Primeiro, uma breve sinopse das minhas experiências com GitPython, PyGit e Dulwich:

  • GitPython : Após o download, consegui isso importado e o objeto apropriado inicializado. No entanto, tentar fazer o que foi sugerido no tutorial levou a erros. Na falta de mais documentação, eu me virei para outro lugar.
  • PyGit : Isso nem importaria, e não encontrei documentação.
  • Dulwich : Parece ser o mais promissor (pelo menos para o que eu queria e vi). Fiz alguns progressos com ele, mais do que com o GitPython, já que seu ovo vem com a fonte Python. No entanto, depois de um tempo, decidi que seria mais fácil tentar o que fiz.

Além disso, o StGit parece interessante, mas eu precisaria da funcionalidade extraída em um módulo separado e não quero esperar que isso aconteça agora.

Em (muito) menos tempo do que gastei tentando colocar os três módulos acima em funcionamento, consegui que os comandos git funcionassem através do módulo de subprocesso, por exemplo

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

Isso ainda não está totalmente incorporado ao meu programa, mas não estou prevendo um problema, exceto talvez a velocidade (já que processarei centenas ou até milhares de arquivos às vezes).

Talvez eu simplesmente não tenha paciência para fazer as coisas acontecerem com Dulwich ou GitPython. Dito isto, espero que os módulos tenham mais desenvolvimento e sejam mais úteis em breve.


25
Esta resposta está ficando velha.
Alex Chamberlain

3
Sim, eu estaria interessado em uma atualização.
JosefAssad

O GitPython funciona muito bem e é amplamente documentado.
Arthur

1
@Arthur Não concordo, já que tenho pelo menos três horas na documentação do StackOverflow e GitPython apenas para entender o básico do git pull, adicionar, confirmar e enviar para um repositório remoto usando-o. A documentação possui alguns casos de uso avançados, mas falta o básico. Estou basicamente desistindo e usando o subprocesso também.
Daniel Lavedonio de Lima 17/06

31

Eu recomendaria pygit2 - ele usa as excelentes ligações libgit2


1
Também oferece o melhor acesso ao encanamento git.
Pielgrzym

pygit2é uma biblioteca realmente útil e espero que ela se expanda no futuro!
Alex Chamberlain

2
Como é agora, é preciso baixar e compilar / configurar manualmente as versões semi-estáveis ​​de ambos libgite pygit2, retirando a fonte do GitHub. O problema é que as ramificações principais têm testes quebrados e a instalação mais recente com falha "estável" ... Não é uma solução adequada se a confiabilidade é importante e você precisa implantar em uma variedade de ambientes ... :(
mac

1
fique longe dessa combinação se você planeja clientes usando o cygwin. pygit2 é um wrapper para libgit2 e libgit2 eliminou todo o suporte cygwin. O comentário que recebi de um dos desenvolvedores, "Você pode tentar, mas será um milagre se ele criar" uma bela API, sim, mas metade dos meus clientes é cygwin, portanto não posso usá-la. Provavelmente indo para o GitPython.
scphantm

2
Observe que eles não oferecem suporte ao cygwin porque seu foco é o suporte nativo ao Windows . Portanto, embora esteja correto que a libgit2 não seja suportada no cygwin, isso não significa que os usuários do Windows sejam deixados de fora no frio.
Xiong Chiamiov

19

Essa é uma pergunta bastante antiga e, enquanto procurava por bibliotecas Git, encontrei uma que foi criada este ano (2013) chamada Gittle .

Funcionou muito bem para mim (onde os outros que eu tentei eram esquisitos) e parece cobrir a maioria das ações comuns.

Alguns exemplos do 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
não gosto que você "prepare" os arquivos em vez de "adicioná-los" ao índice. alterar nomes de operações comuns / importantes parece confuso.
o encaixe

3
A adição do @underrun está adicionando arquivos ao palco. Não é o mesmo com os arquivos temporários?
Jimmy Kane

adicionar arquivos é um arquivo temporário a ser confirmado (está adicionando-os ao índice). a operação é a mesma, mas na linha de comando você digitaria git add other1.txt other2.txtpara que não seguisse o que seria esperado.
o encaixe

1
Concordou com a superioridade deste pacote. Eu até consegui usá-lo no aplicativo Pythonista depois de instalar o StaSh, que foi empacotado. Além disso, é importante notar que sua resposta é a mais recente das respostas a esta pergunta.
Chris Redford

1
Na verdade, parece funcionar apenas para mim no Pythonista. Conseguir a senha para autenticar um clone de um repositório de bitbucket privado no meu Mac foi um pesadelo que eu finalmente desisti.
Chris Redford

17

Talvez ajude, mas Bazaar e Mercurial estão usando dulwich para sua interoperabilidade com o Git.

Dulwich provavelmente é diferente do outro no sentido de que é uma reimplementação do git em python. O outro pode ser apenas um invólucro dos comandos do Git (para que seja mais simples de usar de um ponto de vista de alto nível: confirmar / adicionar / excluir), provavelmente significa que a API está muito próxima da linha de comando do git, então você precisará para ganhar experiência com o Git.


Resposta muito útil, eu não sabia que Mercurial usa Dulwich, obrigado!
Kissgyorgy


7

Uma resposta atualizada que reflete os tempos alterados:

Atualmente, o GitPython é o mais fácil de usar. Ele suporta o agrupamento de muitos comandos de canalização do git e possui um banco de dados de objetos conectável (dulwich é um deles) e, se um comando não for implementado, fornece uma API fácil para direcionar a linha de comando. Por exemplo:

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

Isso chama:

bash$ git checkout -b new_branch

Dulwich também é bom, mas nível muito mais baixo. É um pouco difícil de usar, pois requer a operação em objetos git no nível do encanamento e não possui porcelana agradável que você normalmente gostaria de fazer. No entanto, se você planeja modificar qualquer parte do git ou usar o git-receive-pack e o git-upload-pack, precisará usar o dulwich.


2

Aqui está uma implementação muito rápida do "status 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
Eu não recomendaria a análisegit status
Ehtesh Choudhury

1
A análise git status --shortseria mais fácil e acho que --shorté menos provável que a saída mude.
Ben Page

2
Use git status --porcelainfor this--porcelain: Give the output in a stable, easy-to-parse format for scripts...
estani

Ou melhor ainda, use em --zvez de --porcelain. Ao contrário --porcelain, --znão escapa nomes de arquivos.
Vojislav Stojkovic

2

A resposta do PTBNL é perfeita para mim. Eu faço um pouco mais para o usuário do 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
Eu vejo muita repetição de código ...: p
Ciasto piekarz 15/03

0

A parte da biblioteca de interação git do StGit é realmente muito boa. No entanto, não é dividido como um pacote separado, mas se houver interesse suficiente, tenho certeza de que isso pode ser corrigido.

Possui abstrações muito boas para representar confirmações, árvores, etc., e para criar novas confirmações e árvores.


-3

Para o registro, nenhuma das bibliotecas Git Python mencionadas acima parece conter um equivalente "status git", o que é realmente a única coisa que eu gostaria, já que lidar com o restante dos comandos git via subprocesso é tão fácil.


3
com GitPython: git.Repo (repoDir) .git.status ()
underrun
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.