---
title: "写了 gitignore 还是不对：查出具体命中的规则与索引状态"
date: 2026-11-13
slug: git-check-ignore-debug
canonical: https://kernelranch.com/blog/2026/11/git-check-ignore-debug
markdown_url: https://kernelranch.com/blog/2026/11/git-check-ignore-debug.md
tags: ["git", "gitignore", "tooling"]
---生成文件写进了 .gitignore，git status 依然显示修改。另一个目录里的 README 写了取反规则，却还是找不到。先分别检查路径是否已进索引，以及 Git 能否遍历父目录。

## 1. 在临时仓库复现两种表现

保存为 ignore_lab.py，执行 python ignore_lab.py。

```python
from pathlib import Path
import subprocess
from tempfile import TemporaryDirectory

with TemporaryDirectory() as tmp:
    root = Path(tmp)

    def git(*args, check=True):
        return subprocess.run(["git", *args], cwd=root, text=True,
                              capture_output=True, check=check)

    git("init", "-q")
    log = root / "tracked.log"
    log.write_text("old", encoding="utf-8")
    git("add", "tracked.log")
    log.write_text("new", encoding="utf-8")
    rules = root / ".gitignore"
    rules.write_text("*.log\nbuild/\n!build/README.md\n", encoding="utf-8")
    (root / "build").mkdir()
    (root / "build" / "README.md").touch()
    assert git("ls-files", "--", "tracked.log").stdout.strip() == "tracked.log"
    assert git("check-ignore", "--", "tracked.log", check=False).returncode == 1
    assert "*.log" in git("check-ignore", "-v", "--no-index", "--", "tracked.log").stdout
    print("tracked.log: already indexed; pattern matches only with --no-index")

    result = git("check-ignore", "-v", "--", "build/README.md").stdout
    assert "build/" in result and "!build/" not in result
    print("ignored parent: build/README.md excluded")
    rules.write_text("*.log\nbuild/*\n!build/README.md\n", encoding="utf-8")
    result = git("ls-files", "--others", "--exclude-standard").stdout.splitlines()
    assert "build/README.md" in result
    print("ignored children: build/README.md included")
```

本机实测输出如下。

```text
tracked.log: already indexed; pattern matches only with --no-index
ignored parent: build/README.md excluded
ignored children: build/README.md included
```

## 2. 按索引状态选命令

| 现象 | 直接验证 |
|---|---|
| 规则看起来命中，文件依旧有修改 | git ls-files -- 路径，先确认索引是否包含它 |
| 路径被悄悄忽略 | git check-ignore -v -- 路径，查看规则来源和行号 |
| 想知道已跟踪路径假如没进索引会怎样 | git check-ignore -v --no-index -- 路径 |

Git 不会为了找例外规则而深入已排除的目录。只想留下某个直接子文件时，用 build/* 排除内容，再用取反规则包含它。若路径更深，各级父目录都必须可遍历。

决定停止跟踪某个文件时，可在确认后使用 git rm --cached -- 路径，并提交索引变化与忽略规则。历史中已有的文件内容仍可通过旧提交访问。

## 小结

先查索引，再查具体模式。对取反规则，从父目录逐级验证路径是否仍可遍历。

## 数据来源与检索时间

检索时间 2026-11-13。

| 来源 | URL | 对应内容 |
|---|---|---|
| Git gitignore | https://git-scm.com/docs/gitignore | 已跟踪文件、取反与排除父目录 |
| Git check-ignore | https://git-scm.com/docs/git-check-ignore | 诊断选项与 --no-index |

## 核验说明

- 使用本机 Git 2.54.0.windows.1 在临时仓库复现。
