1

How to reliably convert a .gitignore file into a list of pathspec strings that can be passed to individual git commands?

I want to have a javascript function that can take any .gitignore file as input, and output a long string that can then be passed to the git diff --numstat <commit1> <commit2> command as pathspec to act as a temporary gitignore only for that operation. So the resulting strings should mimic the original gitignore rules as closely as possible in functionality.

It's not just enough to append the rules to :(exclude), since the rules are different for git pathspec compared to gitignore (e.g. not recursive by default). And lines with negation patterns would just be ignored since I found out that those aren't supported when you're also using the :(exclude) magic word.

Example .gitignore:

docs

Assumed pathspec conversion:

:(exclude,glob)**/docs :(exclude,glob)**/docs/**

Since pathspec can't match a path for both files and folders but needs separate entries for each, and when you specify glob, all patterns aren't recursive/relative by default. But glob allows for magic characters like *![] to be used.

Rules would also need to be properly escaped since they will be passed to the command line.

The goal is to covnert rules used in .gitignore to pathspec equivalents as closely as possible. AFAIK there is no existing tool for this?

asked Mar 23, 2025 at 18:26
12
  • 1
    Would it work to temporarily write a .gitignore file, then run your command, then undo the .gitignore file? If yes, this may be a decent workaround, or at least it may help guide testing for a solution to your question as asked. Commented Mar 23, 2025 at 20:07
  • 1
    @TTT I don't think it could work. git diff compares commits; .gitignore ignores untracked files, it shouldn't work with git diff and I don't know any way to make git diff to take .gitignore into account. Commented Mar 23, 2025 at 20:36
  • 1
    @phd Apparently I didn't think that all the way through when I wrote my previous comment. I think it might be more like, checkout commit2, reset mixed to commit1. (Now git diff is the changes between commit1 and commit2.) Now write a temporary .gitignore, then run git diff again to see the 'filtered" diff. (Actually this doesn't work either for modified files...only new ones.) Commented Mar 23, 2025 at 21:57
  • 1
    The biggest problem you're going to have here is, multiple gitignore patterns can match each candidate, Git only pays attention to the last match (by taking the first match it encounters checking the patterns in reverse). Caffeine-deprived me isn't sure it's even possible to get that effect with pathspec processing, it's "any positive match is checked against all exclusions". Commented Mar 23, 2025 at 23:07
  • 2
    @user30020824 Create an empty repository /path/to/foo. Run git diff --name-only <commit1> <commit2> | git -C /path/to/foo -c core.excludesFile=/path/to/gitignore check-ignore --stdin to get the ignored files. Then you can either convert these ignored files to exclude pathspecs and pass them to git diff --numstat, or parse the output of git diff --numstat and remove the ignored files. This process can be adjusted and improved. Commented Mar 25, 2025 at 1:58

1 Answer 1

1

I think one easier way to implement this(ignore files that match patterns in .gitignore) is using ATTR in pathspec.

Use new ATTR like ignore in .gitattributes, something like the following:

weekly/25_01* ignore
weekly/25_01*/** ignore

And use git diff ... -- ':(attr:!ignore)' which mean use files that is unspefied in attribute ignore. So any files not matched by weekly/25_01* and weekly/25_01*/** is included, which has the same meaning as weekly/25_01* in .gitignore

I think both .gitignore and .gitattributes use almost the same pattern specification except for some minor differences like the above. weekly/25_01* matches files and directories in .gitignore but it matches only files in .gitattributes

answered Mar 25, 2025 at 2:12
Sign up to request clarification or add additional context in comments.

1 Comment

Didn't know about the ATTR ability to ignore files. Looking at the documentation, it seems to be a bit more similar to .gitignore than pathspec. Still, the docs say it doesn't support negative patterns.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.