[CLI] Add unified hf cp command (aliased as hf repos cp and hf buckets cp)#4295
Conversation
…uckets cp`) Add a single `cp` command that copies a file between any local path, repository, or bucket (plus stdin/stdout), exposed identically as `hf cp`, `hf repos cp` and `hf buckets cp`. Move all copy-related tests into a dedicated `tests/test_copy_files.py` module and update the CLI, repository and buckets guides. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
|
nice unification! one thing on the aliasing: since is that intentional? wondering if |
Yes it was intentional to keep things simple and I don't think it's problematic too be permissive on that. Happy to revisit if someone feels strongly about it (it's not that complex anyway^^) |
We* were feeling it would maybe remove some footguns if someone copies to an unexpected place. But we can do this in another PR i guess *me and my agent |
Addressed in dbb5963 |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit dbb5963. Configure here.
| if context is None: | ||
| return | ||
| # The remote endpoint is the destination when it is an hf:// URI, otherwise the source (download). | ||
| remote = dst if (dst is not None and is_hf_uri(dst)) else src |
There was a problem hiding this comment.
Context enforcement only checks one remote endpoint
Low Severity
_enforce_context only inspects a single remote endpoint — it prefers dst when it's an hf:// URI, and falls back to src otherwise. For remote-to-remote copies where both sides are hf:// URIs, only the destination is validated against the context. This means hf repos cp hf://buckets/user/bucket/file.txt hf://user/repo/file.txt passes the guardrail even though the source is a bucket. The operation still fails later in copy_files (bucket-to-repo is unsupported), but with a less helpful error message than the intended CLIError.
Reviewed by Cursor Bugbot for commit dbb5963. Configure here.
Co-authored-by: célina <hanouticelina@gmail.com>
|
This PR has been shipped as part of the v1.18.0 release. |


This PR adds a single, unified
hf cpcommand to copy a files/folders between local and remote or between remote locations. Command is aliased ashf cp,hf buckets cpandhf repos cpwith exact same behavior. EDIT: now added a guardrail to prevent usinghf buckets cpon repos and vice-versa (see comments below #4295 (comment))Supported
Local can be a local file or stdin/stdout. To sync/upload/download folders, use the more feature-complete
hf sync/hf upload/hf downloadTests
Added
tests/test_copy_files.pyand moved all copy-related tests there:copy_filesandCommitOperationCopytests fromtest_hf_api.py, theCommitOperationCopy/_resolve_copy_target_pathtests fromtest_commit_api.py, and thecpCLI tests fromtest_buckets_cli.py. Added new coverage for the repo legs (upload, download, stdout,@revision, repo→repo) and the aliases.Examples
Uploading a local file to a repo or a bucket:
Downloading, including to a directory or to stdout:
$ hf cp hf://Wauplin/tmp-for-test/demo/config.json ./downloaded/ ✓ Downloaded src: hf://Wauplin/tmp-for-test/demo/config.json dst: ./downloaded/config.json $ hf cp hf://Wauplin/tmp-for-test/demo/config.json - {"hello": "world"}Piping from stdin:
Remote-to-remote, and the same command via the
reposalias doing a bucket→bucket copy:Note
Medium Risk
New user-facing CLI paths perform authenticated uploads, downloads, and server-side copies; mistakes could write to the wrong repo/bucket, though aliases and validation limit some misuse.
Overview
Introduces a unified
hf cpcommand (shared implementation incli/_cp.py) for copying a single file between local paths, repos, and buckets viahf://URIs or stdin/stdout. The same handler is registered ashf repos cpandhf buckets cp, with context guardrails so those aliases reject the wrong remote type (e.g. bucket URIs underhf repos cp).Behavior: local/stdin → repo or bucket upload; repo/bucket → local/stdout download (repos use a temp dir +
os.replacebeside the target); repo/bucket ↔ repo/bucket viaHfApi.copy_files. Bucket→repo and local→local are rejected; directories still go through upload/download/sync.Refactor: Removes the large inline
cpimplementation frombuckets.pyin favor ofmake_cp("buckets"); addsmake_cp("repos")on the repos CLI.Tests: New
tests/test_copy_files.pyconsolidates copy-related API and CLI tests (moved fromtest_hf_api,test_commit_api,test_buckets_cli) and adds repo upload/download and alias validation. CI splitstest_copy_filesinto the Xet-only job alongside bucket tests.Docs: User guides and generated CLI reference document
hf cp, alias equivalence, and a new Copy files section on the repository guide; bucket docs pivot examples tohf cpwhile noting aliases.Reviewed by Cursor Bugbot for commit 9265993. Bugbot is set up for automated code reviews on this repo. Configure here.