Repo cannot be forked. Fork hierarchies are limited to a maximum depth of 5
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Problem
Trying to create a fork fails with the following error:
<repo> cannot be forked. For performance reasons, fork hierarchies are limited to a maximum depth of 5 beneath a given root repository. Please create your fork from a repository higher up in the hierarchy, such as <repo-parent>.
Diagnosis
When forking repositories, there is a hierarchical limit to the number of times you can "fork a fork". Consider the following scenario:
- original-repo.git is created
- original-repo.git is forked to create fork-1.git
- fork-1.git is forked to create fork-2.git
- fork-2.git is forked to create fork-3.git
- fork-3.git is forked to create fork-4.git
- fork-4.git is forked to create fork-5.git
In the above scenario, if you attempt to fork fork-5.git you will be met with the following error:
Deleting the upstream repositories does not resolve the issue, because git alternates prevent referenced repositories from being removed on disk even if they are deleted from the UI.
Cause
Forks in Bitbucket Server rely on git alternates. Git alternates are basically a reference to another repository's objects. Using git alternates provides a few advantages to forks in Bitbucket Server:
- Forks consume very little additional disk space, as objects from the upstream repository are referenced, not duplicated
- Creating a new fork is nearly instantaneous because objects do not need to be duplicated on disk
- Objects can be automatically synced (fork syncing) from the upstream repository
When you have multiple layers of forks, then the outer-most fork is referencing objects in a parent repository, which is in turn referencing objects in its parent repository, and so on, creating a situation where your repository has to traverse "recursive alternates", following the git alternate references through multiple upstream repositories to retrieve the target object. Git itself places a hard-coded limit of 5 on recursive alternates and this limit can't be overridden.
Resolution
The recommended solution to prevent this issue occurring is to adapt your workflow to prevent creating so many layers of forks. When a forking workflow is used instead of a branching workflow, forks should ideally be made from "higher up" - e.g. from the original repo, or from a direct fork of the original.
When this is not possible there are two potential solutions:
- Repack the repository and remove the git alternate references
- Disable the use of git alternates in forks (not recommended)
Repack the repository
Repacking the repository will pull upstream alternates into the repository's own packs, so it no longer references git alternate objects and can be forked.
To repack the repository:
- Find the location of the repository on disk (this can be seen in the repo settings)
- Copy the repo to another location
- On the copy, perform the following steps:
Run
git fsck
and confirm there are no errors and that "Checking object directories" appears more than once:git fsck --no-dangling
Run
git repack
and confirm there are no errors:git repack -adf --depth=200 --window=200
Remove the
alternates
file from the repository:rm objects/info/alternates
Run
git fsck
again and confirm there are no errors, but this time check that "Checking object directories" only appears once:git fsck --no-dangling
- If all of the above steps succeed exactly as expected, then we can do this for real:
- Shut down Bitbucket Server
- Back up the repository
- Perform the steps 3.1 - 3.4 to repack the repository and remove git alternate references
- Start Bitbucket Server
Disable git alternates
Disabling git alternates means that forks will no longer be subject to the max depth of 5, however there are significant drawbacks:
- Forks will use much more disk space, with each fork consuming disk space equal to the size of the upstream repository
- Fork syncing (aka ref syncing) would stop working, even for existing forks
- Forks will take much longer to create, as instead of creating an empty repo with an alternates file that references the upstream repo, the entire repository must be duplicated on disk
For these reasons, this solution is not recommended.
To disable git alternates:
- Shut down Bitbucket Server
Add the following line to $BITBUCKET_HOME/shared/bitbucket.properties:
plugin.bitbucket-git.forks.usealternates=false
Start Bitbucket Server