Pregunta Cómo invertir `git log --grep = ` o cómo mostrar registros de git que no coinciden con un patrón


Quiero usar git log para mostrar todas las confirmaciones que no coinciden con un patrón dado. Sé que puedo usar lo siguiente para mostrar todas las confirmaciones que coinciden con un patrón:

git log --grep=<pattern>

¿Cómo invierto el sentido de coincidencia?

Estoy tratando de ignorar los commits que han "topado con la versión ..." en el mensaje.

EDITAR: Quiero que mi resultado final sea bastante detallado. p.ej. git log --pretty --stat. Así que la salida de git log --format=oneline no funcionará para mí


32
2018-04-09 01:05


origen


Respuestas:


Genere una lista de todas las confirmaciones, reste aquellas cuyos mensajes de registro contienen el patrón ofensivo y envíe el resultado a git log con tus opciones deseadas En la etapa final, un par de opciones para git log son útiles:

--stdin
  Además de cometer enumerados en la línea de comando, léelos de la entrada estándar.

--no-walk
  Solo muestre las revoluciones dadas, pero no atraviese sus antepasados.

Puede hacerlo con una sola tubería y sustitución de proceso.

#! /bin/bash

if (( $# < 1 )); then
  echo >&2 "Usage: $0 pattern [<since>..<until>]"
  exit 1
fi

pattern=$1
shift

git log --format=%H $@ |
  grep -v -f <(git log --format=%H "--grep=$pattern" $@) |
  git log --pretty --stat --stdin --no-walk

Si no quieres usar bash, puedes hacerlo con Perl.

#! /usr/bin/env perl

use strict;
use warnings;
no warnings "exec";

sub usage { "Usage: $0 pattern\n" }

sub commits_to_omit {
  my($pattern) = @_;

  open my $fh, "-|", "git", "log", "--grep=$pattern", "--format=%H", @ARGV
    or die "$0: exec: $!";
  my %omit = map +($_ => 1), <$fh>;
  %omit;
}

die usage unless @ARGV >= 1;
my $pattern = shift;

my %omit = commits_to_omit $pattern;

open my $all, "-|", "git", "log", "--format=%H", @ARGV
  or die "$0: exec: $!";

open my $out, "|-", "git", "log", "--pretty", "--stat", "--stdin", "--no-walk"
  or die "$0: exec: $!";

while (<$all>) {
  print $out $_ unless $omit{$_};
}

Suponiendo que uno de los anteriores está en su RUTA como git-log-vgrep y con un historial de la forma

$ git lola
* b0f2a28 (tmp, feature1) D
* 68f87b0 C
* d311c65 B
* a092126 A
| * 83052e6 (CABEZA, origen / maestro, maestro) Z
| * 90c3d28 Y
| * 4165a42 X
| * 37844cb W
| /
* f8ba9ea V

podríamos decir

$ git log-vgrep X

para obtener Z, Y, W y V.

También puede registrar otras ramas, por lo

$ git log-vgrep A tmp

da D, C, B y V; y

$ git log-vgrep C tmp ~ 2..tmp

cede solo D.

Una limitación de las implementaciones anteriores es si usa un patrón que coincida con todas las confirmaciones, p.ej., . o ^, entonces obtendrás HEAD. Así es como git log trabajos:

$ git log --stdin --no-walk --pretty = oneline </ dev / null
83052e62f0dc1c6ddfc1aff3463504a4bf23e3c4 Z

15
2018-04-09 17:02



Esto será posible con Git 2.4+ (Q2 2015): ver cometer 22dfa8a por Christoph Junghans (junghans):

log: enseñar --invert-grep opción

"git log --grep=<string>"muestra solo confirmaciones con mensajes que coinciden con la cadena dada, pero a veces es útil poder mostrar solo las confirmaciones que hacen no tener ciertos mensajes (por ejemplo, "muéstrame los que no son compromisos de FIXUP").

Originalmente, tuvimos el invert-grep bandera en grep_opt, pero porque "git grep --invert-grep"no tiene sentido excepto en conjunción con"--files-with-matches", que ya está cubierto por"--files-without-matches", se movió a la estructura de revisiones.
  Tener la bandera allí expresa mejor la función de la función.

Cuando se ejecutan las dos pruebas recientemente insertadas, el historial se habría confirmado con mensajes "initial","second","third","fourth","fifth","sixth"   y "Second", cometido en este orden.
  Los commits que no coinciden tampoco "th"o"Sec" es "second"y"initial". Para el caso insensible a mayúsculas y minúsculas"initial" partidos.

--invert-grep

Limite la salida de confirmaciones a las que tienen un mensaje de registro que no coincide con el patrón especificado con --grep=<pattern>.

Ejemplo:

Primero grep el mensaje con "secuenciador" en ellos:

vonc@voncm C:\Users\vonc\prog\git\git

> git log -2 --pretty="tformat:%s" --grep=sequencer
Merge branch 'js/sequencer-wo-die'
sequencer: ensure to release the lock when we could not read the index

Si quiero mensajes con no secuenciador:

> git log -2 --pretty="tformat:%s" --grep=sequencer --invert-grep
Second batch for 2.11
Merge branch 'js/git-gui-commit-gpgsign'

21
2018-02-15 04:47



Un método relativamente simple con mucha flexibilidad es usar git log con la opción -z canalizada a awk. La opción -z agrega nulos entre los registros de confirmación, por lo que facilita el análisis con awk:

git log --color=always -z | awk -v RS=\\0

(color = siempre es necesario para mantener el color cuando la salida es una tubería). Entonces, es simple agregar cualquier expresión booleana que quiera que funcione en cada campo. Por ejemplo, esto imprimirá todas las entradas donde el correo electrónico del autor no es de fugly.com, y el día de la confirmación fue el domingo:

git log --color=always -z | awk -v RS=\\0 '!/Author:.*fugly.com>/ && /Date:.* Sun /'

Otra cosa agradable es que puedes agregar cualquier opción de formato o rango de revisión al registro de git, y aún funciona.

Una última cosa, si quieres paginarlo, usa "menos -r" para mantener los colores.

EDITAR: cambió para usar -v en awk para hacerlo un poco más simple.


8
2017-10-19 18:44



obtener una lista de todas las confirmaciones que contengan su resultado, luego filtrar sus valores hash.

git log --format=oneline | grep -v `git log --grep="bumped to version" --format="%h"`

1
2018-04-09 01:26



Al igual que con la respuesta de labriguy, grep también tiene una opción -z para permitir que funcione con cadenas terminadas nulas en lugar de líneas. Esto sería tan simple como invertir el partido:

git log -z --color | grep -vz "bumped to version"

Por seguridad, es posible que desee coincidir solo con el mensaje de confirmación. Para hacer esto con grep, necesita usar expresiones perladas para unir las nuevas líneas dentro de las cadenas terminadas nulas. Para saltear el encabezado:

git log -z | grep -Pvz '^commit.*\nAuthor:.*\nDate:.*\n[\S\s]*bumped to version'

O con color:

git log -z --color | \
  grep -Pvz '^.....commit.*\nAuthor:.*\nDate:.*\n[\S\s]*bumped to version'

Finalmente, si usa --stat, también puede hacer coincidir el comienzo de esta salida para evitar la coincidencia de los nombres de archivo que contienen la cadena de confirmación. Entonces una respuesta completa a la pregunta sería como:

log -z --color --pretty --stat | \
  grep -Pvz '^.....commit.*\nAuthor:.*\nDate:.*\n[\S\s]*?bumped to version[\S\s]*?\n [^ ]'

Tenga en cuenta que grep -P se describe como 'altamente experimental' en mi página man. Puede ser mejor usar pcregrep en su lugar, que usa libpcre, ver Cómo dar un patrón para una nueva línea en grep?. A pesar de que grep -P funciona bien para mí y no tengo idea si pcregrep tiene una opción -z o equivalente.


1
2017-09-21 11:10



Hasta donde puedo decir, esto no es posible hacerlo directamente con una sola línea de comando; tendrías que hacer algo como lo sugiere Justin Lilly y luego ejecutar 'git log' en la lista de hashes resultante, por ejemplo,

git log --format="%h" | grep -v `git log -1 --grep="bumped to version" --format="%h"` > good-hashes
for h in `cat good-hashes`; do
    PAGER=cat git log -1 --pretty --stat $h
done

debería hacer el truco.


0
2018-04-09 02:45



Como lo mencionó VonC, la mejor opción es si puede actualizar a Git 2.4.0 (que se encuentra actualmente en RC2). Pero incluso si no puede hacer eso, no hay razón para elaborar scripts. A (gnu) awk one-liner debería hacerlo. git log tiene el útil -z opción para separar confirmaciones por un carácter NUL que hace que sea fácil analizarlas:

git log -z --pretty --stat | awk 'BEGIN{ RS="\0"; FS="\n\n" } !match($2, /<pattern>/)'

Si no tiene gnu awk, probablemente debería al menos instalarlo. O transfiera este script a su versión específica de awk, que dejo como ejercicio para el lector ;-).


0
2018-04-21 09:11