Skip to content
HexCinePublic

About

Check Git filename portability before checkout, with reviewable CI reports.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Treeport

Start here: visual guide EN/RU · Русский: первый запуск

Download start.html and open it in your browser for installation, a failing demo, a passing comparison and next steps. Examples are synthetic and run locally.

CI

Check whether your Git filenames travel well — before checkout.

A filename accepted on Linux can prevent a Windows contributor from checking out your project. Treeport reads a commit's path list directly from Git, reports naming hazards, and produces text, JSON or a self-contained HTML report. It also checks the entire staged index for use in pre-commit workflows.

This is an initial release with a deliberately small scope. It runs locally, has no runtime Python dependencies, makes no network requests, and needs no AI API. Reports contain repository path names; review them before sharing.

Download a release

Release v0.1.2 includes a wheel, source archives, checksums and a verification record. With Python 3.11+, install the downloaded wheel using python -m pip install treeport-0.1.2-py3-none-any.whl. Runtime dependencies listed below are resolved by pip when needed. For source development, clone this repository and follow the existing install steps.

Install

Requires Python 3.11+ and Git on PATH. Git is not needed for JSON path-list input. Windows, Linux and macOS are CI targets. See docs/VALIDATION.md for actually run checks.

From an extracted source release, in the directory containing pyproject.toml:

python -m pip install .
treeport --version

From the supplied wheel (offline, without dependency downloads):

python -m pip install --no-index --no-deps treeport-0.1.2-py3-none-any.whl

The name is provisional and this package has not been published to PyPI. python -m treeport can replace treeport in every command below.

Try it in one minute

From the source release directory after installation:

treeport check --paths examples/problem-paths.json
treeport check --paths examples/problem-paths.json --format html --output report.html
treeport check --paths examples/clean-paths.json

The first two commands intentionally exit 1 because the sample contains errors. The last exits 0. Open report.html in a browser. The sample names are synthetic; they do not represent users or project adoption.

Check a repository

treeport check /path/to/repository
treeport check /path/to/repository --ref main
treeport check /path/to/repository --index
treeport check /path/to/repository --format json --output report.json

The default is the HEAD tree, not the files currently on disk. Use --ref for a branch, tag, commit or tree object and --index for the full staged snapshot. Untracked files and unstaged changes are not included. An unresolved index fails with exit 2. An unborn repository can be scanned with --index.

--ref also works in bare repositories and after a clone with --no-checkout:

git clone --bare https://github.com/OWNER/REPOSITORY.git repository.git
treeport check repository.git --ref HEAD

Replace the example URL with your repository. Cloning is a separate Git operation; Treeport itself never fetches, checks out, renames files or invokes project code. It reads path metadata, not blob contents. Submodule paths are checked, but their contents are not traversed. Symlink names are checked, but targets are not followed.

CI policy and exit status

Exit Meaning
0 No new findings at or above the selected failure threshold
1 At least one new finding reaches that threshold
2 Input, Git, arguments, baseline or output error; the scan is not trustworthy

Warnings fail by default. To fail only on errors, use --fail-on error. This does not remove warnings from reports. Git commands time out after 30 seconds.

treeport check --max-path 200 --exclude "vendor/*" --exclude "fixtures/intentional/*"

--max-path is a repository-relative UTF-16 code-unit budget, default 240; 0 disables it. It is not the Win32 absolute-path limit: your clone directory and toolchain also matter. Excludes are case-sensitive Python fnmatchcase patterns applied to complete leaf paths, and * crosses /. They are not .gitignore patterns. Quote them so your shell does not expand them. Exclusion can hide real problems; use it only for reviewed, intentionally nonportable content.

Adopt gradually with a baseline

Review the initial findings, then explicitly record them:

treeport check --write-baseline treeport-baseline.json
treeport check --baseline treeport-baseline.json

The first command writes the baseline and keeps the normal failure status. Commit the reviewed JSON file (this source template ignores its default name; use git add -f treeport-baseline.json if needed). Subsequent reports show all findings, including acknowledged ones. Only unchanged finding fingerprints are acknowledged. Adding a member to a collision group creates a new finding. Rule identifiers and affected paths define fingerprints. A changed length policy or exclude list rejects the baseline; stale entries are counted for cleanup. Baselines are not proof that a repository is portable, and should be reviewed as code.

GitHub Actions

Install a reviewed release wheel or pin the source repository to a commit. The following job assumes Treeport's source is vendored at tools/treeport:

name: Filename portability
on: [push, pull_request]
permissions:
  contents: read
jobs:
  paths:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: python -m pip install ./tools/treeport
      - run: treeport check --ref HEAD

Run on Linux so a Windows-invalid name cannot stop checkout before the checker runs. The included project CI tests Python 3.11/3.14 on Linux, Windows and macOS, plus builds and installs the wheel. These workflows are prepared; remote CI has not yet run.

pre-commit

The source includes .pre-commit-hooks.yaml. Before publishing it, use this local configuration with Treeport already installed in the environment running pre-commit:

repos:
  - repo: local
    hooks:
      - id: treeport
        name: Check staged filename portability
        entry: treeport check --index
        language: system
        pass_filenames: false
        always_run: true

Checks and limits

Rule Check Default severity
TP001 Win32-forbidden characters, including controls and ADS-style colons Error
TP002 Reserved device stems, including extensions and COM/LPT superscripts Error
TP003 Trailing ASCII dots/spaces in components Error
TP004 Case collisions, including directory and file/directory prefixes Error for ASCII, warning otherwise
TP005 NFC + Unicode case-folding collisions Warning
TP006 Component over 255 UTF-8 bytes or UTF-16 code units Warning
TP007 Relative path over the configured UTF-16 budget Warning
TP008 Filename not decodable as UTF-8 Error
TP009 Malformed relative path or exact file/directory overlap in input Error

Unicode comparisons are conservative Python comparisons, not an emulation of NTFS, APFS or HFS+ collation. A clean report does not guarantee checkout, archive extraction or build success. NTFS short-name aliases, .git alias protection, permissions, executable bits, line endings, symlink behavior, long-path settings, invalid branch names and file content portability are outside this release. The scan stores the path list and directory prefixes in memory; million-path repositories are not a validated target yet. HTML is static with no scripts or remote assets; names are escaped, including control characters.

Existing pre-commit-hooks already provides check-case-conflict and check-illegal-windows-names. If these satisfy your workflow, use them. Treeport focuses on tree inspection without checkout, combined reviewable reports and gradual adoption. See docs/DECISION.md.

Development

python -m pip install -e .
python -m unittest discover -s tests -v
python -m pip install build twine
python -m build
python -m twine check dist/*

On Windows PowerShell, if the last command does not expand the wildcard, use:

python -m twine check (Get-ChildItem dist -File).FullName

Tests use only the standard library plus the installed package and real Git. They generate temporary Git objects containing otherwise uncreatable Windows names. They do not need network access. Dependencies for packaging are build-only; the distributed runtime contains only Treeport's own Python files and MIT license.

See CONTRIBUTING.md, roadmap, release instructions and security. Licensed under MIT.

JSON inputs are limited to 32 MiB and 128 nesting levels. Duplicate keys and non-finite constants are rejected. Git metadata reads disable fsmonitor hooks for that invocation; repository configuration is preserved.

About

Check Git filename portability before checkout, with reviewable CI reports.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages