feat: sync forks (#2364)

This allows syncing a branch of a fork with a branch of the base repo. It looks like this:
![grafik](/attachments/4508920c-7d0b-4330-9083-e3048733e38d)
This is only possible, if the fork don't have commits that are not in the main repo.

The feature is already working, but it is missing Finetuning, a better API, translations and tests, so this is currently WIP. It is also not tested with go-git.

<!--start release-notes-assistant-->

## Release notes
<!--URL:https://codeberg.org/forgejo/forgejo-->
- Features
  - [PR](https://codeberg.org/forgejo/forgejo/pulls/2364): <!--number 2364 --><!--line 0 --><!--description c3luYyBmb3Jrcw==-->sync forks<!--description-->
<!--end release-notes-assistant-->

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/2364
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: JakobDev <jakobdev@gmx.de>
Co-committed-by: JakobDev <jakobdev@gmx.de>
This commit is contained in:
JakobDev 2025-04-07 07:00:38 +00:00 committed by Earl Warren
parent 3272e3588a
commit 8296a23d79
15 changed files with 723 additions and 4 deletions

View file

@ -158,6 +158,18 @@
{{end}}
</div>
</div>
{{if .CanSyncFork}}
<div class="ui positive message tw-flex tw-items-center">
<div class="tw-flex-1">
{{ctx.Locale.TrN .ForkCommitsBehind "repo.sync_fork.branch_behind_one" "repo.sync_fork.branch_behind_few" .ForkCommitsBehind (printf "<a href='%s'>%s:%s</a>" .BaseBranchLink .Repository.BaseRepo.FullName .BranchName | SafeHTML)}}
</div>
<a role="button" class="ui compact positive button tw-m-0" href="{{.SyncForkLink}}">
{{ctx.Locale.Tr "repo.sync_fork.button"}}
</a>
</div>
{{end}}
{{if .IsViewFile}}
{{template "repo/view_file" .}}
{{else if .IsBlame}}

View file

@ -15630,6 +15630,172 @@
}
}
},
"/repos/{owner}/{repo}/sync_fork": {
"get": {
"produces": [
"application/json"
],
"tags": [
"repository"
],
"summary": "Gets information about syncing the fork default branch with the base branch",
"operationId": "repoSyncForkDefaultInfo",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/SyncForkInfo"
},
"400": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/notFound"
}
}
},
"post": {
"produces": [
"application/json"
],
"tags": [
"repository"
],
"summary": "Syncs the default branch of a fork with the base branch",
"operationId": "repoSyncForkDefault",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
},
"400": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/notFound"
}
}
}
},
"/repos/{owner}/{repo}/sync_fork/{branch}": {
"get": {
"produces": [
"application/json"
],
"tags": [
"repository"
],
"summary": "Gets information about syncing a fork branch with the base branch",
"operationId": "repoSyncForkBranchInfo",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "string",
"description": "The branch",
"name": "branch",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/SyncForkInfo"
},
"400": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/notFound"
}
}
},
"post": {
"produces": [
"application/json"
],
"tags": [
"repository"
],
"summary": "Syncs a fork branch with the base branch",
"operationId": "repoSyncForkBranch",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "string",
"description": "The branch",
"name": "branch",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
},
"400": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/notFound"
}
}
}
},
"/repos/{owner}/{repo}/tag_protections": {
"get": {
"produces": [
@ -27432,6 +27598,30 @@
},
"x-go-package": "forgejo.org/modules/structs"
},
"SyncForkInfo": {
"description": "SyncForkInfo information about syncing a fork",
"type": "object",
"properties": {
"allowed": {
"type": "boolean",
"x-go-name": "Allowed"
},
"base_commit": {
"type": "string",
"x-go-name": "BaseCommit"
},
"commits_behind": {
"type": "integer",
"format": "int64",
"x-go-name": "CommitsBehind"
},
"fork_commit": {
"type": "string",
"x-go-name": "ForkCommit"
}
},
"x-go-package": "forgejo.org/modules/structs"
},
"Tag": {
"description": "Tag represents a repository tag",
"type": "object",
@ -29211,6 +29401,15 @@
}
}
},
"SyncForkInfo": {
"description": "SyncForkInfo",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/SyncForkInfo"
}
}
},
"Tag": {
"description": "Tag",
"schema": {