From 628f2f89b0dc8047ef11714b24fdcb87496ea346 Mon Sep 17 00:00:00 2001 From: coldsofttech <161084795+coldsofttech@users.noreply.github.com> Date: Sun, 25 Oct 2026 10:12:25 +0000 Subject: [PATCH] Commit LFS rules by default with --use-lfs Keeping the rules only in .git/info/attributes left LFS pointer files in the working tree after any checkout, pull or clone. --use-lfs now commits per-extension rules to .gitattributes; --no-lfs-commit-rules restores the old local-only behaviour. Also: release via PyPI trusted publishing (OIDC), add CODEOWNERS, add keywords/classifiers/urls to pyproject.toml, bump to 0.1.2. --- .github/CODEOWNERS | 2 ++ .github/workflows/release.yml | 8 ++++---- CHANGELOG.md | 7 +++++++ README.md | 9 +++++---- docs/architecture.md | 2 +- pyproject.toml | 21 ++++++++++++++++++++- src/commitrocket/__init__.py | 2 +- src/commitrocket/cli.py | 16 +++++++++++----- src/commitrocket/options.py | 2 +- src/commitrocket/runner.py | 3 ++- tests/test_cli.py | 1 - uv.lock | 2 +- 12 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..0b5ec8b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Default owner for everything in the repository +* @coldsofttech diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 44f9fb3..bf80843 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,8 @@ name: Release # Publishes to PyPI when a version tag such as v0.2.0 is pushed. -# Needs a PYPI_API_TOKEN secret (Settings > Secrets and variables > Actions). +# Uses PyPI trusted publishing (OIDC), so no API token is stored. PyPI needs a +# trusted publisher for this repository: workflow release.yml, environment pypi. on: push: tags: ["v*.*.*"] @@ -49,6 +50,7 @@ jobs: environment: pypi permissions: contents: write + id-token: write steps: - uses: actions/checkout@v7 @@ -58,9 +60,7 @@ jobs: run: uv build - name: Publish to PyPI - env: - UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - run: uv publish + run: uv publish --trusted-publishing always - name: GitHub release uses: softprops/action-gh-release@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 038327c..506a746 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## [Unreleased] +## [0.1.2] - 2026-10-25 + +### Changed +- `--use-lfs` now commits LFS rules by default so checkouts and clones get the real files. Use `--no-lfs-commit-rules` for the old per-run behaviour. +- Releases are published to PyPI with trusted publishing instead of an API token. +- The PyPI page now shows keywords, classifiers and project links. + ## [0.1.1] - 2026-10-24 ### Added diff --git a/README.md b/README.md index 94c8250..d941376 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ nothing staged, then asks for confirmation. | `--log-file` | Write the log to this file instead of the default folder | | `--lfs-threshold-mib` | With `--use-lfs`, files larger than this use LFS (default 100, `0` = every file) | | `--use-lfs` | Store files over 100 MiB with Git LFS for this run (see below) | -| `--lfs-commit-rules` | With `--use-lfs`, also commit LFS rules so clones get the real files | +| `--no-lfs-commit-rules` | With `--use-lfs`, keep LFS rules local to the run (checkouts and clones then show pointer files, not real files) | | `--report` | Write a JSON summary of the run to this file | | `--notify` | Show a desktop notification when the run ends | | `--notify-webhook` | Send a JSON summary to this web address when the run ends | @@ -285,7 +285,7 @@ commitrocket --repo . --message "Add assets" # later: pushes the saved commi **Videos in LFS that clones can download too** ``` -commitrocket --repo . --message "Videos" --use-lfs --lfs-commit-rules +commitrocket --repo . --message "Videos" --use-lfs ``` **See what would happen first** @@ -432,12 +432,13 @@ used up quickly. Git's own settings files (`.gitattributes`, `.gitignore`, `.lfs always stay as normal files. The threshold cannot be above 100, since larger files are rejected by hosts. -To let clones receive the real files, add `--lfs-commit-rules`. CommitRocket then commits +So that checkouts and clones receive the real files, CommitRocket commits the LFS rules by default. It commits one rule per file type (for example `*.mp4`) to `.gitattributes` as ` (LFS rules)`, pushes it first, and your files follow as LFS pointers. Because rules are per type, every file of that type is stored in LFS from then on, including small ones and future ones. Files without an extension get an exact-path rule. `.gitattributes` must have no -uncommitted changes beforehand. +uncommitted changes beforehand. Pass `--no-lfs-commit-rules` to skip this; videos then turn into +text pointer files after a pull, reset or clone. If a run fails after committing LFS files but before pushing them, the LFS hooks are left installed so the files can still be uploaded. Run CommitRocket again to finish; avoid a diff --git a/docs/architecture.md b/docs/architecture.md index dbab27e..e762beb 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -79,7 +79,7 @@ remain, `130` interrupted. `refs/remotes//..HEAD`, or `HEAD --not --remotes=` when that branch was never pushed. - **`--no-push`**: skips push and verification; rejected together with `--use-lfs`. -- **`--lfs-commit-rules`**: `LfsSession.write_committed_rules` appends one rule per +- **`--lfs-commit-rules`** (default on with `--use-lfs`; `--no-lfs-commit-rules` turns it off): `LfsSession.write_committed_rules` appends one rule per extension (`committed_rule_lines`; exact path for extension-less or odd names) to `.gitattributes` after checking it is clean. The runner commits it as ` (LFS rules)` and pushes it before the first batch. Local-only rules in diff --git a/pyproject.toml b/pyproject.toml index 28e646e..f8d6ffa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,13 +4,32 @@ build-backend = "hatchling.build" [project] name = "commitrocket" -version = "0.1.1" +version = "0.1.2" description = "Batch Git changes by size, commit each batch, and push with live progress." readme = "README.md" license = { file = "LICENSE" } requires-python = ">=3.11" +keywords = ["git", "commit", "push", "batch", "large-files", "git-lfs", "cli"] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Software Development :: Version Control :: Git", + "Topic :: Utilities", +] dependencies = ["rich>=13", "pathspec>=0.12"] +[project.urls] +Homepage = "https://github.com/coldsofttech/CommitRocket" +Issues = "https://github.com/coldsofttech/CommitRocket/issues" + [project.scripts] commitrocket = "commitrocket.cli:main" diff --git a/src/commitrocket/__init__.py b/src/commitrocket/__init__.py index 39956ba..9fccbdc 100644 --- a/src/commitrocket/__init__.py +++ b/src/commitrocket/__init__.py @@ -1,3 +1,3 @@ """CommitRocket: batch Git changes by size, commit each batch, and push.""" -__version__ = "0.1.1" +__version__ = "0.1.2" diff --git a/src/commitrocket/cli.py b/src/commitrocket/cli.py index dc96bff..d3d639e 100644 --- a/src/commitrocket/cli.py +++ b/src/commitrocket/cli.py @@ -130,10 +130,18 @@ def build_parser(): ) parser.add_argument( "--lfs-commit-rules", + dest="lfs_commit_rules", action="store_true", - help="With --use-lfs, also commit LFS rules to .gitattributes (one per " - "file extension) so clones get real files and future files of the same " - "type use LFS", + default=True, + help="With --use-lfs, commit LFS rules to .gitattributes (one per file " + "extension) so clones and checkouts get real files (default)", + ) + parser.add_argument( + "--no-lfs-commit-rules", + dest="lfs_commit_rules", + action="store_false", + help="With --use-lfs, keep the LFS rules local to this run. Checkouts " + "and clones will then contain LFS pointer files instead of the real files", ) parser.add_argument( "--dry-run", @@ -260,8 +268,6 @@ def validate(parser, args): "stay local and a later plain 'git push' would publish LFS pointers " "without their data" ) - if args.lfs_commit_rules and not args.use_lfs: - parser.error("--lfs-commit-rules requires --use-lfs") for label, value in (("--remote", args.remote), ("--branch", args.branch)): if value is not None: diff --git a/src/commitrocket/options.py b/src/commitrocket/options.py index ad609f5..76abae7 100644 --- a/src/commitrocket/options.py +++ b/src/commitrocket/options.py @@ -28,7 +28,7 @@ class RunOptions: lfs_threshold_mib: int = LFS_THRESHOLD_MIB lfs_threads: int | None = None lfs_batch_mib: int | None = None - lfs_commit_rules: bool = False + lfs_commit_rules: bool = True include: list = field(default_factory=list) exclude: list = field(default_factory=list) include_from: list = field(default_factory=list) diff --git a/src/commitrocket/runner.py b/src/commitrocket/runner.py index a1307c9..7e67c11 100644 --- a/src/commitrocket/runner.py +++ b/src/commitrocket/runner.py @@ -433,7 +433,8 @@ def list_pending(): else: lfs_scope = ( f"{which} will be stored with Git LFS for this run only; " - "no LFS config is committed." + "no LFS config is committed, so checkouts and clones will " + "contain LFS pointer files instead of the real files." ) if o.dry_run and not is_lfs_available(): lfs_scope += " git-lfs is not installed and would be installed." diff --git a/tests/test_cli.py b/tests/test_cli.py index dd95554..78db7d2 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -23,7 +23,6 @@ def test_own_output_files_are_found_only_inside_the_repo(tmp_path): "argv", [ ["--message", "m", "--no-push", "--use-lfs"], - ["--message", "m", "--lfs-commit-rules"], ["--message", "m", "--message-template", "{nope}"], ["--message", "m", "--lfs-threshold-mib", "150"], ["--message", "m", "--retries", "-1"], diff --git a/uv.lock b/uv.lock index 80f575f..c2423f5 100644 --- a/uv.lock +++ b/uv.lock @@ -22,7 +22,7 @@ wheels = [ [[package]] name = "commitrocket" -version = "0.1.1" +version = "0.1.2" source = { editable = "." } dependencies = [ { name = "pathspec" },