Je veux exécuter cette commande git via un script Python et en obtenir la sortie:

git diff --name-only mybranch `git merge-base mybranch develop`

Le but de la commande est de voir quelles modifications ont été apportées sur mybranch depuis la dernière fusion avec develop.

Pour y parvenir, j'utilise subprocess.Popen:

output = subprocess.Popen(["git", "diff", "--name-only", "mybranch", "`git merge-base mybranch develop`"], stdout=subprocess.PIPE, shell=True)

Cependant, cela ne fonctionne pas. La variable output.communicate()[0] me donne simplement une impression de l'utilisation de git - me disant essentiellement que la commande d'entrée est fausse.

J'ai vu qu'une question similaire existe ici, mais seulement m'a dit d'utiliser shell=True qui n'a pas résolu mon problème.

J'ai également essayé d'exécuter les deux commandes successivement, mais cela m'a donné le même résultat qu'avant. Il est possible que je manque quelque chose dans cette étape, cependant.

Toute aide ou astuce est appréciée.

3
Jokab 20 juil. 2015 à 15:32

2 réponses

Meilleure réponse

Backticks et sous-processus

Le backtick étant une fonctionnalité du shell , vous n'avez peut-être pas d'autre choix que d'utiliser shell=True, mais passez dans une chaîne de commande du shell , pas une liste d'arguments

Donc, pour votre commande particulière (en supposant que cela fonctionne en premier lieu)

process = subprocess.Popen("git diff --name-only mybranch `git merge-base mybranch develop`", stdout=subprocess.PIPE, shell=True)

Remarquez que lorsque vous appelez Popen(), vous obtenez un processus, ne devrait pas être appelé output IMO

Voici un exemple simple qui fonctionne avec les backticks

>>> process = subprocess.Popen('echo `pwd`', stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'/Users/bakkal\n'

Ou vous pouvez utiliser la syntaxe $ (cmd)

>>> process = subprocess.Popen('echo $(pwd)', stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'/Users/bakkal\n'

Voici ce qui n'a PAS fonctionné (pour les backticks)

>>> process = subprocess.Popen(['echo', '`pwd`'], stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'\n'
>>> process = subprocess.Popen(['echo', '`pwd`'], stdout=subprocess.PIPE, shell=False)
>>> out, err = process.communicate()
>>> out
'`pwd`\n'
2
bakkal 20 juil. 2015 à 12:54

Sur POSIX, la liste d'arguments est passée à /bin/sh -c c'est-à-dire que seul le premier argument est reconnu comme une commande shell, c'est-à-dire que le shell exécute git sans aucun argument, c'est pourquoi vous voyez les informations d'utilisation. Vous devez passer la commande sous forme de chaîne si vous souhaitez utiliser shell=True. Depuis la subprocess documentation:

Sur POSIX avec shell=True, le shell par défaut est /bin/sh. Si args est un string, la chaîne spécifie la commande à exécuter via le shell. Cela signifie que la chaîne doit être formatée exactement comme elle le serait lorsqu'il est saisi à l'invite du shell. Cela inclut, par exemple, citer ou antislash échappant les noms de fichiers avec des espaces. Si args est un séquence, le premier élément spécifie la chaîne de commande, et tout les éléments supplémentaires seront traités comme des arguments supplémentaires du shell lui-même. Autrement dit, Popen fait l'équivalent de:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

Vous n'avez pas besoin de shell=True dans ce cas.

#!/usr/bin/env python
from subprocess import check_output

merge_base_output = check_output('git merge-base mybranch develop'.split(), 
                                 universal_newlines=True).strip()
diff_output = check_output('git diff --name-only mybranch'.split() +
                           [merge_base_output])
2
jfs 20 juil. 2015 à 16:32