This documentation is for a Forgejo version which is not yet released.
To read the documentation for the released version of Forgejo, navigate to the latest version.
Garbage Collection
Git repositories can accumulate commits which are no longer accessible through any existing reference, such as a branch or a tag. This is normal in Git operations. As an example, if a branch has a git rebase operation applied to it followed by a git push --force, then the original commits will remain in the repository but they are not referenced by the branch anymore.
Git provides a command-line tool called git gc which performs maintenance on a repository, including removing commits that are no longer referenced (either directly, or by being a parent of a referenced commit). The git gc command can only be run against local repositories, so integration with Forgejo is required in order to perform maintenance on Forgejo’s repositories.
Performing Garbage Collection
Automatic Maintenance
Forgejo provides a cron job to perform a git gc against all the server-side repositories, which can be configured in the [cron.git_gc_repos] section of the app.ini file.
By default, this cron job is disabled. To enable it, add to your app.ini file:
[cron.git_gc_repos]
ENABLED = true
Manual Maintenance
Admin UI
In your Forgejo instance, access the “Site administration” page (/admin). A set of common maintenance operations is displayed, which includes “Garbage collect all repositories”. Select the “Run” option to begin a garbage collection operation on every Git repository in the Forgejo instance.
Command-line
Forgejo administrators can perform garbage collection on individual repositories by using the git gc command. Access the repositories by finding them in the [repository].ROOT directory, and run git gc. It is safe to run while Forgejo is online.
$ cd data/forgejo-repositories/owner/repo.git
$ git gc
Enumerating objects: 16005, done.
Counting objects: 100% (16005/16005), done.
Delta compression using up to 32 threads
Compressing objects: 100% (10423/10423), done.
Writing objects: 100% (16005/16005), done.
Selecting bitmap commits: 2045, done.
Building bitmaps: 100% (125/125), done.
Total 16005 (delta 4459), reused 15987 (delta 4447), pack-reused 0 (from 0)
Enumerating cruft objects: 347, done.
Traversing cruft objects: 415, done.
Counting objects: 100% (347/347), done.
Delta compression using up to 32 threads
Compressing objects: 100% (263/263), done.
Writing objects: 100% (347/347), done.
Total 347 (delta 208), reused 0 (delta 0), pack-reused 0 (from 0)
Forgejo and Git Internal References
In order to prevent commits from being subject to garbage collection when they are still accessible through Forgejo’s user interface, Forgejo maintains automatic Git references within the base repository of a pull request.
The current head of a pull request is available within the base repository as refs/pull/N/head, where N is the index of the pull request. As new commits are added to a pull request by modifying the branch, or by using the AGit pull request workflow, this reference is updated to the latest commit.
As of Forgejo v18, whenever an open pull request receives a force-push, Forgejo creates two references in the git repository: refs/pr-force-push/N/comment/M/old and refs/pr-force-push/N/comment/M/new, where N is the index of the pull request, and M is the internal ID of a special ”git gc operation. Force push references can be disabled server-wide by setting the [repository.pull-request].KEEP_FORCE_PUSH_REFS setting to false.
Removing Unwanted Commits
If a commit is pushed to Forgejo in error and contains sensitive information, it is not sufficient to correct and force-push a new commit. The original commit will remain until all references to it are removed from the Git repository, and a git gc operation removes the commit.
If the commit contained sensitive information such as secrets or credentials, assume that the information is compromised. Removing the commit from the Git repository does not guarantee that it was not fetched into another repository, or mirrored to another repository. Rotate affected credentials immediately.
If the unwanted commit was pushed to a fork with an open pull request, then Forgejo will automatically push the commit to the base repository. In this case, both the fork repository and the base repository will contain the commit, and both need to be subjected to the following process.
Assuming the commit ID is $C, an administrator can run these commands against the repository located in [repository].ROOT in order to find all the references and remove them:
git branch --contains $Cwill list all the branches that contain the commit, either directly, or as an ancestor to the current branch head.git branch -D <branch>would remove the branch<branch>.- If the commit is an ancestor of the branch head, this may not be appropriate as you’d be removing unrelated work. In this case, the branch should be rebased to remove the ancestor, and force pushed.
git tag --contains $Cwill list all the tags that contain the commit, either directly, or as an ancestor to the tagged commit.git tag -d <tag>would remove the tag<tag>.
git log -g --all --oneline | grep ${C:0:7}would list any entries in the git reflog that point to the commit. The output would have the commit short ID, followed by the reflog entry (e.g.refs/heads/some-branch@{3}, indicating that it is where the branchsome-branchwas 3 updates ago).git reflog delete --rewrite refs/heads/some-branch@{3}would remove the specific entrysome-branch@{3}from the reflog.git reflog expire --expire=now --expire-unreachable=now --allwould remove all entries in the reflog, which is typically safe to perform on a Forgejo server-side repository. It prevents using the reflog to rescue any lost commit on the server, but this is an incredibly rare need.
git for-each-ref --contains $Cwould list any other reference to the commit.git update-ref -d <full-refname>would remove that reference.- If the reference is
refs/pull/N/head, then it is the current head of a pull request with the indexNin this repository. Delete the pull request or rebase the pull request instead of removing this reference. Deleting this reference will break Forgejo’s pull request handling. - If the reference is
refs/pr-force-push/N/comment/M/{old/new}, an internal referenced created by Forgejo, then removing the commit will prevent users from comparing the force-push history of a pull request. The “Compare” button will disappear.
Following cleanup of any references, the offending commit can be removed by git gc. By default, git gc will keep any unreachable objects in the repository if they are less than 2 weeks old, with the reasoning that a Git operation may be in-progress at any time which would write objects and then associate them with a new reference. This can be bypassed by running git gc --prune=now. Using --prune=now may cause in-progress writes to the repository to fail, and could lead to Git repository corruption. It is recommended that --prune=now only be used when Forgejo is offline.