diff --git a/internal/store/gitstore.go b/internal/store/gitstore.go index 86bdd561..93354527 100644 --- a/internal/store/gitstore.go +++ b/internal/store/gitstore.go @@ -858,7 +858,6 @@ func (s *GitTokenStore) commitAndPushLocked(message string, relPaths ...string) } else if errRewrite := s.rewriteHeadAsSingleCommit(repo, headRef.Name(), commitHash, message, signature); errRewrite != nil { return errRewrite } - s.maybeRunGC(repo) pushOpts := &git.PushOptions{Auth: s.gitAuth(), Force: true} if s.branch != "" { pushOpts.RefSpecs = []config.RefSpec{config.RefSpec("refs/heads/" + s.branch + ":refs/heads/" + s.branch)} @@ -874,6 +873,7 @@ func (s *GitTokenStore) commitAndPushLocked(message string, relPaths ...string) } return fmt.Errorf("git token store: push: %w", err) } + s.maybeRunGC(repoDir) return nil } @@ -907,13 +907,18 @@ func (s *GitTokenStore) rewriteHeadAsSingleCommit(repo *git.Repository, branch p return nil } -func (s *GitTokenStore) maybeRunGC(repo *git.Repository) { +func (s *GitTokenStore) maybeRunGC(repoDir string) { now := time.Now() if now.Sub(s.lastGC) < gcInterval { return } s.lastGC = now + repo, err := git.PlainOpen(repoDir) + if err != nil { + return + } + pruneOpts := git.PruneOptions{ OnlyObjectsOlderThan: now, Handler: repo.DeleteObject, diff --git a/internal/store/gitstore_test.go b/internal/store/gitstore_test.go index c5e99039..bdb2ccc5 100644 --- a/internal/store/gitstore_test.go +++ b/internal/store/gitstore_test.go @@ -239,6 +239,40 @@ func TestEnsureRepositoryResetsToRemoteDefaultWhenBranchUnset(t *testing.T) { assertRemoteBranchContents(t, remoteDir, "master", "local master update\n") } +func TestCommitAndPushLockedPushesBeforeRunningGC(t *testing.T) { + root := t.TempDir() + remoteDir := setupGitRemoteRepository(t, root, "master", + testBranchSpec{name: "master", contents: "remote master branch\n"}, + ) + + store := NewGitTokenStore(remoteDir, "", "", "") + store.SetBaseDir(filepath.Join(root, "workspace", "auths")) + if err := store.EnsureRepository(); err != nil { + t.Fatalf("EnsureRepository: %v", err) + } + + workspaceDir := filepath.Join(root, "workspace") + updates := []string{ + "local master update one\n", + "local master update two\n", + } + for _, contents := range updates { + if err := os.WriteFile(filepath.Join(workspaceDir, "branch.txt"), []byte(contents), 0o600); err != nil { + t.Fatalf("write local master marker: %v", err) + } + + store.lastGC = time.Now().Add(-gcInterval) + store.mu.Lock() + err := store.commitAndPushLocked("Update master marker", "branch.txt") + store.mu.Unlock() + if err != nil { + t.Fatalf("commitAndPushLocked with forced GC: %v", err) + } + + assertRemoteBranchContents(t, remoteDir, "master", contents) + } +} + func TestEnsureRepositoryFollowsRenamedRemoteDefaultBranchWhenAvailable(t *testing.T) { root := t.TempDir() remoteDir := setupGitRemoteRepository(t, root, "master",