Utilities for managing trackignore configuration and publish workflows.
Project description
🔐 trackignore
Version control for your private files in public repositories
Work freely with private docs • Push safely to public repos • Never leak sensitive content
🎯 The Problem
You're building an open source project on GitHub, but you have files you want to keep private:
my-awesome-project/
├── src/ ✅ Public code
├── docs/ ✅ Public docs
└── __PRIVATE__/
├── notes.md ⚠️ Private notes, planning documents,
├── AGENTS.md ⚠️ maybe just something you're
└── embarrassing-ideas/ ⚠️ a little embarassed about!
The Dilemma:
- 🚫
.gitignorethem → You lose version control - 🚫 Commit them → They appear in your public GitHub history
- ✅ trackignore → Version control locally, never publish to GitHub, all in the same repo
🎬 How It Works
✨ Key Features
🛡️ Safety First
|
🧹 Clean History
|
🔄 Dual Remotes
|
⚡ Simple Workflow
|
🚀 Quick Start
1. Install (pipx recommended)
pipx install trackignore
pipx installs trackignore in an isolated environment together with the required pathspec and git-filter-repo packages—no extra setup per project.
# Upgrade or remove later
pipx upgrade trackignore
pipx uninstall trackignore
2. Initialize your repository
cd my-awesome-project
trackignore init --public-remote origin --private-remote origin-private
This command:
- creates a
.trackignorefile seeded with__PRIVATE__/ - installs a pre-push hook that prompts (or auto-runs)
trackignore push - writes
.trackignore.d/config.shwith your preferred remotes
3. Add or confirm remotes
git remote add origin git@github.com:username/public-repo.git # sanitized history
git remote add origin-private git@github.com:username/private-repo.git # optional private mirror
4. Day-to-day workflow
# Work normally with public and private files
vim src/main.py
vim __PRIVATE__/planning.md
git add .
git commit -m "Add feature X"
# Publish a cleaned history to the public remote
trackignore push --remote origin --branches main
# (Optional) sync the private-only subtree to your private remote
trackignore sync --remote origin-private --branch main --path __PRIVATE__
📋 Commands Reference
| Command | Description | What it does |
|---|---|---|
trackignore init |
Bootstrap | Seeds .trackignore, installs hook, and writes config |
trackignore push |
Publish | Clones, runs git-filter-repo, and force-pushes sanitized branches |
trackignore sync |
Sync private | Uses git subtree push for a protected directory (e.g., __PRIVATE__/) |
trackignore cleanup --dry-run |
Audit history | Detects committed secrets and prints the cleanup plan before rewriting |
trackignore config-check --json |
Inspect | Lists normalized patterns plus any loader warnings |
🔧 Configuration
Custom Private Directory
Edit scripts/publish.sh:
PRIVATE_DIR="my-private-stuff" # default: __PRIVATE__
Custom Remote Pattern
Edit .githooks/pre-push:
ALLOW_REMOTES_REGEX="^origin-private$|^backup-" # Allow multiple patterns
Publish Specific Branches
# Publish single branch
PUBLIC_BRANCHES="release/v2" make publish
# Publish multiple branches
PUBLIC_BRANCHES="main develop release/v1" make publish
🎓 How It Works (Deep Dive)
1. Pre-Push Hook 🛡️
Installed in .git/hooks/pre-push, this hook:
- Intercepts all
git pushcommands - Checks if you're pushing to a public remote
- Blocks the push if
__PRIVATE__/exists in the branch - Only allows pushes to remotes matching
ALLOW_REMOTES_REGEX
# Example: trying to push to public remote
git push origin main
# ❌ Blocked! Use 'make publish-main' instead
2. Publish Script 🧹
The scripts/publish.sh script does the heavy lifting:
- Creates temporary clone →
/tmp/repo-publish-<random>/ - Runs git-filter-repo → Removes all
__PRIVATE__/from history - Checks out branch → e.g.,
main - Force pushes to public →
origin - Cleans up → Removes temporary directory
# What happens under the hood
git clone . /tmp/repo-publish-abc123
cd /tmp/repo-publish-abc123
git-filter-repo --path __PRIVATE__ --invert-paths --force
git push --force origin main
3. Subtree Sync (Optional) 🌳
For syncing __PRIVATE__/ to a separate private repo:
# First time setup
git subtree split --prefix=__PRIVATE__ -b private-branch
git push origin-private private-branch:main
# Subsequent syncs
make sync-private
⚠️ Important Notes
- Backup first: Test this workflow on a non-critical project first
- Force push warning: The publish script uses
--forceto rewrite history - Not a submodule:
__PRIVATE__/must be a regular directory, not a Git submodule - git-filter-repo: Must be installed (officially recommended tool by git docs)
- One-way sync: Changes in public remote won't sync back to private files
🔒 Security Considerations
What This Protects Against
✅ Accidental git push of private files
✅ Private files appearing in public commit history
✅ Leaking sensitive data to public repositories
What This Does NOT Protect Against
❌ Files already pushed before setup (see cleanup below)
❌ Local repository compromise
❌ Intentional bypass of the hook (e.g., git push --no-verify)
Cleaning Existing History
If you've already pushed __PRIVATE__/ to your public repo:
# ⚠️ WARNING: This rewrites history and breaks clones!
# 1. Backup your repo
git clone your-repo your-repo-backup
# 2. Remove private files from all history
git filter-repo --path __PRIVATE__ --invert-paths --force
# 3. Force push to public remote (coordinate with team!)
git push origin --force --all
git push origin --force --tags
🤔 FAQ
Why not just use .gitignore?
.gitignore prevents files from being staged, but you lose version control. This solution lets you version control private files locally while keeping them out of public repos, and avoids alternative solutions (submodules, symlinks, etc.) which may confuse you, your IDE, or your coding assistant - all complexity is abstracted away into a few easily configurable scripts.
Can I use multiple private directories?
Yes! Edit PRIVATE_DIR in the scripts to support patterns, or run filter-repo multiple times with different paths.
What if I forget and push directly?
You can't. The pre-push hook will block it. (If you bypass with --no-verify, you'll need to force-push a cleaned version to fix it.)
Does this work with GitHub Actions?
Yes! You can automate the publish script in CI/CD. Just ensure git-filter-repo is installed in the runner.
Does this work with git worktrees?
Yes! Create separate worktrees for main, feature branches, or private development:
git worktree add ../proj-main main
git worktree add ../proj-dev dev-private
Only one worktree should be used to publish:
cd ../proj-main
make publish-main
Performance with large repos?
git-filter-repo is fast, but creating temporary clones takes time. For very large repos, consider using shallow clones or selective branch publishing.
🛠️ Troubleshooting
Hook not working?
# Check if hook is executable
ls -la .git/hooks/pre-push
# Make it executable
chmod +x .git/hooks/pre-push
# Verify hook is installed
cat .git/hooks/pre-push
git-filter-repo not found?
# Verify installation
which git-filter-repo
# Install via pip
pip install git-filter-repo
# Or download directly
wget https://raw.githubusercontent.com/newren/git-filter-repo/main/git-filter-repo
chmod +x git-filter-repo
sudo mv git-filter-repo /usr/local/bin/
Publish fails with "ref already exists"?
# The script uses --force, but if you need to manually fix:
cd /tmp/repo-publish-*/
git push origin main --force
📚 Additional Resources
🤝 Contributing
Contributions welcome! Here's how:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-idea - Make your changes
- Test thoroughly
- Submit a pull request
Please open an issue first to discuss major changes.
📜 License
MIT License - see LICENSE file for details.
🙏 Acknowledgments
- Thanks to newren for the amazing
git-filter-repotool - Inspired by various discussions about managing private files in public repos
- Built out of necessity and a healthy dose of paranoia
⭐ Star this repo if you find it useful!
Made with ❤️ and a healthy dose of privacy
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trackignore-0.1.2.tar.gz.
File metadata
- Download URL: trackignore-0.1.2.tar.gz
- Upload date:
- Size: 20.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
791f1b195669123bc0e1a4b5dfb24d7713d3215bfff90068238f18743c9db898
|
|
| MD5 |
858f9a122d4464c0880ee68c811f326b
|
|
| BLAKE2b-256 |
09eac1229526814b9867226425bbd1741241d29d943654f0f8f1361daf98a737
|
Provenance
The following attestation bundles were made for trackignore-0.1.2.tar.gz:
Publisher:
publish.yml on hesreallyhim/trackignore
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trackignore-0.1.2.tar.gz -
Subject digest:
791f1b195669123bc0e1a4b5dfb24d7713d3215bfff90068238f18743c9db898 - Sigstore transparency entry: 597152498
- Sigstore integration time:
-
Permalink:
hesreallyhim/trackignore@3f4d5a20613cb104e50333e25583f30d62dd4ee7 -
Branch / Tag:
refs/tags/v0.1.7 - Owner: https://github.com/hesreallyhim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@3f4d5a20613cb104e50333e25583f30d62dd4ee7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file trackignore-0.1.2-py3-none-any.whl.
File metadata
- Download URL: trackignore-0.1.2-py3-none-any.whl
- Upload date:
- Size: 7.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bee994f9012e4cdfe9caba36150efdc6c4a8c73ca634a328100d3cfaad0fe5cc
|
|
| MD5 |
5812f4104099b6e6f6da5ca600ff2674
|
|
| BLAKE2b-256 |
34b4bb165ad856e720d78a7c57a0c916b25cbade879f170fd24aa32aadeef677
|
Provenance
The following attestation bundles were made for trackignore-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on hesreallyhim/trackignore
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trackignore-0.1.2-py3-none-any.whl -
Subject digest:
bee994f9012e4cdfe9caba36150efdc6c4a8c73ca634a328100d3cfaad0fe5cc - Sigstore transparency entry: 597152533
- Sigstore integration time:
-
Permalink:
hesreallyhim/trackignore@3f4d5a20613cb104e50333e25583f30d62dd4ee7 -
Branch / Tag:
refs/tags/v0.1.7 - Owner: https://github.com/hesreallyhim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@3f4d5a20613cb104e50333e25583f30d62dd4ee7 -
Trigger Event:
release
-
Statement type: