git - 使 'git log' 忽略某些路径的更改

标签 git

如何让 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 忽略这些文件。这些文件应该被跟踪和提交。只是,大多数时候,我对看到它们不感兴趣。

相关问题:How to invert `git log --grep=<pattern>` or How to show git logs that don't match a pattern这是同一个问题,除了提交消息而不是路径。

2008 年关于此主题的论坛讨论:Re: Excluding files from git-diff这看起来很有希望,但线索似乎已经枯竭。

最佳答案

它现在已经实现(git 1.9/2.0,2014 年第一季度),引入了 pathspec magic :(exclude) 及其缩写形式 :!commit ef79b1fcommit 1649612 , 经过 Nguyễn Thái Ngọc Duy (pclouds) ,可以找到文档here .

您现在可以记录除子文件夹内容以外的所有内容:

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'

作为Kenny Evitt noted

Don't forget to use single quotes or proper escaping in double quotes if you're running git in a bash shell, e.g. ':!sub' or ":\!sub". Otherwise you will run into bash: ... event not found errors


注意:Git 2.13(2017 年第 2 季度)将添加一个同义词 ^!

参见 commit 859b7f1 , commit 42ebeb9 (2017 年 2 月 8 日)Linus Torvalds (torvalds) .
(由 Junio C Hamano -- gitster -- merge 于 commit 015fba3 ,2017 年 2 月 27 日)

pathspec magic: add '^' as alias for '!'

The choice of '!' for a negative pathspec ends up not only not matching what we do for revisions, it's also a horrible character for shell expansion since it needs quoting.

因此添加“^”作为排除路径规范条目的替代别名。


请注意,在 Git 2.28(2020 年第 3 季度)之前,在收集工作树中包括未跟踪路径在内的路径时,负路径规范的使用已被破坏。

参见 commit f1f061e (2020 年 6 月 5 日)作者:Elijah Newren (newren) .
(由 Junio C Hamano -- gitster -- merge 于 commit 64efa11 ,2020 年 6 月 18 日)

dir: fix treatment of negated pathspecs

Reported-by: John Millikin
Signed-off-by: Elijah Newren

do_match_pathspec() started life as match_pathspec_depth_1() and for correctness was only supposed to be called from match_pathspec_depth(). match_pathspec_depth() was later renamed to match_pathspec(), so the invariant we expect today is that do_match_pathspec() has no direct callers outside of match_pathspec().

Unfortunately, this intention was lost with the renames of the two functions, and additional calls to do_match_pathspec() were added in commits 75a6315f74 ("ls-files: add pathspec matching for submodules", 2016-10-07, Git v2.11.0-rc0 -- merge listed in batch #11) and 89a1f4aaf7 ("dir: if our pathspec might match files under a dir, recurse into it", 2019-09-17, Git v2.24.0-rc0).

Of course, do_match_pathspec() had an important advantge over match_pathspec() -- match_pathspec() would hardcode flags to one of two values, and these new callers needed to pass some other value for flags.

Also, although calling do_match_pathspec() directly was incorrect, there likely wasn't any difference in the observable end output, because the bug just meant that fill_diretory() would recurse into unneeded directories.

Since subsequent does-this-path-match checks on individual paths under the directory would cause those extra paths to be filtered out, the only difference from using the wrong function was unnecessary computation.

The second of those bad calls to do_match_pathspec() was involved -- via either direct movement or via copying+editing -- into a number of later refactors.

See commits 777b420347 ("dir: synchronize treat_leading_path() and read_directory_recursive()", 2019-12-19, Git v2.25.0-rc0 -- merge), 8d92fb2927 ("dir: replace exponential algorithm with a linear one", 2020-04-01, Git v2.27.0-rc0 -- merge listed in batch #5), and 95c11ecc73 ("Fix error-prone fill_directory() API; make it only return matches", 2020-04-01, Git v2.27.0-rc0 -- merge listed in batch #5).

The last of those introduced the usage of do_match_pathspec() on an individual file, and thus resulted in individual paths being returned that shouldn't be.

The problem with calling do_match_pathspec() instead of match_pathspec() is that any negated patterns such as '`:!unwanted_path`` will be ignored.

Add a new match_pathspec_with_flags() function to fulfill the needs of specifying special flags while still correctly checking negated patterns, add a big comment above do_match_pathspec() to prevent others from misusing it, and correct current callers of do_match_pathspec() to instead use either match_pathspec() or match_pathspec_with_flags().

One final note is that DO_MATCH_LEADING_PATHSPEC needs special consideration when working with DO_MATCH_EXCLUDE.

The point of DO_MATCH_LEADING_PATHSPEC is that if we have a pathspec like

*/Makefile

and we are checking a directory path like

src/module/component

that we want to consider it a match so that we recurse into the directory because it _might_ have a file named Makefile somewhere below.

However, when we are using an exclusion pattern, i.e. we have a pathspec like

:(exclude)*/Makefile

we do NOT want to say that a directory path like

src/module/component

is a (negative) match.

While there might be a file named 'Makefile' somewhere below that directory, there could also be other files and we cannot pre-emptively rule all the files under that directory out; we need to recurse and then check individual files.

Adjust the DO_MATCH_LEADING_PATHSPEC logic to only get activated for positive pathspecs.

关于git - 使 'git log' 忽略某些路径的更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5685007/

相关文章:

git blame - 致命的 : bad revision '22'

git - 如何同步 bitbucket 问题和 JIRA 问题

git - 从多个分支 rebase

git 在编辑器中显示文件的旧版本

git - 如何在 git 子模块更新和 checkout 后恢复丢失的提交?

python - 在我的 python 项目中使用我自己的模块的最佳方式

c# - Libgit2Sharp:在两个标签之间的所有提交中获取文件

Git 如何 check out 一个分支的提交

git - 无法从 Git Extensions 向 GitHub 进行身份验证?

GIT:恢复到以前的提交后恢复未跟踪的文件