Desktop Material

Repository transfer

Transfer repository moves a GitHub-backed repository into a repository owned by another signed-in GitHub account or organization. It is available from the Repository menu, the repository-list context menu, Command Palette, and Repository settings → Remote.

Behavior

The dialog keeps the source repository visible beside the destination route and lets the user:

Full-history transfer requires a clean worktree; clean-state transfer instead snapshots the current tracked and untracked files that Git can commit. Neither mode may run inside a merge, squash, rebase, or cherry-pick operation. The provider repository is created only after those checks pass.

Full history

Full-history mode makes a temporary local bare clone, points that temporary clone at the new destination, and pushes every local branch and tag. The destination branch is verified with git ls-remote before the local checkout is changed. Existing history therefore remains available in the destination, including branches and tags that are not the current branch.

Clean state

Clean-state mode makes one new root commit from the current files and pushes it to the current branch. Before changing the branch, the old tip is retained in a local recovery ref under refs/desktop-material/transfer-backups/. If publication fails, the branch and checkout are restored and the recovery ref remains available for inspection or manual recovery. The stable snapshot commit message is Create clean repository transfer snapshot.

Remote topology

origin is retargeted only after the destination push and branch verification succeed. If the source had an origin and no upstream, its fetch URL becomes upstream so the source remains reachable; an explicit source push URL is preserved on that upstream remote. The new destination becomes origin, and a previous explicit origin push URL is updated to the destination rather than silently continuing to publish to the old repository. A partial local remote edit is rolled back when Git permits it.

Configuration

There is no separate preference. Destination accounts come from the existing account store, and the sign-in button uses the source repository's GitHub.com or GitHub Enterprise endpoint. The chosen owner, name, privacy, and mode are reviewed in the dialog and are not persisted as a second credential or hidden remote setting.

Failure modes

Security and privacy

Git credentials are routed through the selected account's existing credential key and are not embedded in a clone URL, progress message, error detail, or history record. Temporary full-history data is removed after publication. The clean-state recovery ref stays local. Repository names are bounded and allow only provider-safe letters, numbers, dots, dashes, and underscores; the destination owner is selected from the provider response rather than typed into an API path.

Verification

The focused transfer contract tests cover name validation, both modes, the second-account sign-in path, the two confirmation controls, the authorization slider, recovery refs, remote preservation, and menu/Command Palette discovery. Run them with:

node --import tsx --test app/test/unit/repository-transfer-test.ts app/test/unit/repository-transfer-surface-test.ts

The exact Windows production build and isolated hidden-desktop acceptance are the remaining runtime gates for this feature. The repository-wide test harness also needs its existing dependency-tree correction before it can load these tests; the focused direct Node run is the current local proof.

Suggested articles

This feature adds no HTTP endpoint, so no Postman collection is applicable.