Git log - How to filter (exclude) files from appearing in `git log`? (git pathspec magic)
Asked Answered
H

1

17

I need to use the git-log command to create a report of the number of added and removed lines by commit, on average between two dates.

Currently the command I use is:

git log --since="2015-12-01" --until="2015-12-31" --shortstat

But I need to filter some files in the process. Thoses files are autogenerated, and we don't want to see their influence. They are easily recognizes by their name *.generated.*

I choose to use the git-log command, I am able to get the report I need, except I don't see how to filter those unwanted files.

The doc is big, I already read it several times, but I don't see anything about filtering files based on their names. Is this possible, or do I have to find another command to find the number of lines added/deleted by commit?

Hausa answered 3/3, 2016 at 13:46 Comment(4)
Why do you even keep generated files under version control?! I'd say that's the actual issue.Rosauraroscius
Let's say that's another issue for another team where I have no power :)Hausa
Would running the result through grep -vF '.generated.' do?Rosauraroscius
the git log command does not enumerate all files. You just get how many files have been modified (add or deleted) in one commitHausa
H
28

The "secret" on how to do it is called:


pathspec magic


You Can simply use this format (introduced in git version >1.9):

# Use this syntax, pay attention to all the parameters and the syntax

# Unix: 
git log <any required flags> -p  -- . ':(exclude)*.generated.*'

# Windows (double quote) [ Thank to @Cyril Gandon for noticing it]:
# (double quote) should work on all OS as well
git log <any required flags> -p  -- . ":(exclude)*.generated.*"

What is this weird syntax?

This syntax is called pathspec magic.
Using this syntax you can "tell" git which file extensions to exclude. In your case it's the *.generated.*


From the doc:

http://git-scm.com/docs/gitglossary.html:

A pathspec that begins with a colon : has special meaning.

In the short form, the leading colon : is followed by zero or more magic signature letters (which optionally is terminated by another colon :), and the remainder is the pattern to match against the path.

The magic signature consists of ASCII symbols that are neither alphanumeric, glob, regex special characters nor colon. The optional colon that terminates the magic signature can be omitted if the pattern begins with a character that does not belong to "magic signature" symbol set and is not a colon.

In the long form, the leading colon : is followed by a open parenthesis (, a comma-separated list of zero or more magic words, and a close parentheses ), and the remainder is the pattern to match against the path.


Note

In older versions (the feature was introduced in git v1.9 and the bug was fixed in git 1.9.5) there was a bug which was fixed.

https://github.com/git/git/commit/ed22b4173bd8d6dbce6236480bd30a63dd54834e


Demo:

git log --stat

(check the last commit)
enter image description here

And the same runt with the filer - you can see that there is only one file in the results instead of 2

git log --stat -p -- . ':(exclude)*dal.js*'

enter image description here

Hendricks answered 3/3, 2016 at 14:33 Comment(14)
This is documented in the gitglossary man page (and apparently almost nowhere else).Canotas
Agreed, this why i added it + doc :-). Its not a simply question and you need to know git pretty well to answer it. :-)Hendricks
This looks like sorcery. what does -p -- . means? I tried git log --since="2015-12-01" --until="2015-12-31" --shortstat -p -- . ':(exclude)*.generated.*' but I got a whole lot of new lines, specifically each files are returned in the stdout, with the diff for each files. Is that normal?Hausa
-p stands for <path>, . stands for the current directory (recursive) and yep the result is normal :-)Hendricks
What ever I put in the exclusion pattern, the result neverchange, files are still take into account even if I try to exclude them. Even . return something, I was expected that git log --since="2015-12-01" --until="2015-12-31" --shortstat -p -- . ':(exclude)*.*' to be emptyHausa
I added a sample screenshot to show you how it should look like.Hendricks
If yo uwant to elude them all use this: ':(exclude)*' (ant not *.*)Hendricks
I have to be particulary incompetent today :) git log --stat -p -- . ':(exclude)*' still give me result. It's like exclusion doesn't do a thing. Could it be a git version problem?Hausa
Which git version are you using, its only working from certain version and above:-)Hendricks
I have breathe, and it's working like a charm now. Don't know why it didn't work, but thank you!Hausa
I KNOW, it was quote! on windows you need double quote :)Hausa
@codeWizard : typo in your comment git log -p : -p stands for patch, and is not necessary in your examples, nor for the OP's needs. It displays a detailed diff for each listed commit.Damiandamiani
Thanks! Also, good to know you can add more than one e.g. git log -p v3.5.0~..master -- . ':(exclude)yarn.lock' ':(exclude)README.md'Jutta
Apparently this also works in newer git versions: git log -- :!<path>, could not find documentation for itLatour

© 2022 - 2024 — McMap. All rights reserved.