web-dev-qa-db-fra.com

Comment puis-je appeler 'git pull' depuis Python?

En utilisant les github webhooks, je voudrais pouvoir extraire toutes les modifications apportées à un serveur de développement distant. À l’heure actuelle, lorsque vous vous trouvez dans le répertoire approprié, git pull récupère les modifications à apporter. Cependant, je n'arrive pas à comprendre comment appeler cette fonction à partir de Python. J'ai essayé ce qui suit:

import subprocess
process = subprocess.Popen("git pull", stdout=subprocess.PIPE)
output = process.communicate()[0]

Mais cela entraîne l'erreur suivante

Traceback (appel le plus récent en dernier): Fichier "", ligne 1, dans Fichier "/usr/lib/python2.7/subprocess.py", ligne 679, dans init errread, errwrite) Fichier "/usr/lib/python2.7/subprocess.py", ligne 1249, dans _execute_child raise child_exception OSError: [Errno 2] Aucun fichier ou répertoire de ce type

Est-il possible d'appeler cette commande bash depuis Python?

50
djq

Avez-vous envisagé d'utiliser GitPython? Il est conçu pour gérer tout ce non-sens pour vous.

import git 

g = git.cmd.Git(git_dir)
g.pull()

https://github.com/gitpython-developers/GitPython

107
jleahy

subprocess.Popen attend une liste du nom du programme et des arguments. Vous lui passez une chaîne unique, ce qui équivaut (avec le Shell=False par défaut) à:

['git pull']

Cela signifie que le sous-processus essaie de trouver un programme appelé littéralement git pull et échoue: dans Python 3.3, votre code déclenche l'exception FileNotFoundError: [Errno 2] No such file or directory: 'git pull'. Au lieu de cela, passez une liste, comme ceci:

import subprocess
process = subprocess.Popen(["git", "pull"], stdout=subprocess.PIPE)
output = process.communicate()[0]

À propos, dans Python 2.7+, vous pouvez simplifier ce code avec la fonction check_output commodité:

import subprocess
output = subprocess.check_output(["git", "pull"])

De plus, pour utiliser la fonctionnalité git, il n’est nullement nécessaire (bien que simple et portable) d’appeler le binaire git. Pensez à utiliser git-python ou Dulwich .

34
phihag

Ceci est un exemple de recette que j'ai utilisé dans l'un de mes projets. Convenu qu'il existe plusieurs façons de le faire cependant. :)

>>> import subprocess, shlex
>>> git_cmd = 'git status'
>>> kwargs = {}
>>> kwargs['stdout'] = subprocess.PIPE
>>> kwargs['stderr'] = subprocess.PIPE
>>> proc = subprocess.Popen(shlex.split(git_cmd), **kwargs)
>>> (stdout_str, stderr_str) = proc.communicate()
>>> return_code = proc.wait()

>>> print return_code
0

>>> print stdout_str
# On branch dev
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   file1
#   file2
nothing added to commit but untracked files present (use "git add" to track)

>>> print stderr_str

Le problème avec votre code était que vous ne passiez pas un tableau pour subprocess.Popen() et essayiez donc d'exécuter un seul binaire appelé git pull. Au lieu de cela, il doit exécuter le binaire git avec le premier argument étant pull et ainsi de suite.

2
Tuxdude

La réponse acceptée avec GitPython est un peu mieux que de simplement utiliser subprocess directement.

Le problème avec cette approche est que si vous voulez analyser la sortie, vous finissez par regarder le résultat d'une commande "porcelaine", ce qui est une mauvaise idée

Utiliser GitPython de cette manière revient à se procurer une nouvelle boîte à outils brillante, puis l’utiliser pour la pile de vis qui le maintient ensemble au lieu des outils qu’il contient. Voici comment l'API a été conçue pour être utilisée:

import git
repo = git.Repo('Path/to/repo')
repo.remotes.Origin.pull()

Si vous voulez vérifier si quelque chose a changé, vous pouvez utiliser

current = repo.head.commit
repo.remotes.Origin.pull()
if current != repo.head.commit:
    print("It changed")
1
Eric