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?
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()
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 .
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.
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")