Come invertire `git log –grep = ` o Come mostrare log git che non corrispondono a un pattern

Voglio usare git log per mostrare tutti i commit che non corrispondono a un dato pattern. So che posso usare quanto segue per mostrare tutti i commit che corrispondono a un modello:

 git log --grep= 

Come posso invertire il senso di corrispondenza?

Sto cercando di ignorare i commit che hanno “urtato alla versione …” nel messaggio.

EDIT: voglio che il mio output finale sia piuttosto dettagliato. es. git log --pretty --stat . Quindi l’output di git log --format=oneline non funzionerà per me.

Generare un elenco di tutti i commit, sottrarre quelli i cui messaggi di log contengono il pattern offensivo e inserire il risultato nel git log con le opzioni desiderate. Nella fase finale, un paio di opzioni per git log sono utili:

--stdin
Oltre al commit elencato sulla riga di comando, leggili dallo standard input.

--no-walk
Mostra solo i giri previsti, ma non traversare i loro antenati.

Puoi farlo con una singola pipeline e processare la sostituzione.

 #! /bin/bash if (( $# < 1 )); then echo >&2 "Usage: $0 pattern [..]" exit 1 fi pattern=$1 shift git log --format=%H [email protected] | grep -v -f <(git log --format=%H "--grep=$pattern" [email protected]) | git log --pretty --stat --stdin --no-walk 

Se non vuoi usare bash, potresti farlo 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{$_}; } 

Supponendo che uno dei precedenti sia nel PATH come git-log-vgrep e con una cronologia del modulo

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

potremmo dire

  $ git log-vgrep X 

ottenere Z, Y, W e V.

Puoi anche registrare altri rami, quindi

  $ git log-vgrep A tmp 

dà D, C, B e V; e

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

produce solo D.

Una limitazione delle implementazioni di cui sopra è se si utilizza un modello che corrisponde a tutti i commit, ad es . o ^ , quindi otterrai HEAD. Ecco come funziona git log :

  $ git log --stdin --no-walk --pretty = oneline 

Questo sarà ansible con Git 2.4+ (Q2 2015) : vedi commit 22dfa8a di Christoph Junghans ( junghans ) :

log : teach --invert-grep option

git log --grep= ” mostra solo commit con messaggi che corrispondono alla stringa data, ma a volte è utile essere in grado di mostrare solo commit che non hanno determinati messaggi (es. “mostrami quelli che non sono FIXUP impegna “).

Inizialmente, avevamo grep_opt , la bandiera invert-grep , ma perché ” git grep --invert-grep ” non ha senso se non in congiunzione con ” --files-with-matches “, che è già coperto da ” --files-without-matches “, è stato spostato nella struttura delle revisioni.
Per avere la bandiera là esprime meglio la funzione per la caratteristica.

Quando i due nuovi test inseriti vengono eseguiti, la cronologia si impegna con i messaggi ” initial “, ” second “, ” third “, ” fourth “, ” fifth “, ” sixth ” e ” Second “, commessi in questo ordine.
I commit che non corrispondono a ” th ” o ” Sec ” sono ” second ” e ” initial “. Per il caso insensibile solo le corrispondenze ” initial “.

 --invert-grep 

Limita l’output di commit a quelli con messaggio di log che non corrispondono al pattern specificato con --grep= .

Esempio:

Il primo messaggio in grep con “sequencer” in loro:

 [email protected] 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 

Se voglio messaggi senza sequencer:

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

Un metodo relativamente semplice con molta flessibilità è usare git log con l’opzione -z convogliata su awk. L’opzione -z aggiunge null tra i record di commit, e quindi rende facile analizzare con awk:

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

(il colore = è sempre richiesto per mantenere la colorazione quando l’uscita è un tubo). Quindi, è semplice aggiungere qualsiasi espressione booleana che vuoi che funzioni su ogni campo. Ad esempio, questo stamperà tutte le voci in cui l’e-mail dell’autore non proviene da fugly.com e il giorno del commit è stato domenica:

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

Un’altra cosa bella è che puoi aggiungere qualsiasi opzione di formattazione o intervallo di revisione al log git, e funziona ancora.

Un’ultima cosa, se vuoi impaginare, usa “meno -r” per mantenere i colors.

EDIT: modificato per usare -v in awk per renderlo un po ‘più semplice.

ottieni una lista di tutti i commit contenenti i tuoi risultati, quindi filtra gli hash.

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

Come con la risposta di thebriguy, grep ha anche un’opzione -z per abilitarlo a lavorare con stringhe terminate null piuttosto che con linee. Questo sarebbe quindi semplice come invertire la partita:

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

Per motivi di sicurezza, si consiglia di associare solo il messaggio di commit. Per fare ciò con grep, è necessario utilizzare le espressioni perla per far corrispondere le nuove righe all’interno delle stringhe terminate da null. Per saltare l’intestazione:

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

O con il colore:

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

Infine, se si utilizza –stat, si potrebbe anche abbinare l’inizio di questo output per evitare la corrispondenza dei nomi di file contenenti la stringa di commit. Quindi una risposta completa alla domanda sarebbe simile:

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

Si noti che grep -P è descritto come “altamente sperimentale” nella mia pagina man. Potrebbe essere meglio usare invece pcregrep che usa libpcre, vedi Come dare un pattern per la nuova riga in grep? . Sebbene grep -P pcregrep bene per me e non ho idea se pcregrep abbia un’opzione -z o equivalente.

Per quanto posso dire, questo non è ansible fare direttamente con una singola riga di comando; dovresti fare qualcosa come suggerisce Justin Lilly e quindi eseguire ‘git log’ sulla lista risultante di hash, ad es.

 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 

dovrebbe fare il trucco

Come menzionato da VonC, l’opzione migliore è se è ansible aggiornare a Git 2.4.0 (che è attualmente su RC2). Ma anche se non puoi farlo non c’è alcun motivo per elaborare script. Un (gnu) awk one-liner dovrebbe farlo. git log ha l’opzione -z utile per separare commit da un carattere NUL che rende facile analizzarli:

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

Se non hai gnu awk, probabilmente dovresti installarlo almeno. Oppure porta questo script alla tua specifica versione di awk, che lascio come esercizio per il lettore ;-).

 git log --pretty --stat | grep -v "bumped to version"