Frage So invertieren Sie `git log --grep = ` oder Wie zeige ich Git-Logs an, die keinem Muster entsprechen


Ich möchte benutzen git log um alle Commits anzuzeigen, die nicht mit einem bestimmten Muster übereinstimmen. Ich weiß, dass ich Folgendes verwenden kann, um alle Commits anzuzeigen, die einem Muster entsprechen:

git log --grep=<pattern>

Wie invertiere ich den Sinn der Übereinstimmung?

Ich versuche Commits zu ignorieren, die in der Nachricht "auf Version gestoßen sind".

EDIT: Ich möchte meine endgültige Ausgabe ziemlich ausführlich sein. z.B. git log --pretty --stat. Also Ausgabe von git log --format=oneline wird nicht für mich arbeiten.


32
2018-04-09 01:05


Ursprung


Antworten:


Generieren Sie eine Liste aller Commits, subtrahieren Sie diejenigen, deren Protokollnachrichten das beanstandete Muster enthalten, und füttern Sie das Ergebnis an git log mit Ihren gewünschten Optionen. In der letzten Phase, ein paar Optionen zu git log sind praktisch:

--stdin
  In Ergänzung zu verpflichten aufgelistet in der Befehlszeile, lesen Sie sie von der Standardeingabe.

--no-walk
  Zeige nur die angegebenen Drehzahlen, aber nicht ihre Vorfahren.

Sie können dies mit einer einzigen Pipeline und Prozesssubstitution tun.

#! /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

Wenn Sie bash nicht verwenden möchten, können Sie es mit Perl machen.

#! /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{$_};
}

Angenommen, einer der oben genannten Punkte befindet sich in Ihrem PATH als git-log-vgrep und mit einer Geschichte der Form

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

wir könnten sagen

$ git log-vgrep X

um Z, Y, W und V zu bekommen

Sie können auch andere Zweige protokollieren, also

$ git log-vgrep Ein tmp

gibt D, C, B und V; und

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

ergibt nur D.

Eine Einschränkung der obigen Implementierungen besteht darin, dass Sie ein Muster verwenden, das allen Commits entspricht. z.B., . oder ^Dann bekommst du HEAD. Das ist wie git log funktioniert:

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

15
2018-04-09 17:02



Dies wird mit möglich sein Git 2.4+ (Q2 2015): sehen begehe 22dfa8a durch Christoph Junghans (junghans):

log: unterrichten --invert-grep Möglichkeit

"git log --grep=<string>"zeigt nur Commits mit Nachrichten, die der angegebenen Zeichenfolge entsprechen, aber manchmal ist es nützlich, nur Commits anzeigen zu können, die dies tun nicht habe bestimmte Nachrichten (z. B. "zeige mir diejenigen, die keine FIXUP-Commits sind").

Ursprünglich hatten wir die invert-grep Flagge ein grep_opt, aber weil "git grep --invert-grep"macht keinen Sinn außer in Verbindung mit"--files-with-matches", die bereits von"--files-without-matches"wurde es in die Revisions-Struktur verschoben.
  Die Flagge dort auszudrücken drückt die Funktion zum Merkmal besser aus.

Wenn die neu eingefügten zwei Tests ausgeführt werden, wäre der Verlauf mit Nachrichten festgeschrieben worden. "initial","second","third","fourth","fifth","sixth"   und "Second", in dieser Reihenfolge begangen.
  Die Commits, die nicht übereinstimmen entweder "th" oder "Sec"ist"second" und "initial". Nur für den fallunempfindlichen Fall"initial" Streichhölzer.

--invert-grep

Begrenzen Sie die Commits-Ausgabe auf Einsen mit Protokollnachricht, die nicht mit dem angegebenen Muster übereinstimmen --grep=<pattern>.

Beispiel:

Ich grep Nachricht zuerst mit "Sequenzer" in ihnen:

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

Wenn ich Nachrichten mit haben möchte Nein Sequenzer:

> 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



Eine relativ einfache Methode mit viel Flexibilität ist die Verwendung von git log mit der Option -z piped zu awk. Die Option -z fügt Nullen zwischen Commit-Datensätzen hinzu und erleichtert so das Parsen mit awk:

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

(color = immer erforderlich, um die Färbung beizubehalten, wenn die Ausgabe eine Pipe ist). Dann ist es einfach, einen beliebigen booleschen Ausdruck hinzuzufügen, der für jedes Feld funktioniert. So werden beispielsweise alle Einträge gedruckt, bei denen die E-Mail-Adresse des Autors nicht von fugly.com stammt und der Tag des Commits Sonntag war:

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

Eine weitere nette Sache ist, dass Sie dem git-Protokoll eine beliebige Formatierungsoption oder einen Revisionsbereich hinzufügen können, und es funktioniert weiterhin.

Eine letzte Sache, wenn Sie es paginieren möchten, verwenden Sie "weniger -r", um die Farben zu behalten.

BEARBEITEN: geändert, um -v in awk zu verwenden, um es ein wenig einfacher zu machen.


8
2017-10-19 18:44



Holen Sie sich eine Liste aller Commits, die Ihr Ergebnis enthalten, und filtern Sie ihre Hashes heraus.

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

1
2018-04-09 01:26



Wie bei thebriguy's Antwort, hat grep auch eine Option -z, die es ermöglicht mit null terminierten Strings statt mit Linien zu arbeiten. Dies wäre dann so einfach wie das Invertieren der Übereinstimmung:

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

Aus Sicherheitsgründen möchten Sie möglicherweise nur innerhalb der Commit-Nachricht übereinstimmen. Um dies mit grep zu tun, müssen Sie Perl-Ausdrücke verwenden, um Newlines innerhalb der Null-terminierten Strings zu vergleichen. Um die Überschrift zu überspringen:

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

Oder mit Farbe:

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

Wenn Sie --stat verwenden, können Sie auch den Anfang dieser Ausgabe anpassen, um zu vermeiden, dass die Dateinamen mit der Übergabefolge übereinstimmen. So würde eine vollständige Antwort auf die Frage aussehen:

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

Beachten Sie, dass grep -P wird in meiner Manpage als "sehr experimentell" beschrieben. Es könnte besser sein zu verwenden pcregrep stattdessen was libpcre verwendet, siehe Wie man ein Muster für neue Zeile in Grep gibt?. Obwohl grep -P funktioniert gut für mich und ich habe keine Ahnung, ob pcregrep hat eine Option -z oder gleichwertig.


1
2017-09-21 11:10



Soweit ich das beurteilen kann, ist dies nicht direkt mit einer einzigen Befehlszeile möglich. Sie müssten etwas tun, wie Justin Lilly es vorschlägt, und dann 'git log' auf der resultierenden Liste von Hashes ausführen, z.

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

sollte den Trick machen.


0
2018-04-09 02:45



Wie von VonC erwähnt, ist die beste Option, wenn Sie auf Git 2.4.0 (das derzeit auf RC2 ist) aktualisieren können. Aber selbst wenn Sie das nicht können, gibt es keinen Grund für komplizierte Skripte. Ein (gnu) awk Einzeiler sollte es tun. git log hat das Nützliche -z Möglichkeit, Commits durch ein NUL-Zeichen zu trennen, was das Parsen vereinfacht:

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

Wenn du kein gnu awk hast, solltest du das zumindest installieren. Oder portiere dieses Skript auf deine spezifische awk-Version, die ich als Übung für den Leser belasse ;-).


0
2018-04-21 09:11



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

-1
2018-04-09 01:39