web-dev-qa-db-fra.com

Rechercher un index sale ou des fichiers non suivis avec Git

Comment puis-je vérifier si des modifications non validées ont été apportées dans mon référentiel git:

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

à partir d'un script?

git-status semble toujours renvoyer zéro avec la version 1.6.4.2 de Git.

235
Robert Munteanu

Bon timing! J'ai écrit un article de blog à ce sujet il y a quelques jours à peine, quand j'ai découvert comment ajouter des informations sur le statut des git à mon invite.

Voici ce que je fais:

  1. Pour le 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 (notez le --porcelain flag à git status qui vous donne une sortie analysable de Nice):

    # 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 est plus pratique, vous pouvez aussi utiliser git status --porcelain pour obtenir des fichiers corrompus:

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

Noter la 2>/dev/null filtre les messages d'erreur afin que vous puissiez utiliser ces commandes sur des répertoires non-git. (Ils vont simplement retourner 0 pour le nombre de fichiers.)

Modifier:

Voici les messages:

Ajout d'informations sur le statut Git à votre invite de terminal

Invite de shell améliorée activée par Git

166
0xfe

La clé pour "scripter" de manière fiable Git consiste à utiliser les commandes de "plomberie".

Lors du changement des commandes de plomberie, les développeurs veillent à fournir des interfaces très stables (une combinaison donnée d’états de référentiel, stdin, options de ligne de commande, arguments, etc. produiront le même résultat dans toutes les versions de Git où la commande/l'option existe). De nouvelles variations de sortie dans les commandes de plomberie peuvent être introduites via de nouvelles options, mais cela ne pose aucun problème pour les programmes déjà écrits avec des versions plus anciennes (ils n'utiliseraient pas les nouvelles options, car elles n'existaient pas (ou du moins étaient pas utilisé) au moment de la rédaction du script).

Malheureusement, les commandes Git "quotidiennes" sont les commandes "porcelaine". Par conséquent, la plupart des utilisateurs de Git peuvent ne pas être familiarisés avec les commandes de plomberie. La distinction entre commande de porcelaine et commande de plomberie est faite dans la commande principale git manpage (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 (compare l’index (et peut-être des morceaux d’arbre de travail suivis) à un autre arbre (par exemple, HEAD)), peut-être git diff-files (compare l’arbre de travail à l’index), et éventuellement git ls-files (liste de fichiers; par exemple, liste de fichiers non suivis, non ignorés).

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

Pour vérifier si un référentiel a mis en place des modifications (non encore validées), utilisez ceci:

git diff-index --quiet --cached HEAD --
  • S'il existe avec 0 alors 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 contient des modifications pouvant être mises en place:

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'arbre de travail présente des modifications par rapport à HEAD:

git diff-index --quiet HEAD --
  • C'est comme une combinaison des deux précédents. Une des principales différences est qu’il ne signalera toujours "aucune différence" si vous avez un changement organisé que vous avez "annulé" dans l’arbre de travail (pour revenir au contenu qui se trouve dans HEAD). Dans cette même situation, les deux commandes distinctes renverraient toutes les deux des rapports de "différences présentes".

Vous avez également mentionné les fichiers non suivis. Vous pourriez vouloir dire "non suivi et non marqué", ou simplement "non suivi" (y compris les fichiers ignorés). D'une manière ou d'une autre, git ls-files est l'outil pour le travail:

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

git ls-files --others

Pour “non suivi et non ignoré”:

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 existe avec 0 alors il n'y a pas de fichiers non suivis. S'il existe avec 1 puis il y a des fichiers non suivis.

Il y a un petit risque que cela traduise des sorties anormales de git ls-files dans des 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 autorise des erreurs inattendues de git ls-files pour se propager. Dans ce cas, une sortie non nulle pourrait signifier "il y a des fichiers non suivis" ou une erreur. Si vous voulez plutôt que les résultats "erreur" soient combinés au résultat "pas de fichiers non suivis", utilisez test -n "$u" (où sortie de 0 signifie “certains fichiers non suivis” et non nul signifie une erreur ou “pas de fichiers non suivis”).

Une autre idée est d'utiliser --error-unmatch pour provoquer une sortie non nulle en l'absence de fichiers non suivis. Cela risquerait également de confondre "pas de fichiers non suivis" (exit 1) avec “une erreur est survenue” (sortie non nulle, mais probablement 128). Mais vérifier pour 0 contre. 1 vs. les codes de sortie non nuls sont probablement assez robustes:

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

Tout ce qui précède git ls-files exemples peuvent prendre --exclude-standard _ si vous ne souhaitez prendre en compte que les fichiers non suivis et non ignorés.

386
Chris Johnsen

En supposant que vous soyez sur git 1.7.0 ou plus tard ...

Après avoir lu toutes les réponses sur cette page et quelques expériences, je pense que la méthode qui convient le mieux pour concilier exactitude et brièveté est la suivante:

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

Bien que git permette une grande nuance entre ce qui est suivi, ignorer, non suivi mais non-ignoré, etc., je pense que le cas d'utilisation typique est l'automatisation des scripts de construction, dans lesquels vous voulez tout arrêter si votre paiement n'est pas propre.

Dans ce cas, il est logique de simuler ce que ferait le programmeur: tapez git status Et regardez le résultat. Mais nous ne voulons pas nous fier à des mots spécifiques, nous utilisons donc le mode --porcelain Introduit dans 1.7.0; lorsqu'il est activé, un répertoire vide ne génère aucun résultat.

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

Cette commande retournera 1 si le répertoire de travail est propre et 0 s'il y a des modifications à valider. Vous pouvez remplacer le -n Par un -z Si vous voulez le contraire. Ceci est utile pour chaîner cela à 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, soit une alarme"; Ce one-liner peut être préférable à une instruction if, selon le script que vous écrivez.

133
benzado

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

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

J'ai jeté un coup d'œil à quelques-unes de ces réponses ... (et j'ai eu divers problèmes sur * nix et windows, ce qui était une exigence que j'avais) ... ... a trouvé que ce qui suit 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) 

En provenance de https://github.com/sindresorhus/pure/issues/115 Merci à @paulirish pour ce partage

7
mlo55

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

  • analysera la sortie de cette commande
  • renverra le code d'erreur approprié en fonction de vos besoins

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


Comme xfe mentionne dans son excellente réponse , git status --porcelain est essentiel à toute solution basée sur un script

--porcelain

Donnez la sortie dans un format stable et facile à analyser pour les scripts.
Actuellement, cela est identique à --short output, mais est garanti pour ne pas changer à l'avenir, le rendant sûr pour les scripts.

4
VonC

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

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

Comme indiqué par Chris Johnsen , cela ne fonctionne que sur Git 1.7.0 ou plus récent.

4
Robert Munteanu

J'avais souvent besoin d'un moyen simple pour échouer une construction si, à la fin de l'exécution, il existait des fichiers suivis modifiés ou des fichiers non suivis qui n'étaient pas ignorés.

Ceci est très important pour éviter les cas où les builds produisent des restes.

Jusqu'ici, la meilleure commande que j'ai finalement utilisée ressemble à ceci:

 test -z "$(git status --porcelain | tee /dev/fd/2)" || \
     {{ echo "ERROR: git unclean at the end, failing build." && return 1 }}

Cela peut paraître un peu complexe et j'apprécierais que quiconque trouve une variante raccourcie maintienne le comportement souhaité:

  • pas de sortie et succès code de sortie si même tout est en ordre
  • code de sortie 1 s'il échoue
  • message d'erreur sur stderr expliquant pourquoi il échoue
  • afficher la liste des fichiers à l’origine de l’échec, à nouveau stderr.
2
sorin

La réponse de @ eduard-wirch était assez complète, mais comme je voulais vérifier les deux en même temps, voici ma dernière variante.

        set -eu

        u="$(git ls-files --others)"
        if ! git diff-index --name-only --quiet HEAD -- || [ -z "${u:-}" ]; then
            dirty="-dirty"
        fi

Lorsque vous n'exécutez pas avec set-e ou équivalent, nous pouvons à la place faire un u="$(git ls-files --others)" || exit 1 (ou le retourner si cela fonctionne pour une fonction utilisée)

Donc, untracked_files, n'est défini que si la commande réussit correctement.

après quoi, nous pouvons vérifier les deux propriétés et définir une variable (ou autre).

2
oliver

Vous pouvez aussi faire

git describe --dirty

. Il ajoutera le mot "-dirty" à la fin s'il détecte un arbre de travail sale. Selon git-describe(1):

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

. Mise en garde: les fichiers non suivis ne sont pas considérés comme "sales", car, comme l'indique la page de manuel, elle ne s'intéresse qu'à l'arbre de travail.

1
Linus Arver

Il s’agit d’une variante plus conviviale pour Shell permettant de déterminer si aucun fichiers non suivis existent 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 second processus, grep, et il n'est pas nécessaire de vérifier si vous êtes dans un référentiel git ou non. Ce qui est pratique pour les invites de Shell, etc.

1
docwhat

Il peut y avoir une meilleure combinaison de réponses de ce fil .. mais cela fonctionne pour moi ... pour votre .gitconfig _ [alias] section ...

          # 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
0
Alex Gray

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

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

REMARQUE:

  • Sans pour autant add --alldiff-index ne remarque pas les fichiers non suivis.
  • Normalement, je cours git reset après avoir testé le code d’erreur pour tout effacer.
0
uvsmtid