Mit den Github-Webhooks möchte ich Änderungen an einem Remote-Entwicklungsserver vornehmen können. Im Moment, wenn Sie sich im entsprechenden Verzeichnis befinden, werden git pull
alle Änderungen abgerufen, die vorgenommen werden müssen. Ich kann jedoch nicht herausfinden, wie diese Funktion in Python aufgerufen werden kann. Ich habe folgendes versucht:
import subprocess
process = subprocess.Popen("git pull", stdout=subprocess.PIPE)
output = process.communicate()[0]
Dies führt jedoch zu folgendem Fehler
Traceback (letzter Aufruf zuletzt): Datei "", Zeile 1, in Datei "/usr/lib/python2.7/subprocess.py", Zeile 679, in init errread, errwrite) Datei "/ usr / lib / python2. 7 / subprocess.py ", Zeile 1249, in _execute_child erhöhen child_exception OSError: [Errno 2] Keine solche Datei oder kein solches Verzeichnis
Gibt es eine Möglichkeit, diesen Bash-Befehl in Python aufzurufen?
git
ausführbare Datei im Pfad?subprocess.Popen
jetzt gibt es eincwd
Schlüsselwortargument, das den Befehl in einem angegebenen Verzeichnis ausführt. Beispiel:subprocess.Popen(['git', 'pull', '-v', 'origin', 'master'], cwd='/path/to/git/repo', ...)
Antworten:
Haben Sie überlegt, GitPython zu verwenden? Es wurde entwickelt, um all diesen Unsinn für Sie zu erledigen.
import git g = git.cmd.Git(git_dir) g.pull()
https://github.com/gitpython-developers/GitPython
quelle
msg = g.pull()
sagt dir was passiert ist.msg
ist''
oder'Updating ... Fast-forward README.md | 1 + 1 file changed, 1 insertion(+)'
wenn du erfolgreich gezogen hast und'Already up-to-date.'
wenn du ... schon auf dem neuesten Stand bist.subprocess.check_output(['git', 'pull'], cwd=git_dir)
, sodass Sie die Ausgabe eines "git porcelain" -Befehls selbst analysieren können, was Sie nicht tun solltensubprocess.Popen
erwartet eine Liste des Programmnamens und der Argumente. Sie übergeben ihm eine einzelne Zeichenfolge, die (standardmäßigshell=False
) entspricht:['git pull']
Das bedeutet, dass der Unterprozess versucht, ein Programm mit dem wörtlichen Namen zu finden
git pull
, und dies nicht tut: In Python 3.3 löst Ihr Code die Ausnahme ausFileNotFoundError: [Errno 2] No such file or directory: 'git pull'
. Geben Sie stattdessen eine Liste wie folgt ein:import subprocess process = subprocess.Popen(["git", "pull"], stdout=subprocess.PIPE) output = process.communicate()[0]
Übrigens können Sie in Python 2.7+ diesen Code mit der
check_output
praktischen Funktion vereinfachen :import subprocess output = subprocess.check_output(["git", "pull"])
Um die Git-Funktionalität nutzen zu können, ist es keineswegs notwendig (wenn auch einfach und portabel), die Git-Binärdatei aufzurufen. Erwägen Sie die Verwendung von Git-Python oder Dulwich .
quelle
shell=True
.subprocess.Popen("git pull", stdout=subprocess.PIPE).communicate()
(3.3 und 2.7 unter Windows). - Nun, ein bisschen weiter lesen, erklären die Dokumente, dass dies nur unter Unix funktioniert, wenn keine Argumente übergeben werden. Vergiss dann ^^If args is a string, the interpretation is platform-dependent
. Weitere Details hinzugefügt. In Python 3.3 ist die Fehlermeldung viel besser.Die akzeptierte Antwort mit GitPython ist kaum besser als nur
subprocess
direkt.Das Problem bei diesem Ansatz ist, dass Sie, wenn Sie die Ausgabe analysieren möchten, am Ende das Ergebnis eines "Porzellan" -Befehls betrachten, was eine schlechte Idee ist
Wenn Sie GitPython auf diese Weise verwenden, erhalten Sie eine glänzende neue Toolbox und diese dann für den Stapel von Schrauben, die sie zusammenhalten, anstelle der darin enthaltenen Werkzeuge. So wurde die API für die Verwendung entwickelt:
import git repo = git.Repo('Path/to/repo') repo.remotes.origin.pull()
Wenn Sie überprü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")
quelle
Dies ist ein Beispielrezept, das ich in einem meiner Projekte verwendet habe. Einverstanden, 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 übergeben haben
subprocess.Popen()
und daher versucht haben, eine einzelne Binärdatei namens aufzurufengit pull
. Stattdessen muss die Binärdateigit
mit dem ersten Argumentpull
usw. ausgeführt werden.quelle
split
das wirklich so sein sollteshlex.split
, und dieser Code ist unnötig kompliziert - Sie müssen nichtwait
nachcommunicate
und in den meisten Anwendungsfällencheck_output
bereits die richtige Zeichenfolge ausführen.shlex.split
. Und ja, wenn Sie nicht daran interessiert sind, stdout oder stderr zu greifen, können Sie diese überspringen. Es ist nichts Falsches daran, alternative Lösungencheck_output
wurde es erst seit 2.7 hinzugefügt. Ich musste mein Skript auch in Umgebungen mit älteren Python-Versionen ausführen.wait
Arbeitproc.pid
ist viel einfacher zu verstehen. Und dacheck_output
es sich um reines Python handelt, kann man es einfach kopieren , um es auch in älteren Python-Versionen verfügbar zu haben.check_output
scheint auch robuster :)Wenn Sie Python verwenden 3.5+ bevorzugen ,
subprocess.run
umsubprocess.Popen
für Szenarien können damit umgehen. Zum Beispiel:import subprocess subprocess.run(["git", "pull"], check=True, stdout=subprocess.PIPE).stdout
quelle
Versuchen:
subprocess.Popen("git pull", stdout=subprocess.PIPE, shell=True)
quelle