@@ -21,6 +21,9 @@ import (
2121 cliproxyauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
2222)
2323
24+ // gcInterval defines minimum time between garbage collection runs.
25+ const gcInterval = 5 * time .Minute
26+
2427// GitTokenStore persists token records and auth metadata using git as the backing storage.
2528type GitTokenStore struct {
2629 mu sync.Mutex
@@ -31,6 +34,7 @@ type GitTokenStore struct {
3134 remote string
3235 username string
3336 password string
37+ lastGC time.Time
3438}
3539
3640// NewGitTokenStore creates a token store that saves credentials to disk through the
@@ -613,6 +617,7 @@ func (s *GitTokenStore) commitAndPushLocked(message string, relPaths ...string)
613617 } else if errRewrite := s .rewriteHeadAsSingleCommit (repo , headRef .Name (), commitHash , message , signature ); errRewrite != nil {
614618 return errRewrite
615619 }
620+ s .maybeRunGC (repo )
616621 if err = repo .Push (& git.PushOptions {Auth : s .gitAuth (), Force : true }); err != nil {
617622 if errors .Is (err , git .NoErrAlreadyUpToDate ) {
618623 return nil
@@ -652,6 +657,23 @@ func (s *GitTokenStore) rewriteHeadAsSingleCommit(repo *git.Repository, branch p
652657 return nil
653658}
654659
660+ func (s * GitTokenStore ) maybeRunGC (repo * git.Repository ) {
661+ now := time .Now ()
662+ if now .Sub (s .lastGC ) < gcInterval {
663+ return
664+ }
665+ s .lastGC = now
666+
667+ pruneOpts := git.PruneOptions {
668+ OnlyObjectsOlderThan : now ,
669+ Handler : repo .DeleteObject ,
670+ }
671+ if err := repo .Prune (pruneOpts ); err != nil && ! errors .Is (err , git .ErrLooseObjectsNotSupported ) {
672+ return
673+ }
674+ _ = repo .RepackObjects (& git.RepackConfig {})
675+ }
676+
655677// PersistConfig commits and pushes configuration changes to git.
656678func (s * GitTokenStore ) PersistConfig (_ context.Context ) error {
657679 if err := s .EnsureRepository (); err != nil {
0 commit comments