Recherche d’un index sale ou de fichiers non suivis avec Git

Comment puis-je vérifier si j’ai des modifications non validées dans mon repository git:

  1. Modifications ajoutées à l’index mais non validées
  2. Fichiers non suivis

d’un script?

git-status semble toujours retourner zéro avec git version 1.6.4.2.

Bon timing! J’ai écrit un article sur ce sujet il y a quelques jours, lorsque j’ai compris comment append des informations sur l’état de git à mon invite.

Voici ce que je fais:

  1. Pour statut sale:

     # Returns "*" if the current git branch is dirty. function evil_git_dirty { [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*" } 
  2. Pour les fichiers non suivis ( --porcelain drapeau --porcelain to git status qui vous donne une belle sortie d’parsing):

     # Returns the number of untracked files function evil_git_num_untracked_files { expr `git status --porcelain 2>/dev/null| grep "^??" | wc -l` } 

Bien que git diff --shortstat soit plus pratique, vous pouvez également utiliser git status --porcelain pour obtenir des fichiers sales:

 # Get number of files added to the index (but uncommitted) expr $(git status --porcelain 2>/dev/null| grep "^M" | wc -l) # Get number of files that are uncommitted and not added expr $(git status --porcelain 2>/dev/null| grep "^ M" | wc -l) # Get number of total uncommited files expr $(git status --porcelain 2>/dev/null| egrep "^(M| M)" | wc -l) 

Remarque: Le 2>/dev/null filtre les messages d’erreur afin que vous puissiez utiliser ces commandes sur des répertoires non-git. (Ils retourneront simplement 0 pour le nombre de fichiers.)

Modifier :

Voici les articles:

Ajout d’informations sur l’état de Git à votre invite de terminal

Invite améliorée du shell compatible avec Git

La clé du «scripting» de Git est d’utiliser les commandes «plumbing».

Les développeurs font attention lors du changement des commandes de plomberie pour s’assurer qu’ils fournissent des interfaces très stables (c’est-à-dire qu’une combinaison donnée d’état de référentiel, stdin, options de ligne de commande, etc. produira la même sortie dans toutes les versions de option existe). De nouvelles variations de sortie dans les commandes de plomberie peuvent être introduites via de nouvelles options, mais cela ne peut pas poser de problèmes pour les programmes déjà écrits sur des versions plus anciennes (ils n’utiliseraient pas les nouvelles options car elles n’existaient pas pas utilisé) au moment où le script a été écrit).

Malheureusement, les commandes Git «quotidiennes» sont les commandes «porcelaines», de sorte que la plupart des utilisateurs Git ne sont pas familiers avec les commandes de plomberie. La distinction entre la porcelaine et la commande de plomberie est faite dans la page de manuel principale de git (voir les sous-sections intitulées Commandes de haut niveau (porcelaine) et Commandes de bas niveau (plomberie)) .


Pour en savoir plus sur les modifications non validées, vous aurez probablement besoin de git diff-index (comparez l’index (et peut-être les bits de l’arbre de travail) à d’autres arborescences (par exemple HEAD )), peut git diff-files . et peut-être git ls-files ( git ls-files liste, par exemple liste des fichiers non enregistrés, non enregistrés).

(Notez que dans les commandes ci-dessous, HEAD -- est utilisé à la place de HEAD car sinon la commande échoue s’il existe un fichier nommé HEAD .)

Pour vérifier si un référentiel a des modifications par étapes (pas encore validées), utilisez ceci:

 git diff-index --quiet --cached HEAD -- 
  • S’il existe avec 0 il n’y avait pas de différences ( 1 signifie qu’il y avait des différences).

Pour vérifier si un arbre de travail comporte des modifications pouvant être mises en scène:

 git diff-files --quiet 
  • Le code de sortie est le même que pour git diff-index ( 0 == pas de différences; 1 == différences).

Pour vérifier si la combinaison de l’index et des fichiers suivis dans l’arborescence de travail présente des modifications par rapport à HEAD :

 git diff-index --quiet HEAD -- 
  • C’est comme une combinaison des deux précédentes. La principale différence réside dans le fait qu’elle rapportera toujours «aucune différence» si vous avez un changement par étapes que vous avez «annulé» dans l’arborescence de travail (retour au contenu de HEAD ). Dans cette même situation, les deux commandes distinctes renverraient toutes deux des rapports de «différences présentes».

Vous avez également mentionné des fichiers non suivis. Vous pourriez vouloir dire «non suivi et sans titre», ou simplement «non suivi» (y compris les fichiers ignorés). Dans tous les cas, git ls-files est l’outil de travail:

Pour «non suivi» (inclura les fichiers ignorés, le cas échéant):

 git ls-files --others 

Pour “non suivi et sans titre”:

 git ls-files --exclude-standard --others 

Ma première pensée est de vérifier si ces commandes ont une sortie:

 test -z "$(git ls-files --others)" 
  • S’il se termine avec 0 il n’y a pas de fichiers non suivis. S’il quitte avec 1 il y a des fichiers non suivis.

Il y a une petite chance que cela traduise des sorties anormales de git ls-files en rapports «pas de fichiers non suivis» (les deux entraînent des sorties non nulles de la commande ci-dessus). Une version un peu plus robuste pourrait ressembler à ceci:

 u="$(git ls-files --others)" && test -z "$u" 
  • L’idée est la même que la commande précédente, mais elle permet aux erreurs inattendues de git ls-files de se propager. Dans ce cas, une sortie non nulle pourrait signifier “des fichiers non suivis” ou une erreur. Si vous voulez que les résultats “erreur” soient combinés avec le résultat “pas de fichiers non suivis”, utilisez test -n "$u" (où exit de 0 signifie “certains fichiers non suivis”, et non zéro signifie erreur ou “pas de fichiers non suivis”). ”).

Une autre idée est d’utiliser --error-unmatch pour provoquer une sortie non nulle lorsqu’il n’y a pas de fichiers non suivis. Cela risque également de confondre «aucun fichier non suivi» (sortie 1 ) avec «une erreur est survenue» (sortie non nulle, mais probablement 128 ). Mais vérifier les codes de sortie 0 vs 1 vs non nul est probablement assez robuste:

 git ls-files --others --error-unmatch . >/dev/null 2>&1; ec=$? if test "$ec" = 0; then echo some untracked files elif test "$ec" = 1; then echo no untracked files else echo error from ls-files fi 

N’importe lequel des exemples ci-dessus de git ls-files peut prendre --exclude-standard si vous ne souhaitez considérer que les fichiers non suivis et non enregistrés.

En supposant que vous êtes sur git 1.7.0 ou plus tard …

Après avoir lu toutes les réponses sur cette page et fait des expériences, je pense que la méthode qui réussit la bonne combinaison de la justesse et de la concision est la suivante:

 test -n "$(git status --porcelain)" 

Bien que git permette beaucoup de nuances entre ce qui est suivi, ignoré, non suivi mais non signé, etc., je pense que le cas d’utilisation typique est l’automatisation des scripts de construction, où vous devez tout arrêter si votre contrôle n’est pas net.

Dans ce cas, il est judicieux de simuler ce que ferait le programmeur: tapez git status et regardez la sortie. Mais nous ne voulons pas compter sur des mots spécifiques apparaissant, nous utilisons donc le mode --porcelain introduit en 1.7.0; Lorsqu’il est activé, un répertoire propre ne génère aucune sortie.

Ensuite, nous utilisons test -n pour voir s’il y a eu une sortie ou non.

Cette commande renvoie 1 si le répertoire de travail est propre et 0 si des modifications doivent être effectuées. Vous pouvez changer le -n à -z si vous voulez le contraire. Ceci est utile pour enchaîner ceci à une commande dans un script. Par exemple:

 test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN" 

Cela dit effectivement “soit il n’y a aucune modification à apporter ou déclencher une alarme”; Ce one-liner peut être préférable à une instruction if en fonction du script que vous écrivez.

Une implémentation de la réponse de VonC :

 if [[ -n $(git status --porcelain) ]]; then echo "repo is dirty"; fi 

Regardé à travers quelques-unes de ces réponses … (et avait divers problèmes sur * nix et Windows, ce qui était une exigence que j’avais) … trouvé les éléments suivants fonctionnait bien …

 git diff --no-ext-diff --quiet --exit-code 

Pour vérifier le code de sortie dans * nix

 echo $? #returns 1 if the repo has changes (0 if clean) 

Pour vérifier le code de sortie dans la fenêtre $

 echo %errorlevel% #returns 1 if the repos has changes (0 if clean) 

Source: https://github.com/sindresorhus/pure/issues/115 Merci à @paulirish pour ce partage pour le partage

Pourquoi ne pas encapsuler le git status avec un script qui:

  • parsingra la sortie de cette commande
  • renverra le code d’erreur approprié en fonction de ce dont vous avez besoin

De cette façon, vous pouvez utiliser ce statut «amélioré» dans votre script.


Comme 0xfe le mentionne dans son excellente réponse , git status --porcelain est déterminant dans toute solution basée sur un script

 --porcelain 

Donnez la sortie dans un format stable et facile à parsingr pour les scripts.
Actuellement, il est identique à la --short output , mais il est garanti qu’il ne changera pas à l’avenir, ce qui le rend sûr pour les scripts.

Une possibilité de bricolage, mise à jour pour suivre la suggestion de 0xfe

 #!/bin/sh exit $(git status --porcelain | wc -l) 

Comme l’a noté Chris Johnsen , cela ne fonctionne que sur Git 1.7.0 ou plus récent.

Ceci est une variante plus conviviale pour savoir s’il existe des fichiers non suivis dans le référentiel:

 # Works in bash and zsh if [[ "$(git status --porcelain 2>/dev/null)" = *\?\?* ]]; then echo untracked files fi 

Cela ne crée pas un deuxième processus, grep , et n’a pas besoin de vérifier si vous êtes dans un repository git ou non. Ce qui est pratique pour les invites de shell, etc.

Vous pouvez aussi faire

 git describe --dirty 

. Il appenda le mot “-dirty” à la fin s’il détecte un arbre de travail sale. Selon git-describe(1) :

  --dirty[=] Describe the working tree. It means describe HEAD and appends  (-dirty by default) if the working tree is dirty. 

. Avertissement: les fichiers non suivis ne sont pas considérés comme “sales”, car, comme l’indique la page de manuel, ils ne concernent que l’arborescence de travail.

Il y a peut-être une meilleure combinaison de réponses de ce fil de discussion .. mais cela fonctionne pour moi … pour la .gitconfig [alias] de votre .gitconfig

  # git untracked && echo "There are untracked files!" untracked = ! git status --porcelain 2>/dev/null | grep -q "^??" # git unclean && echo "There are uncommited changes!" unclean = ! ! git diff --quiet --ignore-submodules HEAD > /dev/null 2>&1 # git dirty && echo "There are uncommitted changes OR untracked files!" dirty = ! git untracked || git unclean 

Le test automatique le plus simple que j’utilise pour détecter l’ état sale = tout changement, y compris les fichiers non suivis :

 git add --all git diff-index --exit-code HEAD 

REMARQUE:

  • Sans add --all diff-index ne remarque pas les fichiers non suivis.
  • Normalement, je lance git reset après avoir testé le code d’erreur pour tout décompresser.

Voici le meilleur moyen le plus propre. La réponse sélectionnée n’a pas fonctionné pour une raison quelconque, elle n’a pas détecté de changements dans de nouveaux fichiers qui n’étaient pas validés.

 function git_dirty { text=$(git status) changed_text="Changes to be committed" untracked_files="Untracked files" dirty=false if [[ ${text} = *"$changed_text"* ]];then dirty=true fi if [[ ${text} = *"$untracked_files"* ]];then dirty=true fi echo $dirty }