Docs: Review transfer documentation
Problem
The transfer documentation is fragmented and difficult to understand. As part of &17968 (closed), we should review the current behaviour and ensure that we document how permissions behave exactly for different scenarios, such as:
- Transferring a personal project to a group
- Transferring a group project to a personal namespace
- Transferring a group to another group
- Transferring a group to become a top-level group
Proposal
- Migrate content from https://docs.gitlab.com/user/project/settings/migrate_projects/ to https://docs.gitlab.com/user/project/working_with_projects/. For groups this is combined on one page as well.
- Restructure content for clarity around prerequisites, changes and limitations. Below is a suggestion from Claude:
Restructured group and project documentation
GitLab Transfer Documentation
Group Transfers
Overview
Group transfers move groups from one location to another within the same GitLab instance. You can restructure your organization hierarchy by:
- Converting top-level groups to subgroups - Move a top-level group under another group
- Converting subgroups to top-level groups - Move a subgroup out of its parent to become independent
- Moving subgroups between parents - Transfer a subgroup to a different parent group
What Gets Transferred
Included:
- All subgroups and projects within the group
- Explicit group memberships and roles
- Group settings and configurations
Not Included:
- Inherited memberships (members lose access unless they have explicit membership in target location)
Prerequisites
- Owner role required for both source and target groups
- Target group must allow subgroup creation (if applicable)
Important Limitations & Considerations
Membership Changes
- Inherited membership is lost - Only explicit group members are transferred
- Ownership requirement - If current owners only have inherited membership, the person performing the transfer becomes the new owner
Visibility & Access
- Visibility inheritance - If target parent has lower visibility, all subgroups and projects will be downgraded to match
- Repository URLs change - Local repositories must be updated to point to new paths
Package & Registry Restrictions
- npm packages - Transfers fail if top-level group contains npm packages following naming conventions
- Container registry - Images in archived projects must be deleted before transfer
- Package endpoints - Group-level packages (Maven, NuGet, PyPI, Composer, Debian) need endpoint updates
- Instance-level packages - Package names need updates if moved to different top-level group
Subscription Restrictions
- GitLab.com limitation - Top-level groups with active subscriptions cannot be transferred (subscription must be removed first)
Transfer Steps
- Navigate to your group: Search or go to → select your group
- Go to group settings: Settings → General
- Access transfer options: Expand Advanced section
- Initiate transfer: Select Transfer group
- Choose destination: Select target group from dropdown
- Confirm transfer: Select Transfer group
Post-Transfer Actions
- Update local repository remotes to new URLs
- Verify group member access and permissions
- Update package configurations if applicable
- Test CI/CD pipelines and integrations
Project Transfers
Overview
Project transfers move individual projects between any namespaces within the same GitLab instance. This allows you to reorganize projects without losing data or configuration.
You can transfer projects in any of these scenarios:
- Personal namespace to group - Move your personal project into a team or organization group
- Group to group - Transfer projects between different groups for reorganization
- Group to personal namespace - Move a group project to your personal namespace
What Gets Transferred
Project Components:
- Issues, merge requests, and discussions
- CI/CD pipelines and configurations
- Project dashboards and wiki
- Repository code and history
Membership:
- Direct project members and their roles
- Pending membership invitations
Automatic Adjustments:
- New project-level labels created if matching group labels don't exist
- Epic copies created in target group if needed (with separate copies per project)
Prerequisites
- Owner role for the project being transferred
- Maintainer role (minimum) for the target group
- Target group must allow new project creation
Important Limitations & Considerations
Membership Changes
- Inherited membership is lost - Members with only inherited access lose permissions
- New permissions inherited - Project inherits member permissions from target group
Container Registry Restrictions
- GitLab.com - Can only transfer within same top-level namespace
- Self-managed - Project must not contain container images
Package Considerations
- npm packages - Must remove packages following naming convention if root namespace changes
- Post-transfer options - Update package scope OR republish without convention (loses instance endpoint access)
Other Restrictions
- Security policies - Projects with security policies have them automatically unassigned
- Path changes - Repository URLs change, requiring local repository updates
Transfer Steps
- Navigate to your project: Search or go to → select your project
- Go to project settings: Settings → General
- Access transfer options: Expand Advanced section
- Choose destination: Under Transfer project, select target namespace
- Initiate transfer: Select Transfer project
- Confirm transfer: Enter project name and select Confirm
Subscription Tier Changes
When transferring from Premium/Ultimate to Free tier:
- Access tokens revoked - All project access tokens are automatically revoked
- Features removed - Pipeline subscriptions and test cases are deleted
Post-Transfer Actions
- Update local repository remotes to new URLs
- Verify project member access and permissions
- Update package configurations and republish if needed
- Test CI/CD pipelines and integrations
- Review and reassign security policies if needed
Troubleshooting
Console Transfer Method
If UI transfer fails, use Rails console:
# Find the project
p = Project.find_by_full_path('<project_path>')
# Set current user (project owner)
current_user = p.creator
# Find target namespace
namespace = Namespace.find_by_full_path("<new_namespace>")
# Execute transfer
Projects::TransferService.new(p, current_user).execute(namespace)