175 votes

Faire en sorte que 'git log' ignore les changements pour certains chemins

Comment puis-je faire git log ne montre que les modifications qui ont changé des fichiers autres que ceux que j'ai spécifiés ?

Avec git log Je peux filtrer les commits que je vois à ceux qui touchent un ensemble donné de chemins. Ce que je veux, c'est inverser ce filtre de façon à ce que seuls les commits qui touchent des chemins autres que ceux spécifiés soient listés.

Je peux obtenir ce que je veux avec

git log --format="%n/%n%H" --name-only | ~/filter-log.pl | git log --stdin --no-walk

donde filter-log.pl est :

#!/usr/bin/perl
use strict;
use warnings;

$/ = "\n/\n";
<>;

while (<>) {
    my ($commit, @files) = split /\n/, $_;

    if (grep { $_ && $_ !~ m[^(/$|.etckeeper$|lvm/(archive|backup)/)] } @files) {
        print "$commit\n";
    }
}

mais je veux quelque chose d'un peu plus élégant que cela.

Notez que je suis pas demandant comment faire en sorte que git ignore les fichiers. Ces fichiers debe être suivis et engagés. C'est juste que, la plupart du temps, cela ne m'intéresse pas de les voir.

Question connexe : Comment inverser git log --grep=<pattern> ou Comment afficher les logs Git qui ne correspondent pas à un modèle . Il s'agit de la même question, mais pour les messages de validation plutôt que pour les chemins d'accès.

Forum de discussion sur ce sujet en 2008 : Re : Exclusion de fichiers de git-diff . Cela semblait prometteur, mais le fil de discussion semble s'être tari.

320voto

VonC Points 414372

Elle est maintenant implémentée (git 1.9/2.0, Q1 2014) avec l'introduction de magie des chemins :(exclude) et sa forme abrégée :! en commit ef79b1f y commit 1649612 , par Nguyễn Thái Ngọc Duy ( pclouds ) La documentation est disponible à l'adresse suivante aquí .

Vous pouvez maintenant tout enregistrer sauf le contenu d'un sous-dossier :

git log -- . ':(exclude)sub'
git log -- . ':!sub'

Vous pouvez également exclure des éléments spécifiques de ce sous-dossier.

  • un fichier spécifique :

      git log -- . ':(exclude)sub/sub/file'
      git log -- . ':!sub/sub/file'
  • n'importe quel fichier donné dans sub :

      git log -- . ':(exclude)sub/*file'
      git log -- . ':!sub/*file'
      git log -- . ':(exclude,glob)sub/*/file'

Vous pouvez rendre cette exclusion insensible à la casse !

git log -- . ':(exclude,icase)SUB'

En tant que Kenny Evitt a noté

N'oubliez pas d'utiliser des guillemets simples ou un échappement correct entre guillemets doubles si vous utilisez la fonction git dans un bash coquille, par exemple ':!sub' o ":\!sub" . Dans le cas contraire, vous rencontrerez bash: ... event not found erreurs


Note : Git 2.13 (Q2 2017) ajoute un synonyme ^ a !

Véase commit 859b7f1 , commit 42ebeb9 (08 février 2017) par Linus Torvalds ( torvalds ) .
(fusionné par Junio C Hamano -- gitster -- en commettre 015fba3 , 27 février 2017)

pathspec magic : ajouter ' ^ ' comme alias de ' ! '

Le choix de ' ! pour un chemin d'accès négatif ne correspond non seulement pas à ce que nous faisons pour les révisions, mais c'est aussi un caractère horrible pour l'expansion de l'interpréteur de commandes puisqu'il a besoin d'être cité.

Ajoutez donc ' ^ ' comme alias alternatif pour une entrée de pathpec exclue.


Notez qu'avant Git 2.28 (Q3 2020), l'utilisation de pathpec négatif, lors de la collecte des chemins, y compris les chemins non suivis dans l'arbre de travail, était cassée.

Véase commit f1f061e (05 Jun 2020) par Elijah Newren ( newren ) .
(fusionné par Junio C Hamano -- gitster -- en commit 64efa11 , 18 juin 2020)

dir : Correction du traitement des spécifications de chemin négatives

Rapporté par : John Millikin
Signé par : Elijah Newren

do_match_pathspec() a débuté en tant que match_pathspec_depth_1() et, par souci d'exactitude, n'était censé être appelé qu'à partir de match_pathspec_depth() . match_pathspec_depth() a ensuite été rebaptisée match_pathspec() , de sorte que l'invariant auquel nous nous attendons aujourd'hui est le suivant do_match_pathspec() n'a pas d'interlocuteurs directs en dehors de match_pathspec() .

Malheureusement, cette intention a été perdue avec le renommage des deux fonctions et les appels supplémentaires à do_match_pathspec() ont été ajoutés dans les commits

  • 75a6315f74 (" ls-files : add pathpec matching for submodules", 2016-10-07, Git v2.11.0-rc0 -- fusionner figurant sur la liste des lot n°11 )
  • 89a1f4aaf7 (" dir : if our pathpec might match files under a dir, recurse into it", 2019-09-17, Git v2.24.0-rc0).

Bien sûr, do_match_pathspec() avait un avantage important par rapport à match_pathspec() -- match_pathspec() codait en dur les drapeaux à l'une des deux valeurs, et ces nouveaux appelants devaient passer une autre valeur pour les drapeaux.

De même, bien que l'appel à do_match_pathspec() était directement incorrect, il n'y avait probablement pas de différence dans le résultat final observable, parce que le bogue signifiait simplement que fill_diretory() se retrouverait dans des répertoires inutiles.

Étant donné que les vérifications ultérieures de "does-this-path-match" sur les chemins individuels sous le répertoire entraîneraient le filtrage de ces chemins supplémentaires, la seule différence par rapport à l'utilisation de la mauvaise fonction est un calcul inutile.

Le deuxième de ces mauvais appels à do_match_pathspec() a été impliqué -- soit par mouvement direct, soit par copie+édition -- dans un certain nombre de refontes ultérieures.

Voir les commits

  • 777b420347 (" dir : synchroniser treat_leading_path() y read_directory_recursive() ", 2019-12-19, Git v2.25.0-rc0 -- fusionner )
  • 8d92fb2927 (" dir : remplacer l'algorithme exponentiel par un algorithme linéaire", 2020-04-01, Git v2.27.0-rc0 -- fusionner figurant sur la liste des lot n° 5 )
  • 95c11ecc73 ("Corriger les erreurs fill_directory() API ; make it only return matches", 2020-04-01, Git v2.27.0-rc0 -- fusionner figurant sur la liste des lot n° 5 )

Le dernier a introduit l'utilisation de do_match_pathspec() sur un fichier individuel, ce qui a eu pour effet de renvoyer des chemins d'accès individuels qui n'auraient pas dû l'être.

Le problème de l'appel do_match_pathspec() au lieu de match_pathspec() c'est que tout motif nié, tel que :!unwanted_path sera ignorée .

Ajouter un nouveau match_pathspec_with_flags() pour répondre aux besoins de spécifier des drapeaux spéciaux tout en continuant à vérifier correctement les motifs niés, ajoutez un gros commentaire au-dessus de do_match_pathspec() pour éviter que d'autres n'en fassent un usage abusif, et corriger les personnes qui font actuellement appel aux services de l'Union européenne. do_match_pathspec() pour utiliser à la place soit match_pathspec() o match_pathspec_with_flags() .

Enfin, il convient de noter que DO_MATCH_LEADING_PATHSPEC doit faire l'objet d'une attention particulière lorsqu'il s'agit de travailler avec des DO_MATCH_EXCLUDE .

Le point de DO_MATCH_LEADING_PATHSPEC est que si nous avons un chemin d'accès comme

*/Makefile

et nous vérifions un chemin de répertoire comme

src/module/component

que nous voulons considérer comme une correspondance, de sorte que nous recourons à la récursivité dans le répertoire parce qu'il puede ont un fichier nommé Makefile quelque part en dessous.

Cependant, lorsque nous utilisons un motif d'exclusion, c'est-à-dire lorsque nous avons un chemin d'accès tel que

:(exclude)*/Makefile

nous ne voulons PAS dire qu'un chemin de répertoire comme

src/module/component

est une correspondance (négative).

Bien qu'il y ait puede soit un fichier nommé Makefile quelque part sous ce répertoire, il peut y avoir d'autres fichiers et nous ne pouvons pas exclure d'emblée tous les fichiers de ce répertoire ; nous devons procéder à une récursivité et vérifier ensuite les fichiers individuellement.

Ajuster le DO_MATCH_LEADING_PATHSPEC la logique n'est activée que pour les chemins d'accès positifs.

4voto

l0b0 Points 10719

Tl;dr : shopt -s extglob && git log !(unwanted/glob|another/unwanted/glob)

Si vous utilisez Le cambriolage vous devriez être en mesure d'utiliser le globbing étendu pour n'obtenir que les fichiers dont vous avez besoin :

$ cd -- "$(mktemp --directory)" 
$ git init
Initialized empty Git repository in /tmp/tmp.cJm8k38G9y/.git/
$ mkdir aye bee
$ echo foo > aye/foo
$ git add aye/foo
$ git commit -m "First commit"
[master (root-commit) 46a028c] First commit
 0 files changed
 create mode 100644 aye/foo
$ echo foo > bee/foo
$ git add bee/foo
$ git commit -m "Second commit"
[master 30b3af2] Second commit
 1 file changed, 1 insertion(+)
 create mode 100644 bee/foo
$ shopt -s extglob
$ git log !(bee)
commit ec660acdb38ee288a9e771a2685fe3389bed01dd
Author: My Name <jdoe@example.org>
Date:   Wed Jun 5 10:58:45 2013 +0200

    First commit

Vous pouvez combiner cela avec globstar pour une action récursive.

-2voto

rubysolo Points 461

Vous pouvez temporairement ignorer les modifications d'un fichier avec :

git update-index --skip-worktree path/to/file

À l'avenir, toutes les modifications apportées à ces fichiers seront ignorées par l'application git status , git commit -a , etc. Lorsque vous êtes prêt à livrer ces fichiers, inversez simplement le processus :

git update-index --no-skip-worktree path/to/file

et valider comme d'habitude.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X