.gitignore not working: a file listed in it still shows up as modified: in git status and keeps going into commits. Ignore rules only apply to files Git does not track yet, and this file was committed before the rule existed. Stop tracking it with git rm --cached <file>, or git rm -r --cached <folder>, and commit; your copy stays on disk.

One warning before you do: that commit removes the file from the repository, so everyone who pulls it loses the file from their disk too, and every older commit still contains it. If it held a password, change the password.

The error

There is no error message, only a file that will not go away:

$ cat .gitignore
debug.log
bin/
$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   bin/App.dll
	modified:   debug.log

no changes added to commit (use "git add" and/or "git commit -a")
$ git check-ignore -v debug.log
$ git check-ignore -v bin/App.dll

Both check-ignore commands printed nothing and exited with code 1, as if no rule matched. Asked to ignore the index, they show that the rules are fine:

$ git check-ignore -v --no-index debug.log
.gitignore:1:debug.log	debug.log
$ git check-ignore -v --no-index bin/App.dll
.gitignore:2:bin/	bin/App.dll

Why it happens

.gitignore answers one question: which untracked files should git status leave out and git add . skip. A file that is already in the index, because it was committed before the rule was written, is tracked, and Git keeps recording its changes whatever the rules say. git check-ignore leaves tracked files out by default for the same reason; --no-index tests the pattern alone, which is how you tell "the rule is wrong" from "the file is tracked".

The fix

$ git rm --cached debug.log
rm 'debug.log'
$ git rm -r --cached bin
rm 'bin/App.dll'
$ git commit -m 'Stop tracking debug.log and bin/'
[main 8755d5f] Stop tracking debug.log and bin/
 2 files changed, 2 deletions(-)
 delete mode 100644 bin/App.dll
 delete mode 100644 debug.log
$ git check-ignore -v debug.log
.gitignore:1:debug.log	debug.log
$ git check-ignore -v bin/App.dll
.gitignore:2:bin/	bin/App.dll

--cached removes the entry from the index only: ls still found both files, git ls-files no longer listed them, and after another line was written to debug.log, git status said nothing to commit, working tree clean. A second clone, still at the first commit, then pulled the change:

$ git pull --ff-only
Updating a9d9143..8755d5f
Fast-forward
 .gitignore  | 2 ++
 bin/App.dll | 1 -
 debug.log   | 1 -
 3 files changed, 2 insertions(+), 2 deletions(-)
 create mode 100644 .gitignore
 delete mode 100644 bin/App.dll
 delete mode 100644 debug.log
$ ls debug.log bin
ls: cannot access 'debug.log': No such file or directory
ls: cannot access 'bin': No such file or directory

For build output that every machine regenerates, that is what you want. For a local settings file, tell the team first so they can copy theirs aside. And git show HEAD~2:debug.log still printed the old content: history keeps the file.

When check-ignore -v prints nothing for an untracked file, the pattern is wrong. A leading slash anchors a rule to the folder of the .gitignore:

$ cat .gitignore
debug.log
bin/
/app.log
$ git check-ignore -v src/app.log

With the third line changed to app.log, the rule matched:

$ git check-ignore -v src/app.log
.gitignore:3:app.log	src/app.log

/app.log matches only app.log at the top; app.log matches it in any folder. A trailing slash narrows a rule the other way: cache/ is for folders, and in the test it did not match a plain file called cache.

How it was reproduced

Git for Windows 2.45.2 (git version 2.45.2.windows.1) in Git Bash 5.2.26. A repository with debug.log, bin/App.dll and one source file was committed and pushed to a local bare repository before any .gitignore existed; the rules were added in a second commit and both files were changed. A second clone, reset to the first commit, pulled the fix to show what a teammate gets. The personal global config was replaced by an empty file (GIT_CONFIG_GLOBAL).

Frequently asked

Why is .gitignore not ignoring my file?
Usually because the file was committed before the rule was added, and ignore rules only apply to untracked files. Run git check-ignore -v on the file: if it prints nothing but git check-ignore -v --no-index prints the rule, the file is tracked and git rm --cached is the fix.
Does git rm --cached delete the file?
Not from your disk. It removes the file from the index, so the next commit deletes it from the repository while your copy stays. Anyone who pulls that commit loses the file from their disk, and older commits still contain it.
How do I stop tracking a folder but keep it locally?
Add the folder to .gitignore with a trailing slash, for example bin/, then run git rm -r --cached bin and commit. The folder stays on your disk and git status stops listing it.

More decoded errors in the Fixes category. For what belongs in a .gitignore in the first place, see reading history and undoing mistakes, which covers it alongside the first rescue moves.