94 votes

Comment puis-je appeler "git pull" à partir de Python ?

En utilisant les webhooks de Github, j'aimerais être en mesure d'extraire toute modification vers un serveur de développement distant. Pour l'instant, lorsque dans le répertoire approprié, git pull obtient tout changement qui doit être fait. Cependant, je n'arrive pas à trouver comment appeler cette fonction depuis Python. J'ai essayé ce qui suit :

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

Mais cela donne lieu à l'erreur suivante

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

Existe-t-il un moyen d'appeler cette commande bash depuis Python ?

162voto

jleahy Points 3678

Avez-vous envisagé d'utiliser GitPython ? Il est conçu pour gérer toutes ces absurdités à votre place.

import git 

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

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

60voto

phihag Points 89765

subprocess.Popen attend une liste du nom du programme et des arguments. Vous lui passez une seule chaîne de caractères, qui est (avec le paramètre par défaut shell=False ) équivalent à :

['git pull']

Cela signifie que le sous-processus essaie de trouver un programme nommé littéralement git pull et ne le fait pas : En Python 3.3, votre code soulève l'exception FileNotFoundError: [Errno 2] No such file or directory: 'git pull' . Au lieu de cela, passez dans 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 fonction de commodité :

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

De plus, pour utiliser les fonctionnalités de git, il n'est en aucun cas nécessaire (bien que simple et portable) d'appeler le binaire git. Pensez à utiliser git-python o Dulwich .

30voto

Eric Points 36290

La réponse acceptée utilisant GitPython n'est guère mieux que d'utiliser simplement 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, c'est comme obtenir une nouvelle boîte à outils brillante, et l'utiliser pour la pile de vis qui la maintient ensemble au lieu des outils qu'elle 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")

2voto

Tuxdude Points 8652

Il s'agit d'une recette type que j'ai utilisée dans le cadre d'un de mes projets. Je suis d'accord pour dire qu'il y a plusieurs façons de faire :)

>>> 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 est que vous ne passez pas un tableau pour subprocess.Popen() et donc essayait 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.

2voto

davidvandebunte Points 559

Si vous utilisez Python 3.5+ préférez subprocess.run a subprocess.Popen pour les scénarios qu'il peut gérer. Par exemple :

import subprocess
subprocess.run(["git", "pull"], check=True, stdout=subprocess.PIPE).stdout

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X