Allow per-repository configuration for LFS migration and issue synchronization in mirror settings #147

Closed
opened 2026-10-05 01:44:37 +02:00 by adam · 12 comments
Owner

First of all

Thank you for all your work! They are wonderful. 🚀

Secondly

Allow per-repository configuration for LFS migration and issue synchronization in mirror settings

I would like to request a more flexible configuration model for repository mirroring.

Currently, the mirror configuration appears to apply the same settings to all repositories, including options such as:

  • Migrate LFS files
  • Migrate issues

This becomes problematic when mirroring a large number of repositories because different repositories often have very different requirements.

For example, some repositories such as browser-use consistently fail to mirror when "Migrate LFS files" is enabled. The migration reaches the LFS synchronization stage and fails, which causes the entire mirror operation to fail.

Image

Always migrating...
Image

Migrating manually in gitea without LFS configured is successful as followed.

Image Image

In this situation, there is no way to say:

"Mirror this repository, but do not migrate its LFS files."

Because the LFS option is configured globally for the mirror task, repositories that cannot be migrated with LFS enabled will repeatedly fail.

There are also other practical cases:

  • Some repositories have valuable issues/discussions, but their Git/LFS data is not particularly important.
  • Some repositories have a very large number of release assets, and storing all of them locally would consume an unreasonable amount of disk space.
  • Some repositories require LFS migration, while others should explicitly skip LFS.
  • Some repositories only need source code and tags, while others need issues, releases, or LFS objects.

Proposed improvement

I suggest allowing the mirror configuration to be overridden per repository.

For example, the global mirror configuration could define defaults:

Migrate LFS files: Yes
Migrate issues:    Yes
Migrate releases:  Yes

And each repository could override these options individually:

browser-use
    Migrate LFS files: No
    Migrate issues:    Yes
    Migrate releases:  No

some-other-repository
    Migrate LFS files: Yes
    Migrate issues:    No
    Migrate releases:  Yes

Alternatively, the UI could provide these options when adding or editing an individual repository:

Repository: browser-use

[ ] Migrate LFS files
[x] Migrate issues
[ ] Migrate releases

The global mirror configuration could still remain as the default, while allowing individual repositories to override it.

Why this would be useful

A single global configuration is difficult to use when mirroring repositories with significantly different characteristics.

More importantly, a single repository that cannot be migrated with LFS enabled can currently prevent that repository from being mirrored successfully at all.

Per-repository settings would allow users to choose the appropriate level of synchronization for each repository instead of having to choose between:

  1. Enable LFS globally and have some repositories fail permanently, or
  2. Disable LFS globally and lose LFS data from repositories where it is actually needed.

The same applies to issues and release assets. Different repositories have different priorities and storage requirements.

I believe making the mirror options configurable per repository would make the mirroring system considerably more flexible and practical for large-scale GitHub/Gitea mirroring.

Feature request: Please consider adding per-repository overrides for LFS migration, issue synchronization, and ideally other resource types such as releases/assets as well.

# First of all Thank you for all your work! They are wonderful. 🚀 ## Secondly ### Allow per-repository configuration for LFS migration and issue synchronization in mirror settings I would like to request a more flexible configuration model for repository mirroring. Currently, the mirror configuration appears to apply the same settings to all repositories, including options such as: - Migrate LFS files - Migrate issues This becomes problematic when mirroring a large number of repositories because different repositories often have very different requirements. For example, some repositories such as **browser-use** consistently fail to mirror when **"Migrate LFS files"** is enabled. The migration reaches the LFS synchronization stage and fails, which causes the entire mirror operation to fail. <img width="2231" height="207" alt="Image" src="https://github.com/user-attachments/assets/d4cdd5ba-2266-417d-beb9-a797567fb46f" /> Always migrating... <img width="1313" height="648" alt="Image" src="https://github.com/user-attachments/assets/7a9b53c7-1785-40c5-91c4-7eccf3b42f3d" /> Migrating manually in gitea without LFS configured is successful as followed. <img width="1398" height="1009" alt="Image" src="https://github.com/user-attachments/assets/a18dab1a-580f-491e-b396-cf136bbd0413" /> <img width="1045" height="810" alt="Image" src="https://github.com/user-attachments/assets/8e4a5658-6e4d-4984-900d-d9ad2872e3f6" /> In this situation, there is no way to say: > "Mirror this repository, but do not migrate its LFS files." Because the LFS option is configured globally for the mirror task, repositories that cannot be migrated with LFS enabled will repeatedly fail. There are also other practical cases: - Some repositories have valuable **issues/discussions**, but their Git/LFS data is not particularly important. - Some repositories have a very large number of **release assets**, and storing all of them locally would consume an unreasonable amount of disk space. - Some repositories require LFS migration, while others should explicitly skip LFS. - Some repositories only need source code and tags, while others need issues, releases, or LFS objects. ## Proposed improvement I suggest allowing the mirror configuration to be overridden **per repository**. For example, the global mirror configuration could define defaults: Migrate LFS files: Yes Migrate issues: Yes Migrate releases: Yes And each repository could override these options individually: browser-use Migrate LFS files: No Migrate issues: Yes Migrate releases: No some-other-repository Migrate LFS files: Yes Migrate issues: No Migrate releases: Yes Alternatively, the UI could provide these options when adding or editing an individual repository: Repository: browser-use [ ] Migrate LFS files [x] Migrate issues [ ] Migrate releases The global mirror configuration could still remain as the default, while allowing individual repositories to override it. ## Why this would be useful A single global configuration is difficult to use when mirroring repositories with significantly different characteristics. More importantly, **a single repository that cannot be migrated with LFS enabled can currently prevent that repository from being mirrored successfully at all**. Per-repository settings would allow users to choose the appropriate level of synchronization for each repository instead of having to choose between: 1. Enable LFS globally and have some repositories fail permanently, or 2. Disable LFS globally and lose LFS data from repositories where it is actually needed. The same applies to issues and release assets. Different repositories have different priorities and storage requirements. I believe making the mirror options configurable per repository would make the mirroring system considerably more flexible and practical for large-scale GitHub/Gitea mirroring. **Feature request:** Please consider adding per-repository overrides for LFS migration, issue synchronization, and ideally other resource types such as releases/assets as well. <!-- github-sync-id:5196323943 -->
adam closed this issue 2026-10-05 01:44:37 +02:00
Author
Owner

Not just LFS migration and issue synchronization, any other configurations can be included while preparing to migrate should be able to be customized.

Not just LFS migration and issue synchronization, any other configurations can be included while preparing to migrate should be able to be customized. <!-- github-comment-id:5346940996 -->
Author
Owner

Yeah, you've read this right.

We pass lfs: true straight through to Gitea's /repos/migrate, so the LFS pull happens inside Gitea's migration, not in our code. When it fails, Gitea throws out the whole migration and there's nothing left on our side to salvage. That's why it worked when you did it by hand with LFS off.

So we can't just catch it and carry on. Turning LFS off per repo is the only real fix here. Agreed it should be there.

Same story for the rest of your list. Issues, PRs, releases and wiki are all global right now. Repos already have a per-repo destination override, so there's a pattern to copy for this.

Couple of things before I start:

Do you want this at the org level too, so it goes global -> org -> repo? Orgs already have their own destination override, so it's cheap to add now and annoying to bolt on later. If you're mirroring a lot of repos, "everything under this org skips LFS" probably beats ticking boxes one at a time.

And which of these do you actually need? I'm planning LFS, issues, PRs, releases and wiki. If there's something else you'd want to set per repo, mention it now and I'll fold it in.

Yeah, you've read this right. We pass `lfs: true` straight through to Gitea's `/repos/migrate`, so the LFS pull happens inside Gitea's migration, not in our code. When it fails, Gitea throws out the whole migration and there's nothing left on our side to salvage. That's why it worked when you did it by hand with LFS off. So we can't just catch it and carry on. Turning LFS off per repo is the only real fix here. Agreed it should be there. Same story for the rest of your list. Issues, PRs, releases and wiki are all global right now. Repos already have a per-repo destination override, so there's a pattern to copy for this. Couple of things before I start: Do you want this at the org level too, so it goes global -> org -> repo? Orgs already have their own destination override, so it's cheap to add now and annoying to bolt on later. If you're mirroring a lot of repos, "everything under this org skips LFS" probably beats ticking boxes one at a time. And which of these do you actually need? I'm planning LFS, issues, PRs, releases and wiki. If there's something else you'd want to set per repo, mention it now and I'll fold it in. <!-- github-comment-id:5349193649 -->
Author
Owner

@MMMMMoris Please test out the new version and let me know

@MMMMMoris Please test out the new version and let me know <!-- github-comment-id:5349792936 -->
Author
Owner

@MMMMMoris Please test out the new version and let me know

Great! I'll be testing it later.👍

> @MMMMMoris Please test out the new version and let me know Great! I'll be testing it later.👍 <!-- github-comment-id:5350117030 -->
Author
Owner

@MMMMMoris Please test out the new version and let me know

It works! Marvelous! Keep testing...

> [@MMMMMoris](https://github.com/MMMMMoris) Please test out the new version and let me know It works! Marvelous! Keep testing... <!-- github-comment-id:5353460944 -->
Author
Owner

@MMMMMoris Please test out the new version and let me know

Seems like sync configurations are missing under mobile mode.

Screenshot_2026-08-21-01-26-26-618_com.android.chrome-edit.jpg

> @MMMMMoris Please test out the new version and let me know Seems like sync configurations are missing under mobile mode. ![Screenshot_2026-08-21-01-26-26-618_com.android.chrome-edit.jpg](https://github.com/user-attachments/assets/2a234b1e-2fd3-406f-a629-c839d0ed6999) <!-- github-comment-id:5359411764 -->
Author
Owner

@MMMMMoris Fixed in v3.27.1. The mobile cards had no menu at all, the options were only wired into the desktop table. Each card now has the same three dot menu:

Mobile repository card with the new three dot menu open, showing Mirror Options Mirror options dialog on mobile

The Organizations page had the same gap in reverse, the desktop menu was missing the entry while mobile had it. Both are in v3.27.1, image is on ghcr now. Thanks for catching it so quickly.

@MMMMMoris Fixed in v3.27.1. The mobile cards had no menu at all, the options were only wired into the desktop table. Each card now has the same three dot menu: <img src="https://gist.githubusercontent.com/arunavo4/7decfc7905cee7dba9af3df8f328ff13/raw/8c19f910fd49b4c9cc41f40cbb1087c96a19b108/shot-mobile-menu.png" width="320" alt="Mobile repository card with the new three dot menu open, showing Mirror Options" /> <img src="https://gist.githubusercontent.com/arunavo4/7decfc7905cee7dba9af3df8f328ff13/raw/8c19f910fd49b4c9cc41f40cbb1087c96a19b108/shot-mobile-dialog.png" width="320" alt="Mirror options dialog on mobile" /> The Organizations page had the same gap in reverse, the desktop menu was missing the entry while mobile had it. Both are in v3.27.1, image is on ghcr now. Thanks for catching it so quickly. <!-- github-comment-id:5364187495 -->
Author
Owner

@MMMMMoris Fixed in v3.27.1. The mobile cards had no menu at all, the options were only wired into the desktop table. Each card now has the same three dot menu:

Mobile repository card with the new three dot menu open, showing Mirror Options Mirror options dialog on mobile

The Organizations page had the same gap in reverse, the desktop menu was missing the entry while mobile had it. Both are in v3.27.1, image is on ghcr now. Thanks for catching it so quickly.

Yeah, it works on mobile now.

I have some questions and suggestions regarding the current repository mirroring behavior and UI.

1. Releases and Tags Synchronization

I have a question about how Releases and Tags are handled during mirroring.

As far as I understand, a GitHub Release is associated with a Git tag. If the mirror option includes Releases, does that mean the corresponding tags must also be synchronized?

More specifically:

  • Does enabling Releases also require synchronizing all tags?
  • Are Releases and Tags tightly coupled in the current mirroring implementation?
  • Is there currently any way to control how many Releases or Tags should be synchronized for each repository?
  • Could the number of Releases/Tags to synchronize be configurable on a per-repository basis?

For example, some repositories have a very large number of historical releases and tags, while I may only be interested in the latest few releases.

I am not very familiar with the internal synchronization mechanism between Releases and Tags, so I would also appreciate some clarification on how this currently works.

If possible, it would be useful to have per-repository options such as:

Synchronize Releases: Yes
Maximum Releases: 10

Synchronize Tags: Yes
Maximum Tags: 50

This could help significantly reduce unnecessary storage usage when mirroring repositories with a large amount of historical release data.


2. Repository Description Is Not Synchronized

Another issue I noticed is that the repository description does not seem to be synchronized when creating a mirror through gitea-mirror.

For comparison, Gitea's built-in repository mirroring functionality is able to synchronize the repository description.

However, when I create the same repository using gitea-mirror, the mirror repository does not appear to inherit the original repository description.

Would it be possible to synchronize the repository description as part of the mirror process?


3. Mobile Repository Card UI Improvements

I also have some UI suggestions for the repository cards on mobile devices.

Currently, most of the information in the repository card is concentrated on the left side, while there is a relatively large amount of unused space on the right side.

I think the layout could make better use of the available horizontal space.

Current Layout

The Custom tag takes up space around the repository information, while the synchronization status and other metadata are also mostly positioned on the left.

The result is roughly:

Image

Suggested Layout

I would suggest moving the Custom tag to the same row as the repository name, preferably near the top-right area.

Similarly, synchronization status tags such as:

  • Synced
  • Syncing
  • Failed

could be moved toward the right side of the card.

Image

Also looks good like this:

Image

This would make the card more balanced and use the available horizontal space more effectively.

I also noticed that the repository name row does not always appear to be perfectly horizontally aligned. It may be related to reserving space for the Custom tag.

Image

If possible, the repository name and related elements could be aligned consistently regardless of whether the Custom tag is present.


Thanks for the great work on gitea-mirror!

> [@MMMMMoris](https://github.com/MMMMMoris) Fixed in v3.27.1. The mobile cards had no menu at all, the options were only wired into the desktop table. Each card now has the same three dot menu: > > <img alt="Mobile repository card with the new three dot menu open, showing Mirror Options" width="320" src="https://gist.githubusercontent.com/arunavo4/7decfc7905cee7dba9af3df8f328ff13/raw/8c19f910fd49b4c9cc41f40cbb1087c96a19b108/shot-mobile-menu.png"> <img alt="Mirror options dialog on mobile" width="320" src="https://gist.githubusercontent.com/arunavo4/7decfc7905cee7dba9af3df8f328ff13/raw/8c19f910fd49b4c9cc41f40cbb1087c96a19b108/shot-mobile-dialog.png"> > > The Organizations page had the same gap in reverse, the desktop menu was missing the entry while mobile had it. Both are in v3.27.1, image is on ghcr now. Thanks for catching it so quickly. Yeah, it works on mobile now. I have some questions and suggestions regarding the current repository mirroring behavior and UI. ## 1. Releases and Tags Synchronization I have a question about how **Releases** and **Tags** are handled during mirroring. As far as I understand, a GitHub Release is associated with a Git tag. If the mirror option includes **Releases**, does that mean the corresponding tags must also be synchronized? More specifically: - Does enabling **Releases** also require synchronizing all tags? - Are Releases and Tags tightly coupled in the current mirroring implementation? - Is there currently any way to control how many Releases or Tags should be synchronized for each repository? - Could the number of Releases/Tags to synchronize be configurable on a per-repository basis? For example, some repositories have a very large number of historical releases and tags, while I may only be interested in the latest few releases. I am not very familiar with the internal synchronization mechanism between Releases and Tags, so I would also appreciate some clarification on how this currently works. If possible, it would be useful to have per-repository options such as: Synchronize Releases: Yes Maximum Releases: 10 Synchronize Tags: Yes Maximum Tags: 50 This could help significantly reduce unnecessary storage usage when mirroring repositories with a large amount of historical release data. --- ## 2. Repository Description Is Not Synchronized Another issue I noticed is that the **repository description does not seem to be synchronized** when creating a mirror through `gitea-mirror`. For comparison, Gitea's built-in repository mirroring functionality is able to synchronize the repository description. However, when I create the same repository using `gitea-mirror`, the mirror repository does not appear to inherit the original repository description. Would it be possible to synchronize the repository description as part of the mirror process? --- ## 3. Mobile Repository Card UI Improvements I also have some UI suggestions for the repository cards on mobile devices. Currently, most of the information in the repository card is concentrated on the **left side**, while there is a relatively large amount of unused space on the **right side**. I think the layout could make better use of the available horizontal space. ### Current Layout The `Custom` tag takes up space around the repository information, while the synchronization status and other metadata are also mostly positioned on the left. The result is roughly: <img width="417" height="649" alt="Image" src="https://github.com/user-attachments/assets/84730faf-e6e5-4833-8c71-20e1325e2b61" /> ### Suggested Layout I would suggest moving the `Custom` tag to the same row as the repository name, preferably near the top-right area. Similarly, synchronization status tags such as: - `Synced` - `Syncing` - `Failed` could be moved toward the right side of the card. <img width="722" height="456" alt="Image" src="https://github.com/user-attachments/assets/3d904031-1149-4ba4-999e-b765be792f55" /> Also looks good like this: <img width="726" height="495" alt="Image" src="https://github.com/user-attachments/assets/55b561a5-764d-482d-9e42-e3fc877b5752" /> This would make the card more balanced and use the available horizontal space more effectively. I also noticed that the repository name row does not always appear to be perfectly horizontally aligned. It may be related to reserving space for the `Custom` tag. <img width="417" height="316" alt="Image" src="https://github.com/user-attachments/assets/40f9996b-1ecb-4de8-ae90-0f1955c970c7" /> If possible, the repository name and related elements could be aligned consistently regardless of whether the `Custom` tag is present. --- Thanks for the great work on `gitea-mirror`! <!-- github-comment-id:5377981716 -->
Author
Owner

@MMMMMoris Thanks for all the suggestions I will work on it next week

@MMMMMoris Thanks for all the suggestions I will work on it next week <!-- github-comment-id:5381594559 -->
Author
Owner

@MMMMMoris All three are in #370, merged to main and part of the next release.

  1. Releases and tags. Tags are not something gitea-mirror syncs itself. Gitea's own git mirror pulls every ref, tags included, so they arrive with the code and cost nothing beyond the commits already in the clone. There is nothing to limit there. Releases are created through the Gitea API on top of those tags, and their assets are the real disk cost. The global "latest N releases" setting already existed (default 10, older ones get pruned from Gitea). It can now be overridden per repository and per organization: Mirror Options has a new "Release limit" field under Releases, empty means inherit.

  2. Description. It was only sent when the mirror was first created, and only from our local copy, so repos imported before that landed, or whose GitHub description changed later, never got one. Description and topics are now reconciled with GitHub on every sync. Existing mirrors pick it up on their next sync, no re-mirror needed.

  3. Mobile cards. Name, Custom badge and menu share one centred row, the other badges sit under the name, and status and last sync are on the right. The misaligned name row is gone.

Reworked mobile repository cards Mirror options dialog with the Release limit field

Thanks for the detailed writeup.

@MMMMMoris All three are in #370, merged to main and part of the next release. 1. Releases and tags. Tags are not something gitea-mirror syncs itself. Gitea's own git mirror pulls every ref, tags included, so they arrive with the code and cost nothing beyond the commits already in the clone. There is nothing to limit there. Releases are created through the Gitea API on top of those tags, and their assets are the real disk cost. The global "latest N releases" setting already existed (default 10, older ones get pruned from Gitea). It can now be overridden per repository and per organization: Mirror Options has a new "Release limit" field under Releases, empty means inherit. 2. Description. It was only sent when the mirror was first created, and only from our local copy, so repos imported before that landed, or whose GitHub description changed later, never got one. Description and topics are now reconciled with GitHub on every sync. Existing mirrors pick it up on their next sync, no re-mirror needed. 3. Mobile cards. Name, Custom badge and menu share one centred row, the other badges sit under the name, and status and last sync are on the right. The misaligned name row is gone. <img src="https://gist.githubusercontent.com/arunavo4/d044dc02b7cce2d565e8aa1efb032c8e/raw/cf4bcb494f28a0482b696cad399893cf6a74ae9b/mobile-cards.png" width="320" alt="Reworked mobile repository cards" /> <img src="https://gist.githubusercontent.com/arunavo4/d044dc02b7cce2d565e8aa1efb032c8e/raw/cf4bcb494f28a0482b696cad399893cf6a74ae9b/mobile-dialog.png" width="320" alt="Mirror options dialog with the Release limit field" /> Thanks for the detailed writeup. <!-- github-comment-id:5390444333 -->
Author
Owner

@MMMMMoris All three are in #370, merged to main and part of the next release.

  1. Releases and tags. Tags are not something gitea-mirror syncs itself. Gitea's own git mirror pulls every ref, tags included, so they arrive with the code and cost nothing beyond the commits already in the clone. There is nothing to limit there. Releases are created through the Gitea API on top of those tags, and their assets are the real disk cost. The global "latest N releases" setting already existed (default 10, older ones get pruned from Gitea). It can now be overridden per repository and per organization: Mirror Options has a new "Release limit" field under Releases, empty means inherit.
  2. Description. It was only sent when the mirror was first created, and only from our local copy, so repos imported before that landed, or whose GitHub description changed later, never got one. Description and topics are now reconciled with GitHub on every sync. Existing mirrors pick it up on their next sync, no re-mirror needed.
  3. Mobile cards. Name, Custom badge and menu share one centred row, the other badges sit under the name, and status and last sync are on the right. The misaligned name row is gone.

Reworked mobile repository cards Mirror options dialog with the Release limit field

Thanks for the detailed writeup.

What an efficient and quick fix! You have all my thanks. I love gitea-mirror!
I made a small donation to support the project. Thanks for your work!

> [@MMMMMoris](https://github.com/MMMMMoris) All three are in [#370](https://github.com/RayLabsHQ/gitea-mirror/pull/370), merged to main and part of the next release. > > 1. Releases and tags. Tags are not something gitea-mirror syncs itself. Gitea's own git mirror pulls every ref, tags included, so they arrive with the code and cost nothing beyond the commits already in the clone. There is nothing to limit there. Releases are created through the Gitea API on top of those tags, and their assets are the real disk cost. The global "latest N releases" setting already existed (default 10, older ones get pruned from Gitea). It can now be overridden per repository and per organization: Mirror Options has a new "Release limit" field under Releases, empty means inherit. > 2. Description. It was only sent when the mirror was first created, and only from our local copy, so repos imported before that landed, or whose GitHub description changed later, never got one. Description and topics are now reconciled with GitHub on every sync. Existing mirrors pick it up on their next sync, no re-mirror needed. > 3. Mobile cards. Name, Custom badge and menu share one centred row, the other badges sit under the name, and status and last sync are on the right. The misaligned name row is gone. > > <img alt="Reworked mobile repository cards" width="320" src="https://gist.githubusercontent.com/arunavo4/d044dc02b7cce2d565e8aa1efb032c8e/raw/cf4bcb494f28a0482b696cad399893cf6a74ae9b/mobile-cards.png"> <img alt="Mirror options dialog with the Release limit field" width="320" src="https://gist.githubusercontent.com/arunavo4/d044dc02b7cce2d565e8aa1efb032c8e/raw/cf4bcb494f28a0482b696cad399893cf6a74ae9b/mobile-dialog.png"> > > Thanks for the detailed writeup. What an efficient and quick fix! You have all my thanks. I love `gitea-mirror`! I made a small donation to support the project. Thanks for your work! <!-- github-comment-id:5392174574 -->
Author
Owner

@MMMMMoris Thanks for your support appreciate your kind gesture

@MMMMMoris Thanks for your support appreciate your kind gesture <!-- github-comment-id:5394477873 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/gitea-mirror#147