{"thread":{"id":"64167","subject":"[bug] git check-ignore returns the wrong exit code with -v when only a negative pattern matches","startedAt":"2025-09-18T17:28:22Z","lastAt":"2025-11-29T05:02:53Z","messageCount":4,"participants":["David Goldstein","Jeff King","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"526712","messageId":"CANavNqpHqVgHshUaToS51OGVuvx5FqxROP2PssHW9OELMLeBQQ@mail.gmail.com","threadId":"64167","inReplyTo":null,"subject":"[bug] git check-ignore returns the wrong exit code with -v when only a negative pattern matches","fromName":"David Goldstein","fromEmail":"dgoldstein0@gmail.com","sentAt":"2025-09-18T17:28:05Z","receivedAt":"2025-09-18T17:28:22Z","isPatch":false,"sender":{"key":"dgoldstein0@gmail.com","avatar":null},"body":"Hey folks, I think I found a git check-ignore bug.  According to the\ndocs, git check-ignore should only exit 0 if a file is ignored, but if\nan untracked file matches a negative pattern in .gitignore (or the\nfile can be tracked if --no-index is also used), then git check-ignore\n-v <file> exits 0 when it should exit 1; without -v the exit code is\ncorrect (0).\n\nhttps://github.com/dgoldstein0/git_bug_repro has a self-contained\nreproduction + repeated explanation.\n\nThis exists in all git versions I've tested, but I haven't tried to\nget the latest dev version to check if it's still a problem in the\nlatest version.\n"},{"id":"526715","messageId":"20250918182545.GA1184978@coredump.intra.peff.net","threadId":"64167","inReplyTo":"CANavNqpHqVgHshUaToS51OGVuvx5FqxROP2PssHW9OELMLeBQQ@mail.gmail.com","subject":"Re: [bug] git check-ignore returns the wrong exit code with -v when only a negative pattern matches","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-18T18:25:45Z","receivedAt":"2025-09-18T18:25:47Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 18, 2025 at 10:28:05AM -0700, David Goldstein wrote:\n\n> Hey folks, I think I found a git check-ignore bug.  According to the\n> docs, git check-ignore should only exit 0 if a file is ignored, but if\n> an untracked file matches a negative pattern in .gitignore (or the\n> file can be tracked if --no-index is also used), then git check-ignore\n> -v <file> exits 0 when it should exit 1; without -v the exit code is\n> correct (0).\n> \n> https://github.com/dgoldstein0/git_bug_repro has a self-contained\n> reproduction + repeated explanation.\n> \n> This exists in all git versions I've tested, but I haven't tried to\n> get the latest dev version to check if it's still a problem in the\n> latest version.\n\nI can reproduce it here with the latest version. I've never looked at\nthe check-ignore code before, but it looks like the issue is something\nlike:\n\n  1. We \"count\" ignored files by seeing if the matched \"pattern\"\n     variable is left non-NULL.\n\n  2. In non-verbose mode, we set the pattern to NULL when it is a\n     negative pattern. Makes sense.\n\n  3. In verbose mode, we don't do that because we need to show the\n     pattern. So we accidentally count the entry as ignored.\n\nSo something like this makes your repo behave as you expected:\n\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex 644c9a414f..808c0e5ff4 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -117,7 +117,7 @@ static int check_ignore(struct dir_struct *dir,\n \t\t}\n \t\tif (!quiet && (pattern || show_non_matching))\n \t\t\toutput_pattern(pathspec.items[i].original, pattern);\n-\t\tif (pattern)\n+\t\tif (pattern && !(pattern->flags & PATTERN_FLAG_NEGATIVE))\n \t\t\tnum_ignored++;\n \t}\n \tfree(seen);\n\nAFAICT it has been this way since the inception of the code. I haven't\never used the exit code of check-ignore. I wonder if the current\nbehavior is actually useful, along the lines of \"exit 0 if any output\nwas shown, and 1 otherwise\". That would justify a difference in behavior\nbetween running with \"-v\" and without. But again, I've never used the\nexit code so I'm not sure in what circumstances it would be useful.\n\n-Peff\n"},{"id":"526720","messageId":"xmqqwm5v7btu.fsf@gitster.g","threadId":"64167","inReplyTo":"20250918182545.GA1184978@coredump.intra.peff.net","subject":"Re: [bug] git check-ignore returns the wrong exit code with -v when only a negative pattern matches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-18T20:19:41Z","receivedAt":"2025-09-18T20:19:44Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> AFAICT it has been this way since the inception of the code. I haven't\n> ever used the exit code of check-ignore. I wonder if the current\n> behavior is actually useful, along the lines of \"exit 0 if any output\n> was shown, and 1 otherwise\". That would justify a difference in behavior\n> between running with \"-v\" and without. But again, I've never used the\n> exit code so I'm not sure in what circumstances it would be useful.\n\nI very much agree with your assessment, as my understanding is that\nthe command is primarily for debugging your .gitignore pattern by\neyeballing the output from it (as opposed to a serious tool to see\nif a particular path is or is not ignored), so I am not surprised if\nits exit code handling is buggy, and I am not suprirsed at all if\nnobody has even noticed it is buggy ;-).\n\n\n"},{"id":"531424","messageId":"CANavNqp4ot=tNFWLfsK3Jy1RBVA3+SrkoKNm9f54a1QvhC2vXw@mail.gmail.com","threadId":"64167","inReplyTo":"xmqqwm5v7btu.fsf@gitster.g","subject":"Re: [bug] git check-ignore returns the wrong exit code with -v when only a negative pattern matches","fromName":"David Goldstein","fromEmail":"dgoldstein0@gmail.com","sentAt":"2025-11-29T05:02:37Z","receivedAt":"2025-11-29T05:02:53Z","isPatch":false,"sender":{"key":"dgoldstein0@gmail.com","avatar":null},"body":"I meant to reply with some info about how I discovered this and just\nrealized I forgot.  Anyhow I don't think it'll change how yall\nprioritize.\n\nI was reviewing a change to swap grep for ripgrep, and was trying to\nunderstand why we got different results with ripgrep with and without\n--no-ignore.  Hence, I was testing some of the files that showed up as\ndifferences with git check-ignore - which didn't really answer the\nquestion either.  So I ended up using git check-ignore -v and\ninspecting exit codes as a way to try to verify my own sanity, trying\nto understand how a file could be both ignored but not ignored, hence\nstumbling over this bug.  In the end I figured out that the\ndifferences were that my repository had tracked files which matched\n.gitignore patterns (which therefore aren't ignored files), and\nripgrep doesn't know what is tracked or not, just what matches\n.gitignore patterns.  That fully explained the apparent misbehavior\n(afaict ripgrep doesn't call git check-ignore in any way), but along\nthe way I found this check-ignore edge case.\n\nOn Thu, Sep 18, 2025 at 3:19 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Jeff King <peff@peff.net> writes:\n>\n> > AFAICT it has been this way since the inception of the code. I haven't\n> > ever used the exit code of check-ignore. I wonder if the current\n> > behavior is actually useful, along the lines of \"exit 0 if any output\n> > was shown, and 1 otherwise\". That would justify a difference in behavior\n> > between running with \"-v\" and without. But again, I've never used the\n> > exit code so I'm not sure in what circumstances it would be useful.\n>\n> I very much agree with your assessment, as my understanding is that\n> the command is primarily for debugging your .gitignore pattern by\n> eyeballing the output from it (as opposed to a serious tool to see\n> if a particular path is or is not ignored), so I am not surprised if\n> its exit code handling is buggy, and I am not suprirsed at all if\n> nobody has even noticed it is buggy ;-).\n>\n>\n"}]}