Создание 'git log' игнорирует изменения для определенных путей

Как я могу сделать git log показывать только коммиты, которые меняли файлы, отличные от тех, которые я указываю?

С git log, я могу отфильтровать коммиты, которые я вижу, тем, кто касается определенного набора путей. Я хочу, чтобы инвертировать этот фильтр так, чтобы он записывал только те пути касания, кроме указанных.

Я могу получить то, что хочу,

git log --format="%n/%n%H" --name-only | ~/filter-log.pl | git log --stdin --no-walk

где filter-log.pl:

#!/usr/bin/perl
use strict;
use warnings;

$/ = "\n/\n";
<>;

while (<>) {
    my ($commit, @files) = split /\n/, $_;

    if (grep { $_ && $_ !~ m[^(/$|.etckeeper$|lvm/(archive|backup)/)] } @files) {
        print "$commit\n";
    }
}

за исключением того, что я хочу что-то более элегантное, чем это.

Обратите внимание, что я не спрашиваю, как сделать git игнорировать файлы. Эти файлы следует отслеживать и фиксировать. Это просто, что большую часть времени мне не интересно видеть их.

Связанный вопрос: Как инвертировать` git log --grep = <pattern> `или Как показать журналы git, которые не соответствуют шаблону Это тот же вопрос, кроме сообщений commit, а не путей.

Обсуждение форума по этому вопросу с 2008 года: Re: Исключение файлов из git -diff Это выглядело многообещающим, но поток, кажется, высушил вверх.

Ответ 1

Теперь он реализован (git 1.9/2.0, первый квартал 2014 года) с введением в магии pathspec :(exclude) и его краткой формой :! в commit ef79b1f и commit 1649612, Nguyễn Thái Ngọc Duy (pclouds), документацию можно найти здесь.

Теперь вы можете регистрировать все, кроме содержимого подпапок:

git log -- . ":(exclude)sub"
git log -- . ":!sub"

Или вы можете исключить определенные элементы в этой подпапке

  • конкретный файл:

    git log -- . ":(exclude)sub/sub/file"
    git log -- . ":!sub/sub/file"
    
  • любой данный файл в sub:

    git log -- . ":(exclude)sub/*file"
    git log -- . ":!sub/*file"
    git log -- . ":(exclude,glob)sub/*/file"
    

Вы можете сделать это исключение без учета регистра!

git log -- . ":(exclude,icase)SUB"

Как отметил Кенни Эвитт

Если вы запускаете Git в оболочке Bash, используйте ':!sub' или ":\!sub" чтобы избежать ошибок bash:... event not found


Примечание: Git 2.13 (Q2 2017) добавит синоним ^ к !

Смотрите коммит 859b7f1, коммит 42ebeb9 (08 февраля 2017 г.) Линуса Торвальдса (torvalds).
(Объединено с Junio C Hamano - gitster - в коммите 015fba3, 27 февраля 2017 г.)

магия пути: добавьте ' ^ ' в качестве псевдонима для ' ! '

Выбор из ! "поскольку отрицательный путь указывает, что он не только не соответствует тому, что мы делаем для ревизий, но также является ужасным символом для расширения оболочки, поскольку требует цитирования.

Поэтому добавьте ' ^ ' в качестве альтернативного псевдонима для исключающей записи pathspec.

Ответ 2

tl; dr: shopt -s extglob && git log !(unwanted/glob|another/unwanted/glob)

Если вы используете Bash, вы можете использовать расширенный globbing , чтобы получить только нужные файлы:

$ cd -- "$(mktemp --directory)" 
$ git init
Initialized empty Git repository in /tmp/tmp.cJm8k38G9y/.git/
$ mkdir aye bee
$ echo foo > aye/foo
$ git add aye/foo
$ git commit -m "First commit"
[master (root-commit) 46a028c] First commit
 0 files changed
 create mode 100644 aye/foo
$ echo foo > bee/foo
$ git add bee/foo
$ git commit -m "Second commit"
[master 30b3af2] Second commit
 1 file changed, 1 insertion(+)
 create mode 100644 bee/foo
$ shopt -s extglob
$ git log !(bee)
commit ec660acdb38ee288a9e771a2685fe3389bed01dd
Author: My Name <[email protected]>
Date:   Wed Jun 5 10:58:45 2013 +0200

    First commit

Вы можете комбинировать это с globstar для рекурсивного действия.

Ответ 3

Вы можете временно игнорировать изменения в файле с помощью

git update-index --skip-worktree path/to/file

Вперед, все изменения этих файлов будут проигнорированы git status, git commit -a и т.д. Когда вы будете готовы зафиксировать эти файлы, просто отмените его:

git update-index --no-skip-worktree path/to/file

и зафиксировать как обычно.