En Linux puedes probar el programa directamente con: python3 -m repopath_sanitizer
A PyQt6 desktop app (Linux-first) that scans a directory (Git repo or any folder) for file/folder paths
that would fail on Windows. It proposes safe fixes and can apply them using either git-aware renames
(git mv) or pure filesystem renames (os.rename) depending on the mode.
- Two modes: Git Repository / Any Folder (Filesystem) — toggle in the toolbar
- Git mode: scans with
git ls-files, renames tracked files withgit mv, untracked withos.rename - Filesystem mode: scans any directory with
os.walk, renames everything withos.rename— zero git dependency
- Git mode: scans with
- Detects Windows-incompatible paths in directories and Git repositories
- Reports tracked files and normal untracked files; ignored files are optional
- Git-aware renames (
git mv) to preserve history - Filesystem renames (
os.rename) for untracked files — no git needed - Auto-switches between
os.rename(untracked) andgit mv(tracked) automatically - Collision detection (case-insensitive + Unicode NFC)
- Long path and long file/folder name detection with shortening strategies
- Estimated Windows checkout path detection using a configurable base folder
- GUI + CLI modes
- Safe undo system
- Results context menu for opening paths in the file manager or copying paths
- Reusable
windows_rules.pymodule with all Windows path restrictions - Opens maximized by default with minimum size protection (960×540)
- Window geometry persistence — remembers size/position between sessions
- Thread-safe scanning — prevents crashes on double-click or window close
This project now documents and tests an important real-world case that breaks git clone or git checkout on Windows:
- Problematic path example:
Promts/Acerca de.../About Juan y Washington.txt
The problem was not the file About Juan y Washington.txt itself. The real issue was the directory name Acerca de..., because Windows does not allow file or folder names to end with a period (.) or a space.
On Linux, Git can store and check out that path without trouble. On Windows, the clone may download successfully but fail during checkout with an error similar to:
error: invalid path 'Promts/Acerca de.../About Juan y Washington.txt'
fatal: unable to checkout working tree
RepoPath Sanitizer already had the trailing-space/trailing-period rule, and this case is now explicitly covered in tests and documentation so it remains protected against regressions.
The automatic fix is to trim the invalid trailing periods from the affected segment:
- Original:
Promts/Acerca de.../About Juan y Washington.txt - Fixed:
Promts/Acerca de/About Juan y Washington.txt
RepoPath Sanitizer requires:
- Python 3.10+
- Git (used for safe
git mvoperations) - PyQt6
Install on Debian 12:
sudo apt install python3 python3-pyqt6 gitThis program was tested on Debian 12 (Bookworm).
If yo use this program in a non KDE Linux, when the GUI was launched with:
QT_QPA_PLATFORMTHEME=qt5ctUnder that backend, yo cannot search for folders o files with "Ctrl + F"
In this project, the solution is already integrated in the code. RepoPath Sanitizer detects Linux GUI startup and, before creating QApplication, it checks QT_QPA_PLATFORMTHEME. If the value is empty or qt5ct, it changes it to gtk3.
In this environment, the GTK3-backed dialog behaved better than the Qt dialog backend:
- file dialogs opened immediately
- the search box worked correctly
- bookmarks places from GTK worked correctly
The logic used by this project is simple and can be reused in other PyQt6 applications:
import os
import sys
if sys.platform.startswith("linux"):
current = os.environ.get("QT_QPA_PLATFORMTHEME", "")
if current in {"", "qt5ct"}:
os.environ["QT_QPA_PLATFORMTHEME"] = "gtk3"Important: this must run before creating QApplication.
If another PyQt6 program does not have this fix in its own code, you can launch it manually from its repository with a command such as:
QT_QPA_PLATFORMTHEME=gtk3 python3 -m repopath_sanitizerFor RepoPath Sanitizer specifically, this manual command is only a fallback or test command because the fix is already built in.
This affects GUI dialogs such as:
Browse...Save Log- report export dialogs
On Debian you can use the system PyQt6 package (APT). if your dependencies are already installed from the Debian repositories, you can test the program directly without creating a venv:
python3 -m repopath_sanitizerUsing pip and a virtual environment if you need
sudo apt update
sudo apt install python3 python3-venv python3-pyqt6 git
python3 -m venv .venv --system-site-packages
source .venv/bin/activate
pip install -U pip
pip install -e .[dev] --no-deps
repopath-sanitizerExplanation
--system-site-packages allows the virtual environment to use PyQt6 installed via APT.
--no-deps prevents pip from trying to reinstall PyQt6 from PyPI.
The second time you want to launch the program, just put:
source .venv/bin/activate
repopath-sanitizerrepopath-sanitizer --cli --repo /path/to/repo --json out.json --text out.txtIf you want the scan to estimate the real Windows clone destination more accurately, set the expected base folder:
repopath-sanitizer --cli --repo /path/to/repo --checkout-root "C:\Users\Juan\Documents\Projects"This tool performs Git renames (git mv).
Always review changes with:
git status
git diffbefore committing.
This repository also includes a shared pre-commit hook in .githooks/pre-commit.
If you want to use the same protection in all your repositories on Linux, use the global hook package in global-hooks/README.md.
It blocks commits when staged paths contain Windows-incompatible problems such as:
- forbidden characters
- reserved Windows device names
- trailing spaces or trailing periods
- file or folder names that exceed the configured segment limit
- repository-relative paths that exceed the configured path limit
- estimated Windows checkout paths that become too long after adding the clone base folder
To enable it in this repository:
git config core.hooksPath .githooks
chmod +x .githooks/pre-commitTo enable it globally for all your repositories, see:
Optional environment variables for stricter or more realistic checks:
export REPOPATH_SANITIZER_MAX_PATH=260
export REPOPATH_SANITIZER_MAX_SEGMENT=255
export REPOPATH_SANITIZER_CHECKOUT_ROOT='C:\Users\Juan\Documents\Projects'At the top of the window, a Mode dropdown lets you choose:
| Mode | Description |
|---|---|
| Git Repository | Uses git ls-files to find files. Renames tracked files with git mv, untracked files with os.rename. Shows stash warnings for tracked renames. |
| Any Folder (Filesystem) | Uses os.walk to find files. No git required at all. Renames everything with os.rename. Works on regular project folders that are not git repos. |
- Uses
git ls-filesto enumerate tracked files and normal untracked files - Validates each path against Windows filesystem rules
- Detects:
- forbidden characters
- reserved device names
- trailing spaces/periods
- total path length issues
- individual file/folder name length issues
- estimated final Windows checkout path length issues
- case-insensitive collisions
- Unicode normalization conflicts
- Proposes safe sanitized paths
- Applies fixes using the appropriate strategy:
git mvfor tracked files (preserves git history)os.renamefor untracked files (no git dependency)
The program auto-switches between these two strategies. When you click Apply Fixes, it shows a single combined preview with each file labeled [untracked] or [git mv], then applies them all in one operation.
- Uses
os.walkto enumerate all files and directories - Skips hidden directories (
.git,.svn, etc.) and hidden files - Validates each path against Windows filesystem rules
- Detects the same issues as Git mode
- Proposes safe sanitized paths
- Applies fixes with
os.rename()— no git commands, no stash
If you accidentally type a Windows-forbidden character (like : or |) in a filename on Linux and haven't done git add yet, the file is untracked. Using git mv on an untracked file would fail. Instead, the program uses os.rename() directly — no stash, no git dependency. After renaming, you can git add the corrected names.
The "uncommitted changes" warning only appears when there are tracked files that need renaming (Git mode only). If the only issues are with untracked files, the program renames them directly without asking about stash. In Filesystem mode, the stash warning never appears.
If you have a regular project folder (not a git repo) and want to check it for Windows compatibility:
- Switch the Mode dropdown to Any Folder (Filesystem)
- Click Browse... and select your folder
- Click Scan
- Review the issues and click Apply Fixes
All renames are done with os.rename() — no git commands are executed. This is safe for any directory.
For the Windows checkout failure described above, the relevant rule is trailing spaces/periods. If a path segment ends in . or space, the sanitizer flags it and proposes a trimmed replacement that Windows can store safely.
The scanner also detects repositories that may fail on Windows because the final checkout path becomes too long after combining:
- the Windows base folder
- the repository folder name
- deep nesting of folders and subfolders
- long file or folder names
This matters because a repository may look acceptable on Linux while still failing on Windows when cloned under a path such as C:\Users\Name\Documents\Projects\....
In the GUI, these length-related issues are shown separately so they are easier to understand:
Relative path too longFile/folder name too longEstimated Windows checkout path too long
The file src/repopath_sanitizer/windows_rules.py is a standalone, importable module that contains all Windows filesystem path restrictions. Any developer can use it in their own project without depending on the rest of RepoPath Sanitizer.
| Symbol | Description |
|---|---|
FORBIDDEN_CHARS |
Characters banned in Windows filenames: `< > : " / \ |
RESERVED_DEVICE_NAMES |
Device names Windows treats as special: CON, PRN, AUX, NUL, COM1–COM9, LPT1–LPT9 |
MAX_PATH_LENGTH |
Maximum total path length: 260 |
MAX_SEGMENT_LENGTH |
Maximum single segment length: 255 |
is_valid_filename(seg) |
Returns True if the segment is valid on Windows |
sanitize_segment(seg) |
Returns a Windows-safe version of the segment |
sanitize_relative_path(path) |
Sanitizes every segment in a path |
validate_relative_path(path) |
Returns a list of (code, message) issues |
contains_forbidden(seg) |
Checks for forbidden characters |
has_trailing_space_or_period(seg) |
Checks for trailing . or |
is_reserved_device_name(seg) |
Checks for reserved device names |
from repopath_sanitizer.windows_rules import (
is_valid_filename,
sanitize_segment,
validate_relative_path,
FORBIDDEN_CHARS,
)
if not is_valid_filename("my:file.txt"):
safe = sanitize_segment("my:file.txt")
print(f"Renamed to: {safe}") # → my -file.txt
issues = validate_relative_path("src/my:file.txt")
for code, msg in issues:
print(f"{code}: {msg}")The application opens maximized on all screen sizes. A minimum size of 960×540 is enforced to prevent the UI from becoming unusable on small displays.
The window's size, position, and maximized state are saved between sessions. When you reopen the app, it restores the exact same layout.
Scanning runs in a background thread. If you click Scan twice quickly, the previous scan is cancelled cleanly before the new one starts. Closing the window while a scan is running is also safe — threads are terminated before the application exits.
For development and testing:
sudo apt install python3-pytestsrc/repopath_sanitizer/
ui_main.py # GUI
engine.py # Scan logic
pathrules.py # Windows compatibility rules
windows_rules.py # Reusable Windows path restrictions (importable standalone)
gitutils.py # Git operations
worker.py # Background tasks
report.py # JSON/Text reports
state.py # Undo system
cli.py # CLI mode
To build the .deb package you need:
sudo apt install debhelper dh-python python3-all pybuild-plugin-pyproject \
python3-pyqt6 python3-pytest gitThen build with:
sudo apt build-dep .
dpkg-buildpackage -us -ucThe application is prepared for internationalization.
Install tools:
sudo apt install qtcreator qttools5-dev-tools qt6-tools-dev-toolsWorkflow to add a language:
pylupdate6 src -ts translations/repopath_sanitizer_es.ts
linguist translations/repopath_sanitizer_es.ts
lrelease translations/repopath_sanitizer_es.tsTranslation files (.qm) are installed to:
/usr/share/repopath-sanitizer/translations/

