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