Как инвертировать 'git log --grep=' или как показать журналы git, которые не соответствуют шаблону

Я хочу использовать git log показать все коммиты, которые не соответствуют заданному шаблону. Я знаю, что могу использовать следующее, чтобы показать все коммиты, которые соответствуют шаблону:

git log --grep=<pattern>

как мне инвертировать чувство соответствия?

Я пытаюсь игнорировать коммиты ,которые " наткнулись на версию ..."в сообщении.

EDIT: я хочу, чтобы мой конечный результат был довольно подробным. например,git log --pretty --stat. Итак, вывод из git log --format=oneline не будет работать для меня.

8 ответов


создать список всех коммитов, вычесть те, чьи сообщения журнала содержат оскорбительный шаблон, и передать результат в git log с нужными параметрами. На заключительном этапе, несколько вариантов, чтобы git log удобная:

--stdin
В дополнение к фиксация перечисленные в командной строке, прочитайте их из стандартного ввода.

--no-walk
Показывать только заданные обороты, но не пересекать их предки.

вы можете сделать это с помощью одного конвейера и замены процесса.

#! /bin/bash

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

pattern=
shift

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

если вы не хотите использовать bash, вы можете сделать это с Perl.

#! /usr/bin/env perl

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

sub usage { "Usage:  pattern\n" }

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

  open my $fh, "-|", "git", "log", "--grep=$pattern", "--format=%H", @ARGV
    or die ": 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 ": exec: $!";

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

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

предполагая, что один из вышеперечисленных находится на вашем пути как git-log-vgrep и с историей формы

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

мы могли бы сказать

$ git log-vgrep X

чтобы получить Z, Y, W и V.

вы также можете регистрировать другие ветви, так что

$ git log-vgrep A tmp

дает D, C, B, и V; и

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

дает просто Д.

одним из ограничений вышеуказанных реализаций является использование шаблона, который соответствует всем коммитам,например, . или ^, тогда вы получите голову. Вот как!--7--> работает:

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

это будет возможно с Git 2.4+ (Q2 2015): см.совершить 22dfa8a by Кристоф Junghans (junghans):

log: teach --invert-grep опции

"git log --grep=<string> " показывает только коммиты с сообщениями, которые соответствуют данной строке, но иногда полезно иметь возможность показывать только коммиты, которые делают не есть определенные сообщения (например, "покажите мне те, которые не фиксируют фиксации").

первоначально у нас был invert-grep флаг grep_opt, но и потому, что "git grep --invert-grep" не имеет смысла кроме как в сочетании с "--files-with-matches", который уже покрыт "--files-without-matches", он был перенесен в структуру ревизий.
Чтобы флаг там выражал функцию к функции лучше.

при запуске новых вставленных двух тестов история будет иметь фиксации с сообщениями"initial","second","third","fourth","fifth","sixth" и "Second", совершено в таком порядке.
Коммиты, которые не соответствуют ни "th" или "Sec" является "second" и "initial". Для случая нечувствительного случая только"initial" матчей.

--invert-grep

ограничьте выходные данные коммитов сообщениями журнала, которые не соответствуют шаблону, указанному с --grep=<pattern>.

пример:

я первое сообщение grep с "секвенсором"в них:

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

Если Я хотите сообщения с нет секвенсор:

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

относительно простой метод с большой гибкостью-использовать git log с опцией-z, переданной в awk. Опция-z добавляет нули между записями фиксации и поэтому упрощает синтаксический анализ с помощью awk:

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

(цвет=всегда требуется, чтобы сохранить окраску, когда выход является трубой). Затем его просто добавить любое логическое выражение, которое вы хотите, которое работает на каждом поле. Например, это будет печатать все записи, где автор электронной почты не от fugly.com и день совершения было воскресенье:

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

еще одна хорошая вещь - вы можете добавить в любой параметр форматирования или диапазон ревизий в журнал git, и он все еще работает.

последнее, если вы хотите разбить его на страницы, Используйте "less-r", чтобы сохранить цвета.

EDIT: изменено на использование -v в awk, чтобы сделать его немного проще.


получите список всех коммитов, содержащих ваш результат, а затем отфильтруйте их хэши.

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

как и в ответе thebriguy, grep также имеет опцию a-z, чтобы позволить ему работать с нулевыми завершенными строками, а не строками. Это было бы так же просто, как перевернуть матч:

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

для безопасности вы можете соответствовать только в сообщении фиксации. Чтобы сделать это с grep, вам нужно использовать выражения pearl для соответствия новым строкам в строках с нулевым завершением. Чтобы пропустить заголовок:

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

или с цветом:

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

наконец, при использовании -- stat, вы также можете сопоставить начало этого вывода, чтобы избежать совпадения имен файлов, содержащих строку фиксации. Так что полный ответ на вопрос будет выглядеть так:

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

отметим, что grep -P описывается как "очень экспериментальный" в моей справочной странице. Возможно, лучше использовать pcregrep вместо этого, который использует libpcre, см. как дать шаблон для новой строки в grep?. Хотя grep -P отлично работает для меня и я не знаю, если pcregrep имеет вариант a-z или аналог.


насколько я могу судить, это невозможно сделать непосредственно с помощью одной командной строки; вам нужно будет сделать что-то вроде предложения Джастина Лилли, а затем запустить "git log" в результирующем списке хэшей, например,

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

следует сделать трюк.


как упоминалось VonC, лучшим вариантом является обновление до Git 2.4.0 (который в настоящее время находится на RC2). Но даже если вы не можете этого сделать, нет причин для сложных сценариев. (Gnu) awk one-liner должен это сделать. git log имеет полезную -z возможность разделения коммитов нулевым символом, что упрощает их анализ:

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

Если у вас нет gnu awk, вы, вероятно, должны по крайней мере установить это. Или перенесите этот скрипт на вашу конкретную версию awk, которую я оставляю как упражнение для читателя ;-).


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