it-swarm.com.de

Wie kann ich "git pull" aus Python heraus aufrufen?

Mit den Webhooks von Github möchte ich Änderungen auf einen Remote-Entwicklungsserver übertragen. Im Moment, wenn sich das Verzeichnis in dem entsprechenden Verzeichnis befindet, erhält git pull alle erforderlichen Änderungen. Ich kann jedoch nicht herausfinden, wie ich diese Funktion in Python aufrufen kann. Ich habe folgendes versucht:

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

Dies führt jedoch zu dem folgenden Fehler

Traceback (letzter Anruf zuletzt): Datei "", Zeile 1, in Datei "/usr/lib/python2.7/subprocess.py", Zeile 679, in drin errread, errwrite) Datei "/usr/lib/python2.7/subprocess.py", Zeile 1249, in _execute_child child_exception erhöhen OSError: [Errno 2] Keine solche Datei oder Verzeichnis

Gibt es eine Möglichkeit, diesen bash-Befehl in Python aufzurufen?

50
djq

Haben Sie sich überlegt, GitPython zu verwenden? Es wurde entwickelt, um all diesen Unsinn für Sie zu bewältigen.

import git 

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

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

107
jleahy

subprocess.Popen erwartet eine Liste des Programmnamens und der Argumente. Sie übergeben eine einzelne Zeichenfolge, die (mit der Standardeinstellung Shell=False) entspricht:

['git pull']

Das bedeutet, dass der Unterprozess versucht, ein Programm mit dem Namen wörtlich git pull zu finden, und dies nicht. In Python 3.3 löst der Code die Ausnahme FileNotFoundError: [Errno 2] No such file or directory: 'git pull' aus. Übergeben Sie stattdessen eine Liste wie diese:

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

In Python 2.7 und höher können Sie diesen Code übrigens mit der Convenience-Funktion check_output vereinfachen:

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

Um die Git-Funktionalität zu nutzen, ist es keinesfalls notwendig (wenn auch einfach und portabel), die Git-Binärdatei aufzurufen. Erwägen Sie die Verwendung von git-python oder Dulwich .

34
phihag

Dies ist ein Beispielrezept, das ich in einem meiner Projekte verwendet habe. Vereinbart, dass es mehrere Möglichkeiten gibt, dies zu tun. :)

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

Das Problem mit Ihrem Code war, dass Sie kein Array für subprocess.Popen() übergeben haben und daher versucht haben, eine einzelne Binärdatei namens git pull auszuführen. Stattdessen muss die binäre Variable git ausgeführt werden, wobei das erste Argument pull usw. ist.

2
Tuxdude

Die akzeptierte Antwort mit GitPython ist etwas besser als die direkte Verwendung von subprocess.

Das Problem bei diesem Ansatz besteht darin, dass Sie, wenn Sie die Ausgabe analysieren möchten, am Ende das Ergebnis eines Befehls "Porzellan" sehen, was eine schlechte Idee ist

Wenn Sie GitPython auf diese Weise verwenden, ist es so, als würden Sie eine glänzende neue Toolbox erhalten und sie dann für den Schraubenhaufen verwenden, der sie zusammenhält, anstatt die Werkzeuge darin. So wurde die API für die Verwendung entworfen:

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

Wenn Sie prüfen möchten, ob sich etwas geändert hat, können Sie verwenden

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