Hacer que 'git log' ignore los cambios para ciertas rutas

121

¿Cómo puedo git logmostrar solo confirmaciones que cambiaron archivos distintos de los que especifiqué?

Con git log, puedo filtrar las confirmaciones que veo a aquellas que tocan un conjunto determinado de rutas. Lo que quiero es invertir ese filtro para que solo se enumeren las rutas táctiles que no sean las especificadas.

Puedo conseguir lo que quiero con

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

donde filter-log.plesta:

#!/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";
    }
}

excepto que quiero algo algo más elegante que eso.

Tenga en cuenta que estoy no preguntando cómo hacer git ignorar los archivos. Estos archivos deben ser rastreados y confirmados. Es solo que, la mayoría de las veces, no me interesa verlos.

Pregunta relacionada: Cómo invertir `git log --grep = <pattern>` o Cómo mostrar los registros de git que no coinciden con un patrón Es la misma pregunta excepto para los mensajes de confirmación en lugar de las rutas.

Discusión en el foro sobre este tema desde 2008: Re: Exclusión de archivos de git-diff Esto parecía prometedor, pero el hilo parece haberse secado.

Anonymoose
fuente
No estoy seguro de si existe una forma incorporada, y su solución de Perl parece bastante decente. Si lo modifica para aceptar las rutas como argumentos de la línea de comandos, podría simplemente crear un alias similar !f() { git log ... | path/to/filter-log.pl "$@" | git log --stdin --no-walk; f, o incluso incluir esa parte de la canalización en el script también.
Cascabel
Como solución temporal, utilizo findpara filtrar los directorios cuyas confirmaciones no quiero ver. Si quisiera ignorar las entradas de registro de las confirmaciones realizadas en el directorio de nivel raíz SiteConfig, diría:git log `find . -type d -mindepth 1 -maxdepth 1 ! -name *SiteConfig`
Noah Sussman
Para Git 1.9 / 2.0 (Q1 2014), vea mi respuesta a continuación : git log --oneline --format=%s -- . ":!sub"funcionará (con la magia de pathpec :(exclude)y su forma corta:! )
VonC

Respuestas:

214

Está implementado ahora (git 1.9 / 2.0, primer trimestre de 2014) con la introducción pathpec magic :(exclude)y su forma corta:! en commit ef79b1f y commit 1649612 , por Nguyễn Thái Ngọc Duy ( pclouds) , la documentación se puede encontrar aquí .

Ahora puede registrar todo excepto el contenido de una subcarpeta:

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

O puede excluir elementos específicos dentro de esa subcarpeta

  • un archivo específico:

      git log -- . ":(exclude)sub/sub/file"
      git log -- . ":!sub/sub/file"
  • cualquier archivo dado dentro de sub:

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

¡Puede hacer que esa exclusión no distinga entre mayúsculas y minúsculas!

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

Como señaló Kenny Evitt

Si está ejecutando Git en un shell Bash, use ':!sub'o en su ":\!sub"lugar para evitar bash: ... event not founderrores


Nota: Git 2.13 (Q2 2017) agregará un sinónimo ^a!

Consulte la confirmación 859b7f1 , la confirmación 42ebeb9 (08 de febrero de 2017) por Linus Torvalds ( torvalds) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 015fba3 , 27 de febrero de 2017)

magia de pathpec: agregue ' ^' como alias para ' !'

La elección de " !" para una especificación de ruta negativa no solo no coincide con lo que hacemos para las revisiones, sino que también es un carácter horrible para la expansión de shell, ya que necesita comillas.

Por lo tanto, agregue ' ^' como un alias alternativo para una entrada de especificación de ruta excluyente.


Tenga en cuenta que, antes de Git 2.28 (tercer trimestre de 2020), se interrumpió el uso de la especificación de rutas negativas, mientras se recopilaban rutas que incluían las sin seguimiento en el árbol de trabajo.

Consulte la confirmación f1f061e (5 de junio de 2020) de Elijah Newren ( newren) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 64efa11 , 18 de junio de 2020)

dir: corregir el tratamiento de las rutas negadas

Reportado por: John Millikin
Firmado por: Elijah Newren

do_match_pathspec()comenzó la vida como match_pathspec_depth_1()y para la corrección solo se suponía que debía ser llamado match_pathspec_depth(). match_pathspec_depth()luego fue renombrado amatch_pathspec() , por lo que el invariante que esperamos hoy es que do_match_pathspec()no tenga llamadas directas fuera de match_pathspec().

Desafortunadamente, esta intención se perdió con los cambios de nombre de las dos funciones, y do_match_pathspec()se agregaron llamadas adicionales a en las confirmaciones 75a6315f74 (" ls-files: agregar coincidencias de pathpec para submódulos", 2016-10-07, Git v2.11.0-rc0 - fusión listada en lote # 11 ) y 89a1f4aaf7 (" dir: si nuestra especificación de ruta puede coincidir con archivos bajo un directorio, recurrir a él", 2019-09-17, Git v2.24.0-rc0).

Por supuesto, do_match_pathspec()tenía una ventaja importante match_pathspec(): match_pathspec()codificaría las banderas en uno de dos valores, y estos nuevos llamadores necesitaban pasar algún otro valor para las banderas.

Además, aunque llamar do_match_pathspec()directamente fue incorrecto, probablemente no hubo ninguna diferencia en el resultado final observable, porque el error solo significaba que fill_diretory()se repetía en directorios innecesarios.

Dado que las comprobaciones posteriores de coincidencias de coincidencias en las rutas individuales del directorio provocarían que se filtraran esas rutas adicionales, la única diferencia con el uso de la función incorrecta era el cálculo innecesario.

La segunda de esas malas llamadas a do_match_pathspec()estuvo involucrada, ya sea mediante movimiento directo o mediante copia + edición, en una serie de refactores posteriores.

Consulte las confirmaciones 777b420347 (" dir: sincronizar treat_leading_path()y read_directory_recursive()", 2019-12-19, Git v2.25.0-rc0 - merge ), 8d92fb2927 (" dir: reemplazar el algoritmo exponencial por uno lineal", 2020-04-01, Git v2.27.0 -rc0: fusión enumerada en el lote n. ° 5 ) y 95c11ecc73 ("Corregir fill_directory()API propensa a errores ; hacer que solo devuelva coincidencias", 2020-04-01, Git v2.27.0-rc0 - combinación en lista en lote n. ° 5 ) .

El último de los que introdujo el uso de do_match_pathspec() en un archivo individual y, por lo tanto, dio como resultado que se devolvieran rutas individuales que no deberían ser.

El problema de llamar en do_match_pathspec()lugar de match_pathspec()es que se ignorará cualquier patrón negado como '`:! Ruta_un_seada' ' .

Agregue una nueva match_pathspec_with_flags()función para satisfacer las necesidades de especificar indicadores especiales sin dejar de verificar correctamente los patrones negados, agregue un gran comentario arriba do_match_pathspec()para evitar que otros lo hagan mal y corrija a las personas que llaman actualmente do_match_pathspec()para que usen match_pathspec()omatch_pathspec_with_flags() .

Una nota final es que DO_MATCH_LEADING_PATHSPECnecesita una consideración especial cuando se trabaja con DO_MATCH_EXCLUDE.

El punto DO_MATCH_LEADING_PATHSPECes que si tenemos un pathpec como

*/Makefile

y estamos comprobando una ruta de directorio como

src/module/component

que queremos considerarlo una coincidencia para que recurramos al directorio porque _might_ tiene un archivo llamadoMakefile algún lugar debajo.

Sin embargo, cuando usamos un patrón de exclusión, es decir, tenemos una especificación de ruta como

:(exclude)*/Makefile

NO queremos decir que una ruta de directorio como

src/module/component

es una coincidencia (negativa).

Mientras pueda haber un archivo llamado 'Makefile' en algún lugar debajo de ese directorio, también podría haber otros archivos y no podemos descartar preventivamente todos los archivos de ese directorio; necesitamos recurrir y luego verificar archivos individuales.

Ajuste la DO_MATCH_LEADING_PATHSPEClógica para que solo se active para especificaciones de ruta positivas.

VonC
fuente
7
¿Puedes hacer varios archivos?
Justin Thomas
12
@JustinThomas Creo (aún no probado) que puede repetir ese patrón de exclusión de ruta varias veces ":(exclude)pathPattern1" ":(exclude)pathPattern2", ignorando por lo tanto múltiples carpetas / archivos.
VonC
7
Si está ejecutando Git en un shell Bash, utilícelo ':!sub'para evitar bash: ... event not founderrores . ":\!sub"no funciona.
Kenny Evitt
1
@KennyEvitt Gracias por editar y comentar. He incluido este último en la respuesta para una mayor visibilidad.
VonC
2
Para aquellos que se preguntan dónde está la documentación oficial sobre esta funcionalidad, consulte git help glossary(que encontré enumerada en git help -g[que encontré sugerida en git help]).
Ravron
4

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

Si está usando Bash , debería poder usar la función de globbing extendida para obtener solo los archivos que necesita:

$ 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 <[email protected]>
Date:   Wed Jun 5 10:58:45 2013 +0200

    First commit

Puede combinar esto con globstarpara acciones recursivas.

l0b0
fuente
7
Esto no muestra confirmaciones que afecten a archivos que ya no existen. Muy cerca y buen truco de todos modos.
Anonymoose
-2

Puede ignorar temporalmente los cambios en un archivo con:

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

En el futuro, todos los cambios en esos archivos serán ignorados por git status, git commit -a, etc. Cuando esté listo para cometer esos archivos, simplemente revertirla:

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

y comprometerse con normalidad.

rubysolo
fuente
9
Esto parece abordar una situación ligeramente diferente. git update-index --skip-worktreeno hace git logque se filtren las confirmaciones que ya se han realizado.
Anonymoose