Why Ignore Rules Need Care
A pharmacometric project produces files that are useful locally but do not belong in its shared source history: temporary files, run-specific outputs, local settings, and credentials. A good ignore policy reduces accidental additions without hiding the scripts, input specifications, or configuration templates that collaborators need. The goal is not to ignore as much as possible; it is to make the boundary between maintained project material and local or generated material explicit.
Ignore rules are not a security control and do not remove files from a repository once they are tracked. They help Git decide which untracked paths to omit from ordinary status and addition workflows. A credential must never be treated as safe merely because a pattern currently matches it.
Where Rules Apply and How Patterns Match
The repository-level .gitignore file is usually the right place for exclusions that apply to everyone working in the project. Each line is a pattern; blank lines are ignored, and a line beginning with # is a comment. A leading ! makes a pattern an exception to an earlier matching pattern. A backslash can be used to escape special characters when they are meant literally.
Pattern scope depends on its slashes. A pattern without a slash, such as *.tmp, can match files or directories at any level beneath the .gitignore file. A slash in the middle of a pattern makes its location relative to the directory containing that .gitignore. A leading slash anchors the pattern to that directory. A trailing slash matches directories rather than files. For example, /runs/ matches the repository-root runs directory, while runs/ can match a directory with that name at any level.
Git considers the applicable ignore sources in a defined precedence order: patterns supplied on the command line take precedence over per-directory .gitignore files; lower-level .gitignore files can override parent-level ones; and repository-local exclusions and user-wide exclusions have lower precedence than applicable .gitignore patterns. Within a set of rules at the same level, the last matching pattern determines whether a path is ignored. Specific, documented rules are easier to review than broad patterns whose effects are hard to predict.
An important limitation applies to exceptions: Git does not re-include a file if one of its parent directories remains excluded. If a directory is ignored as a whole, an exception for a file inside it may not work. The parent directory must remain visible to Git for Git to evaluate the exception below it.
Worked Example: Excluding Run Outputs Without Hiding Scripts
Suppose a repository contains scripts/fit.R, config/model.example.yaml, and outputs beneath runs/. The run directory contains temporary estimates and reports recreated by model execution. The script and example configuration are maintained project files; the run products are generated artifacts.
A focused repository-root .gitignore could contain:
# Generated run products
/runs/
/cache/
*.tmp
*.Rout
The anchored /runs/ and /cache/ patterns exclude those repository-root directories. The extension patterns exclude matching temporary and R output files at any level. None of these patterns matches scripts/fit.R or config/model.example.yaml, so those files remain eligible to be tracked. Ignore rules do not add files: if the script or template is new, it still needs to be deliberately added to Git.
To inspect the policy, run git check-ignore -v -- runs/run-017/estimates.csv. Git reports the matching rule and its source, showing whether the path is ignored because it is under the repository-root runs directory. Run git status --short --ignored to see ordinary changes and a summary of ignored paths; ignored entries are marked with !!. Then check the maintained files with git check-ignore -v -- scripts/fit.R config/model.example.yaml. If neither is ignored, the rule set has not accidentally excluded them. A newly created, unignored file still needs to be added explicitly when it is intended for version control.
Protect Local Settings While Keeping Templates
Configuration often includes both shareable defaults and machine-specific values. A template such as config/model.example.yaml can document parameter names and safe example values. A local configuration file may contain paths, usernames, or other information that should not be shared. Keep the filenames and roles distinct so that an ignore rule can target the local file without excluding the template.
Credentials need even more care. API tokens, passwords, private keys, and credential-bearing environment files should not be committed. Avoid broad rules that conceal entire useful file types or directories: for example, ignoring every YAML file could hide a required configuration template. Prefer known local-only paths and credential conventions, and check that templates remain visible.
Worked Example: Ignoring Local Configuration and Credential Files
Imagine the repository has config/model.example.yaml as a safe template and config/model.local.yaml for machine-specific settings. A user may also create a root-level .env file or a private key with a .pem extension. The following rules are one possible starting point in the root .gitignore:
# Machine-specific settings and credentials
/config/model.local.yaml
.env
*.pem
The anchored configuration rule targets only the named local file at the repository root’s config path. The .env pattern matches files named .env at any level, and *.pem matches PEM-suffixed paths at any level. The example YAML template is not matched by these rules. The broad PEM rule is appropriate only if all PEM files in this project are local secrets; if the project intentionally tracks public certificates or other PEM files, replace it with a more specific path or filename pattern.
Test the local configuration and key with git check-ignore -v -- config/model.local.yaml .env analyst-key.pem. Check the template separately with git check-ignore -v -- config/model.example.yaml; it should not be reported as ignored. If you need to ignore .env.local files while preserving a safe .env.example, use a more explicit pair of rules:
.env.*
!.env.example
The exception works because the root itself is not excluded and the matching files are directly beneath it. If the template is nested inside an excluded directory, the directory-level rule must also be adjusted so Git can reach the template. After checking the template is not ignored, deliberately add it if it is new. An unignored credential is still dangerous; the correct response is to keep its contents out of the index, not to rely on a pattern as the sole protection.
Inspecting Rules and Correcting Mistakes
A reliable ignore policy is tested against both paths that should be excluded and paths that must remain available. The most useful diagnostic is git check-ignore -v -- path, which identifies the matching pattern and the file that supplied it. If a path is unexpectedly ignored, that output points to the rule to revise. If a tracked path needs to be diagnosed, add --no-index to ask Git to consider ignore rules even though the path is tracked.
Use git status --short --ignored to review ignored files and directories alongside ordinary changes. This is particularly useful after a model run: confirm that generated outputs are ignored, but also confirm that source scripts and required templates are not. A pattern can be syntactically valid yet operationally wrong because it matches more than intended.
Worked Example: A Generated File Is Already Tracked
Suppose reports/generated/fit-summary.csv was committed before the project added /reports/generated/ to .gitignore. The new rule will prevent other untracked files under that directory from being added accidentally, but it will not stop Git from tracking this summary. Confirm its tracked status with git ls-files -- reports/generated/fit-summary.csv. The path will appear in the output if it is in the index.
If the summary is generated and should no longer be tracked, first confirm that it is safe to remove from the shared repository. Then run git rm --cached -- reports/generated/fit-summary.csv and commit the resulting index change through the project’s normal review process. The --cached option removes the path from the index while leaving the working copy in place. The ignore rule can then prevent that local copy from appearing as an untracked addition.
If the tracked file contains a password, token, or private key, removing it from the current index is not enough. The secret may remain in earlier commits and may already have been copied by others. Treat it as exposed: revoke or rotate the credential promptly and follow the organization’s process for handling sensitive material in repository history. An ignore rule prevents some future mistakes; it cannot undo disclosure.
Choosing the Right Exclusion Location
Not every exclusion belongs in the same place. The choice depends on whether the rule is a shared project policy or a local convenience.
| Location | Appropriate use | Important limitation |
|---|---|---|
| Repository .gitignore | Generated outputs and local-only patterns relevant to everyone working in the project | It is shared; avoid rules that hide required files for collaborators |
| Repository .git/info/exclude | Unusual files specific to one local checkout that should not affect collaborators | It is not shared, so it cannot enforce a project-wide exclusion policy |
| User-wide ignore file | Editor temporary files or operating-system files that are personal, general conveniences | It can make a file appear absent only on that user’s machine and is not a substitute for repository rules |
Use the repository .gitignore for predictable, project-specific generated files and sensitive local-file conventions. Keep personal editor noise in a local or user-wide exclusion source rather than imposing it on everyone. Whichever source is used, identify it with git check-ignore -v when the result is surprising.
Common Failure Modes and a Practical Review
- Ignoring too broadly. A rule such as *.yaml can hide configuration templates and other maintained inputs. Narrow the rule to the local filename or path.
- Assuming an ignored file is secure. Ignore rules do not encrypt or protect a file. Keep secrets out of commits, control access to local files, and rotate any credential that was exposed.
- Expecting a rule to untrack a file. Check with git ls-files; if a generated file is already tracked, address its index status separately.
- Adding an exception beneath an excluded directory. Git cannot re-include a file if its parent remains excluded. Adjust the directory rule so Git can evaluate the exception.
- Checking only files that should be ignored. Also test scripts, source data specifications, and configuration templates that must remain visible to Git.
Before relying on a new policy, test representative paths from each category: one run output, one temporary file, one local setting, one credential-like file, one maintained script, and one safe template. Confirm each result with git check-ignore -v and review git status --short --ignored. Ignore policy is most useful when its intended boundary can be explained and verified.
Check Your Understanding
Answer these questions using the rule behavior and repository checks described above. Solutions follow each question.
- A root .gitignore contains /runs/. Should runs/fit-2/output.csv be ignored, and should analysis/runs/output.csv match that same rule?
- The file config/model.example.yaml is a required template, but config/model.local.yaml contains local settings. What is a safer rule than ignoring every YAML file?
- A generated report is listed by git ls-files even though its directory now matches .gitignore. Why does the rule not stop it being tracked?
- A credential file was committed and then removed from the latest version. Name two actions needed beyond adding an ignore rule.
Solutions. (1) The first path is beneath the repository-root runs directory and is ignored. The second is under analysis/runs/, so it does not match the anchored root rule. (2) Ignore the specific local path, for example /config/model.local.yaml; this does not match the example template. (3) Ignore rules apply to untracked paths; a tracked path remains in the index until it is separately removed from tracking. (4) Revoke or rotate the exposed credential and follow the organization’s process for addressing sensitive material in repository history. Removing the latest copy and adding an ignore rule do not erase prior exposure.