Skip to content

Conversation

AdamMajer
Copy link
Contributor

Normally, a fork becomes the child of the source repository. In this case, the fork becomes the new parent of the source repository.

Closes: #34848

Normally, a fork becomes the `child` of the source repository.
In this case, the fork becomes the new `parent` of the source
repository.

Closes: go-gitea#34848
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Sep 7, 2025
@github-actions github-actions bot added modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code labels Sep 7, 2025
@AdamMajer
Copy link
Contributor Author

I'm not certain about permissions here, but I think this option only makes sense for server admin or admin of both source and target organizations.


// ReparentFork sets the fork to be an unforked repository and the forked repo becomes its fork
func ReparentFork(ctx context.Context, forkedRepoID, srcForkID int64) error {
if _, err := db.GetEngine(ctx).Table("repository").ID(srcForkID).Cols("fork_id", "is_fork").Update(&Repository{ForkID: forkedRepoID, IsFork: true}); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Database transaction is necessary. And what happens for the other fork repositories of the original parent repository?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect nothing needs to happen to the other forks. This is about just one particular fork.

This was already called from within a transaction, but never
know about future callers
@lunny
Copy link
Member

lunny commented Sep 7, 2025

This feature is unusual—it can only be accessed through the API, not the web interface.

@AdamMajer
Copy link
Contributor Author

I agree this is not a usual feature that should be exposed via UI. Maybe in the admin interface? But then is it even worth it? We plan on using this via API-only.

An additional feature that would make sense to expose via UI may be to change the fork_id of a repository to another repository with compatible git history. This one would only need admin access to the repository that is being changed. But I think that's a different PR.

// ReparentFork sets the fork to be an unforked repository and the forked repo becomes its fork
func ReparentFork(ctx context.Context, forkedRepoID, srcForkID int64) error {
return db.WithTx(ctx, func(ctx context.Context) error {
if _, err := db.GetEngine(ctx).Table("repository").ID(srcForkID).Cols("fork_id", "is_fork").Update(&Repository{ForkID: forkedRepoID, IsFork: true}); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fork numbers should be updated as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the source repo, the number of forks remain as-is. Only its new parent is updated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fork count of the source repository should be decreased, while the fork count of the new parent repository should be increased.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fork count in the source repository is not yet increased here and it never is because it's part of the else{} clause in the calling function.

The fork of the new parent is set as 1 already.

But I understand how this design is a little confusing. I'll split this into separate API call instead which will make this more straightforward.

@@ -52,6 +52,7 @@ type ForkRepoOptions struct {
Name string
Description string
SingleBranch string
Reparent bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the previous implementation to have a new API to do the reparent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous implementation? Or do you mean this should be a new API call, like Repository/CreateNewParent or similar name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do a new API call here, can we still use the repo_service.ForkRepoOptions{Reparent:true} or split off that logic on top of a fork?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think introducing a new API endpoint would be more appropriate. Also, the Reparent field in ForkRepoOptions feels a bit awkward.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as we can use the internal Fork implementation already, I'm ok in introducing another API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Swap fork repos via "reparent"
3 participants