- 1 - I updated `.configure.sh` so repositories that already have Git LFS hook scripts in `.git/hooks` now treat `git-lfs` as a required dependency during verification, install the `git-lfs` system package on supported package managers, and run `git lfs install --local` during non-verify setup.
(cherry picked from commit b66ec8c19d)
- 1 - I updated `smart-build.sh` so its interactive architecture menu now offers `macos-amd64`, `macos-arm64`, and includes both Darwin targets in `All Arch`, while preserving the existing `darwin` artifact naming in `dist/`.
- 2 - I added a dedicated Darwin SQLite build path in `smart-build.sh` that routes macOS `bindata sqlite sqlite_unlock_notify` builds through `make release-darwin`, and I updated `Makefile` to make `release-darwin` configurable through `DARWIN_ARCHS` so helper scripts can request only `darwin-10.12/amd64` or `darwin-10.12/arm64`.
- 3 - I hardened the Darwin SQLite flow in `smart-build.sh` for `code-server`-style containerized workspaces by distinguishing between a missing Docker CLI and an unreachable Docker daemon, by validating that the host Docker daemon can see the same mounted repository `go.mod` path as the current workspace, and by moving the temporary release output under `dist/` instead of `/tmp`.
- 4 - I added `SMART_BUILD_DARWIN_HOST_REPO_PATH` support to `smart-build.sh` so Darwin SQLite builds can be redirected to a host-visible repository mount path when the interactive workspace path inside the container differs from the real host path used by the Docker daemon.
(cherry picked from commit 06e5bd7f46)
- 1 - I updated the remaining bare `#NNNNN` pull-request references in `CHANGELOG.md` so they now point directly to `https://github.com/go-gitea/gitea/pull/...`, without folding this tag-specific changelog cleanup into the earlier generic changelog-link conversion entry.
(cherry picked from commit 2d228475fc)
Backport of #37403 to `release/v1.26`.
The `events › logout propagation` e2e test was racing the SSE connection
setup: if page2's SharedWorker had not finished registering its
messenger by the time page1 triggered logout, the event was silently
dropped and page2 stayed on the authenticated page.
Wait 500ms after verifying page2 is signed in, before triggering the
logout from page1, so the SharedWorker has time to register. Comment
points at a cleaner future fix (expose a ready attribute on the page)
that will also work for the planned WebSocket SharedWorker.
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
(cherry picked from commit 64d12024d65c5f343f4ae89ea9a6f6ed5616ef82)
(cherry picked from commit a6b0bd9755)
Backport #37388 by @wxiaoguang
Fix#27120
By the way, refactor ReserveLineBreakForTextarea to NormalizeStringEOL
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit 5d7768f34ca7d100823a2ced855c288409478690)
(cherry picked from commit ef0e2ecdc1)
Backport #37365 by @pisarz77
Fix team members missing from assignee list when `team_unit.access_mode`
is 0 but the doer is owner.
Fix #34871
1. Use `GetTeamUserIDsWithAccessToAnyRepoUnit` for repo assignee list
2. Load assignee list for project issues directly
3. Use `GetTeamUserIDsWithAccessToAnyRepoUnit` for repo reviewer list
Signed-off-by: Jakub Pisarczyk <pisarz77@gmail.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: pisarz77 <pisarz77@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
(cherry picked from commit 55a6cfe79b57a42b0ae279fa5c7a5f261d7823eb)
(cherry picked from commit 7ed64f3c94)
Backport #37288 by @KalashThakare
## Summary
Fixes#37252
The `/api/v1/repos/{owner}/{repo}/actions/runs` endpoint was returning
`event: "push"` for workflow runs triggered by `schedule:` (cron),
instead
of `event: "schedule"`.
## Root Cause
`ActionRun` has two separate fields:
- `Event` — the workflow registration event (e.g. `push`, set when the
workflow file was first pushed)
- `TriggerEvent` — the actual event that triggered the run (e.g.
`schedule`)
`ToActionWorkflowRun` in `services/convert/action.go` was serializing
`run.Event` into the API response instead of `run.TriggerEvent`, causing
scheduled runs to be indistinguishable from push events via the API.
This was already asymmetric — the tasks/jobs API correctly used
`TriggerEvent`.
## Fix
Changed `ToActionWorkflowRun` to use `run.TriggerEvent` for the `event`
field in the API response, consistent with how the jobs API works.
## Before
`event: "push"` returned for all scheduled runs:
<img width="1112" height="191" alt="Screenshot 2026-04-19 115642"
src="https://github.com/user-attachments/assets/c0a169f5-bbd9-4f5d-9474-e4c3795110e4"
/>
## After
`event: "schedule"` correctly returned for scheduled runs:
<img width="890" height="166" alt="Screenshot 2026-04-19 121723"
src="https://github.com/user-attachments/assets/860e99ac-0935-4a43-86a1-7b60f8113480"
/>
## Testing
- Added unit test `TestToActionWorkflowRun_UsesTriggerEvent` in
`services/convert/action_test.go` that explicitly verifies the API
returns `TriggerEvent` and not `Event` for a scheduled run.
- Manually verified via the API against a live Gitea instance with a
`cron: "* * * * *"` workflow.
Co-authored-by: Kalash Thakare ☯︎ <kalashthakare898@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
(cherry picked from commit fc9dfe0e56a84f2eb8e389d364f2da0b9c24d917)
(cherry picked from commit 836d451d6a)
Backport #37324 by @lunny
A quick fix#37317
---
The current behavior for forks when an organization or repository is
changed to private differs from GitHub.
On GitHub, when a parent repository becomes private, the fork
relationship is removed, which keeps the behavior simple and avoids
visibility conflicts.
I think we need a similar solution to handle cases where the parent
repository becomes private while a fork remains public and the fork
relationship is still preserved.
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit 291f6cbd3abfd0ffb6a9d70efb2d943e581ff257)
(cherry picked from commit f31163e6de)
Backport #37338 by @wxiaoguang
Modern syntax was added in git 2.0
And add more tests
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit f536bcd5084a9fb1864977b90a86e206ca6e6f5d)
(cherry picked from commit a5b92e70ab)
Backport #37327 by @prettysunflower
Nyallo~
In pull request #36901, a change is made so that the link to
authentication sources is now escaped with the QueryEscape filter.
https://github.com/go-gitea/gitea/pull/36901/changes#diff-34c39c9736a8b62e293c0c0b24c4b5b8c1c792790018c5809f9ff2cbc12b16b1R4
The problem is that [QueryEscape replace spaces with the `+`
character](https://cs.opensource.google/go/go/+/refs/tags/go1.26.2:src/net/url/url.go;l=234;drc=917949cc1d16c652cb09ba369718f45e5d814d8f),
and this is not unescaped when a user tries to log in with an
authentication source that contains a space, which throws an error.
This commit fixes that by unescaping the provider name in the URL.
---
Example of the error, on my instance, when I try to log in with
`prettysunflower's auth`
```
2026/04/21 00:11:41 routers/web/auth/oauth.go:42:SignInOAuth() [E] SignIn: oauth2 source not found, name: "prettysunflower's+auth"
/go/src/code.gitea.io/gitea/routers/web/auth/oauth.go:42 (0x2cfa5c5)
/usr/local/go/src/reflect/value.go:586 (0x51e245)
/usr/local/go/src/reflect/value.go:369 (0x51d0f8)
/go/src/code.gitea.io/gitea/modules/web/handler.go:181 (0x1a6aaf6)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:188 (0x1a6ab65)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:188 (0x1a6ab65)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:188 (0x1a6ab65)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/services/context/context.go:217 (0x2df1b23)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/gitea.com/go-chi/session@v0.0.0-20251124165456-68e0254e989e/session.go:258 (0x197eb82)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/chain.go:31 (0x1a61d05)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:479 (0x1a64fae)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:73 (0x1a628c2)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:321 (0x1a6421a)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/chain.go:31 (0x1a61d05)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:479 (0x1a64fae)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/middleware/get_head.go:37 (0x2c33a67)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:73 (0x1a628c2)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:321 (0x1a6421a)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/routers/common/maintenancemode.go:50 (0x2b752da)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/chain.go:31 (0x1a61d05)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:479 (0x1a64fae)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/routing/logger_manager.go:124 (0x127d1ec)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/chi-middleware/proxy@v1.1.1/middleware.go:37 (0x2b76acf)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/routers/common/middleware.go:89 (0x2b78cd6)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/routers/common/middleware.go:104 (0x2b7890f)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:90 (0x1a62881)
/go/src/code.gitea.io/gitea/modules/web/router.go:286 (0x1a6d2a2)
/go/src/code.gitea.io/gitea/modules/web/router.go:221 (0x1a6cbc6)
/usr/local/go/src/net/http/server.go:3311 (0x96e36d)
/usr/local/go/src/net/http/server.go:2073 (0x94bd6f)
/usr/local/go/src/runtime/asm_amd64.s:1771 (0x49af20)
```
Signed-off-by: prettysunflower <me@prettysunflower.moe>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: prettysunflower <me@prettysunflower.moe>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
(cherry picked from commit ef096b0f9025122957b049b5d1a9c4f27bcc1d78)
(cherry picked from commit b14015efe9)
Backport #37311 by @silverwind
## Problem
Workflow-level concurrency groups were evaluated — and jobs were parsed
— before the run was persisted, so `run.ID` was `0` and `github.run_id`
in the expression context resolved to an empty string. Expressions like:
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
```
collapsed to `<workflow>-` on every push event (`head_ref` is empty on
push), so `cancel-in-progress` cancelled in-progress runs across
**unrelated branches**, not just the current one.
Reproduced on a 1.26 instance:
- push to `master` → `ci` run starts
- push to `feature-branch` → the `master` run gets cancelled
GitHub Actions' documented semantic: on push events `github.run_id` is
unique per run, so the group is unique → no cancellation; on PR events
`github.head_ref` is the source branch → cancellation is per-PR.
## Fix
Insert the run **before** parsing jobs or evaluating workflow-level
concurrency, so `run.ID` is populated in time for every expression that
reads `github.run_id` — not just the concurrency group, but also
`run-name`, job names, and `runs-on`.
`jobparser.Parse` now runs inside the `InsertRun` transaction, after
`db.Insert(ctx, run)`. Workflow-level concurrency evaluation runs next
and only mutates `run` in memory. All concurrency-derived fields
(`raw_concurrency`, `concurrency_group`, `concurrency_cancel`) plus
`status` and `title` are persisted in a single final `UpdateRun` at
end-of-transaction — one `INSERT` + one `UPDATE` per run in both the
concurrency and non-concurrency paths (matches pre-branch parity, one
fewer `UpdateRepoRunsNumbers` `COUNT` than the interim state).
`GenerateGiteaContext` now sets `run_id` from `run.ID` unconditionally;
every caller passes a persisted run.
**Verification**: tested end-to-end on a 1.26 deployment. Before the
patch, two successive `ci` pushes (one to master, one to a feature
branch) cross-cancelled each other. After the patch, the same pushes —
in both orders (master→branch, branch→master) — run to completion
simultaneously across 15+ runs with zero cancellations.
**Regression tests** in `services/actions/context_test.go`:
- `TestEvaluateRunConcurrency_RunIDFallback` — unit check that
`EvaluateRunConcurrencyFillModel` resolves `github.run_id` from
`run.ID`.
- `TestPrepareRunAndInsert_ExpressionsSeeRunID` — full-flow check: calls
`PrepareRunAndInsert` with `${{ github.run_id }}` in both `run-name` and
the concurrency group, then asserts the persisted `Title`,
`ConcurrencyGroup`, and `RawConcurrency` contain / survive the run's ID.
Re-ordering `db.Insert` relative to either parse or concurrency eval
fails this test.
## Relation to #37119
[#37119](https://github.com/go-gitea/gitea/pull/37119) also moves
concurrency evaluation into `InsertRun` but keeps it **before**
`db.Insert`, then tries to populate `run_id` only when `run.ID > 0` —
which is still `0` at that call site, so the cross-branch leak would
survive that PR as written. This PR fixes the ordering so that `run.ID`
is actually populated at eval time, and broadens it to cover parse-time
expression interpolation too.
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
(cherry picked from commit 7bd55deab302d1de482737340954a8be7efb132d)
(cherry picked from commit 433efc6093)
Backport #37325 by @lunny
Fix a bug the checkout command line hint become `git fetch -u
https://gitea.combircni/tea`
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
(cherry picked from commit f0fd185f14fdcc13a0ec50f3134515623abbf0a2)
(cherry picked from commit aff9a28fa4)
Backport #37279 by @silverwind
Moves the manifest patching from `closeBundle` to `writeBundle`. Thrown
errors in `writeBundle` work correctly and exit the build.
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit adfa535dc200f81f6452b22f36d94f1ca8de9606)
(cherry picked from commit 3249dedde1)
Backport #37296
Co-authored-by: Nicolas <bircni@icloud.com>
(cherry picked from commit e6691b0e8d2948c609fabb95967de1209f3c4520)
(cherry picked from commit e28eec37ea)
Backport #37290 by wxiaoguang
Fix#37289
Don't tell container client that the instance needs basic auth if the
public access is available.
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit 82613a40a02908eca7b256567354931500b94253)
(cherry picked from commit 2de0b4f34d)
Backport #37189 by @bircni
If a workflow is not in default branch the hooks could not be detected
Fixes#37169
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit ba5117e4e4327c69f1b24dcf5c408279b4e80781)
(cherry picked from commit bff8f3d2e4)
- 1 - I updated the `/-/admin/users` delete modal in the user table to submit an explicit inline fetch flag, and I changed the web admin `DeleteUser` handler so that this table-specific fetch flow now returns `JSONRedirect` on success and `JSONError` for expected validation failures, while the classic edit-page delete form keeps its normal redirect behavior; I also added integration coverage for the table delete path.
(cherry picked from commit 849cb3f6ae)
- 1 - I updated `Makefile` so `GITEA_VERSION` now strips the leading `v`, preserves exact custom tag names such as `1.26.0-by-petru`, and converts only the trailing `-N-gSHA` suffix from `git describe` into `+N-gSHA` for in-between builds like `1.26.0-by-petru+3-g...` and `1.27.0-dev+143-g...`.
(cherry picked from commit adb90b3453)
- 1 - I updated [`.smart-build.sh`](/config/workspace/gitea-dev/gitea/.smart-build.sh) so each build artifact is now written as `gitea-<tag-or-ref>-<os>-<platform><-sqlite>` with the original executable extension preserved, and each output also gets its own adjacent `.sha256` file generated with `sha256sum` or `shasum -a 256`.
(cherry picked from commit c6f2b32f0b)
- 1 - I updated [`.maintain-custom-release.sh`](/config/workspace/gitea-dev/gitea/.maintain-custom-release.sh) so `Sync upstream release target commits` validates only the configured `UPSTREAM_RELEASE_TARGET_REF` when one is set, instead of still failing on a missing local `upstream/release/...` remote-tracking branch after successfully fetching a target tag such as `v1.26.1`.
(cherry picked from commit 244a472691)
Backport of go-git upgrade to v5.18.0 for the v1.26 release branch.
Fixes GHSA-3xc5-wrhm-f963 (credential exposure on HTTP redirects).
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
(cherry picked from commit eb43da41f58f95aa014a80e333baa44d264d5a38)
Backport #37244 by @JoeGruffins
Patterns starting with "/" (e.g. /docs/.*\.md) never matched because git
returns relative paths without a leading slash. Strip the leading "/"
before compiling the regex since the ^...$ anchoring already provides
root-relative semantics.
closes#28107
Co-authored-by: JoeGruffins <34998433+JoeGruffins@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit 26a618ac1a773da722dfa13c7647dfdcc1c64355)
Backport #37256 by wxiaoguang
1. Make sure OmitEmail won't panic
2. SSH principal keys are not for signing or authentication
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit b191cf7e7708e122be300f8e88554413680c34e4)
- 1 - I made `bootstrap` a clean branch-creation step from `BASE_TAG`, separated fetch and sync into explicit compare/release-target/custom actions, added `UPSTREAM_RELEASE_TARGET_REF`, and updated the built-in help so the recommended workflow matches the current menu structure.
- 2 - I hardened recovery so rollback, restore-point, restore-snapshot, restore-stash, and restore-deletion correctly preserve or clean script-managed refs, maintenance branches, state files, backup branches, and snapshots, including rollback from the original entry branch after a bootstrap-created maintenance branch, cleanup of legacy restore-point leftovers, and removal of the paired `backup/maint-*` Git Graph marker when a saved snapshot is deleted.
- 3 - I finalized the interactive UX by keeping a self-updating runtime copy in `/tmp`, persisting the last-used settings in `/tmp/.maintain-custom-release.env`, and reorganizing the menu into `Manual Backups >`, `Fetch upstreams >`, `Sync >`, `Rollback >`, and `Restore >` submenus, including `Delete Restore >` with numbered stash and snapshot selection, with numbered selections, `b`/`B` or `Enter` for Back, correct return-to-parent behavior from every submenu, and `0` for Exit.
(cherry picked from commit 5eae94f95a)
- 1 - I made `bootstrap` a clean branch-creation step from `BASE_TAG`, separated fetch and sync into explicit compare/release-target/custom actions, added `UPSTREAM_RELEASE_TARGET_REF`, and updated the built-in help so the recommended workflow matches the current menu structure.
- 2 - I hardened recovery so rollback, restore-point, restore-snapshot, and restore-stash correctly preserve or clean script-managed refs, maintenance branches, state files, backup branches, and snapshots, including rollback from the original entry branch after a bootstrap-created maintenance branch and cleanup of legacy restore-point leftovers.
- 3 - I finalized the interactive UX by keeping a self-updating runtime copy in `/tmp`, persisting the last-used settings in `/tmp/.maintain-custom-release.env`, and reorganizing the menu into `Backups >`, `Fetch upstreams >`, `Sync >`, `Rollback >`, and `Restore >` submenus with numbered selections, `b`/`B` or `Enter` for Back, and `0` for Exit.
(cherry picked from commit 3bbe60b6b7)
- Added a persistent `/tmp/.maintain-custom-release.env` settings file so the last used configuration survives script restarts.
- Moved `bootstrap` ahead of the explicit fetch actions in the interactive menu, removed automatic fetching from `bootstrap` and `plan`, and split both the fetch and sync flows into separate compare-branch and release-target actions while clarifying that custom commits are cherry-picked from oldest to newest.
(cherry picked from commit f5718dd509)