Как инвертировать `git log --grep = <pattern>` или Как показать журналы git, которые не соответствуют шаблону
Я хочу использовать git log
для отображения всех коммитов, которые не соответствуют заданному шаблону. Я знаю, что я могу использовать следующее, чтобы показать все коммиты, которые соответствуют шаблону:
git log --grep=<pattern>
Как инвертировать смысл соответствия?
Я пытаюсь игнорировать коммиты, которые "попали в версию..." в сообщении.
EDIT: я хочу, чтобы мой окончательный результат был довольно подробным. например git log --pretty --stat
. Поэтому вывод из git log --format=oneline
не будет работать для меня.
Ответы
Ответ 1
Создайте список всех коммитов, вычтите тех, чьи сообщения в журнале содержат шаблон нарушения, и подайте результат на git log
с вашими желаемыми параметрами. На завершающем этапе несколько вариантов git log
удобны:
--stdin
В дополнение к фиксации, перечисленным в командной строке, прочитайте их со стандартного ввода.
--no-walk
Покажите только данные, но не пересекайте их предков.
Вы можете сделать это с помощью единственного конвейера и замены процесса.
#! /bin/bash
if (( $# < 1 )); then
echo >&2 "Usage: $0 pattern [<since>..<until>]"
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
Если вы не хотите использовать bash, вы можете сделать это с помощью 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{$_};
}
Предполагая, что одно из вышесказанного находится в вашем PATH как 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
дает только D.
Одно из ограничений вышеуказанных реализаций заключается в том, что если вы используете шаблон, который соответствует всем коммитам, например, .
или ^
, тогда вы получите HEAD. Вот как работает git log
:
$ git log --stdin --no-walk --pretty=oneline </dev/null
83052e62f0dc1c6ddfc1aff3463504a4bf23e3c4 Z
Ответ 2
Это возможно с помощью Git 2.4+ (Q2 2015): см. совершить 22dfa8a Christoph Junghans (junghans
):
log
: преподавать --invert-grep
вариант
"git log --grep=<string>
" показывает только фиксации с сообщениями, которые соответствуют данной строке, но иногда полезно показывать только коммиты, которые не имеют определенных сообщений (например, "показывать мне те, которые не фиксируются FIXUP" ).
Первоначально у нас был флаг 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 с "секвенсером" в них:
[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
Если мне нужны сообщения без секвенсора:
> git log -2 --pretty="tformat:%s" --grep=sequencer --invert-grep
Second batch for 2.11
Merge branch 'js/git-gui-commit-gpgsign'
Ответ 3
Относительно простой метод с большой гибкостью заключается в использовании журнала git с параметром -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, чтобы сделать его немного проще.
Ответ 4
получить список всех коммитов, содержащих ваш результат, а затем отфильтровать их хэши.
git log --format=oneline | grep -v `git log --grep="bumped to version" --format="%h"`
Ответ 5
Как и в ответе briguy, grep также имеет параметр -z, чтобы он мог работать с нулевыми завершенными строками, а не с линиями. Это было бы так же просто, как инвертировать совпадение:
git log -z --color | grep -vz "bumped to version"
В целях безопасности вы можете захотеть совместить только сообщение commit. Чтобы сделать это с помощью grep, вам нужно использовать выражения перламута, чтобы соответствовать символам новой строки в нулевых завершаемых строках. Чтобы пропустить заголовок:
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
опция -z или эквивалент.
Ответ 6
Насколько я могу судить, это невозможно сделать непосредственно с одной командной строкой; вам придется сделать что-то вроде Джастина Лилли, а затем запустить "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
должен сделать трюк.
Ответ 7
Как уже упоминалось VonC, лучшим вариантом является обновление до Git 2.4.0 (которое в настоящее время находится на RC2). Но даже если вы не можете этого сделать, нет никаких оснований для разработки сценариев. A (gnu) awk one-liner должен это сделать. git log
имеет полезную опцию -z
для разделения коммитов на NUL-символ, что упрощает их анализ:
git log -z --pretty --stat | awk 'BEGIN{ RS="\0"; FS="\n\n" } !match($2, /<pattern>/)'
Если у вас нет gnu awk, вы, вероятно, должны хотя бы установить это. Или переносите этот script на вашу специальную версию awk, которую я оставляю в качестве упражнения для читателя; -).
Ответ 8
git log --pretty --stat | grep -v "bumped to version"