Skip to content

Commit 1841e10

Browse files
authored
Merge pull request #4674 from flipt-io/feat/git-init-existing-features
feat: support Git repository initialization for existing features files
2 parents 2100e42 + f405dc2 commit 1841e10

File tree

2 files changed

+374
-4
lines changed

2 files changed

+374
-4
lines changed

internal/storage/git/repository.go

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"maps"
77
"os"
8+
"path/filepath"
89
"slices"
910
"strings"
1011
"sync"
@@ -44,6 +45,7 @@ type Repository struct {
4445
sigEmail string
4546
signer signing.Signer
4647
maxOpenDescriptors int
48+
isNormalRepo bool // true if opened with PlainOpen, false if bare repository
4749

4850
subs []Subscriber
4951

@@ -137,10 +139,42 @@ func newRepository(ctx context.Context, logger *zap.Logger, opts ...containers.O
137139
return nil, empty, err
138140
}
139141
} else {
140-
// opened successfully and there is contents so we assume not empty
141-
r.Repository, err = git.Open(storage, nil)
142-
if err != nil {
143-
return nil, empty, err
142+
// Directory has content - check if it has a .git subdirectory (normal repo) or bare repo files
143+
gitDir := filepath.Join(r.localPath, ".git")
144+
if _, err := os.Stat(gitDir); err == nil {
145+
// .git subdirectory exists - this is a normal Git repository
146+
r.Repository, err = git.PlainOpen(r.localPath)
147+
if err != nil {
148+
return nil, empty, fmt.Errorf("opening normal git repository: %w", err)
149+
}
150+
r.isNormalRepo = true
151+
152+
// Check if repository has commits
153+
head, err := r.Repository.Head()
154+
if err != nil && errors.Is(err, plumbing.ErrReferenceNotFound) {
155+
empty = true
156+
} else {
157+
empty = false
158+
159+
// For normal repositories, ensure remote tracking reference exists
160+
// This is needed for Flipt's branch management to work correctly
161+
remoteRef := plumbing.NewReferenceFromStrings("refs/remotes/origin/"+r.defaultBranch, head.Hash().String())
162+
if err := r.Repository.Storer.SetReference(remoteRef); err != nil {
163+
return nil, empty, fmt.Errorf("setting remote tracking reference: %w", err)
164+
}
165+
}
166+
} else {
167+
// No .git subdirectory - try to open as bare repository or create one
168+
r.Repository, err = git.Open(storage, nil)
169+
if err != nil {
170+
// No repository exists, initialize new bare repository
171+
r.Repository, err = git.Init(storage, git.WithDefaultBranch(plumbing.NewBranchReferenceName(r.defaultBranch)))
172+
if err != nil {
173+
return nil, empty, err
174+
}
175+
// Directory has content but no Git repo - mark as empty to commit existing files
176+
empty = true
177+
}
144178
}
145179
}
146180
}
@@ -474,6 +508,16 @@ func (r *Repository) UpdateAndPush(
474508

475509
r.logger.Debug("commit created successfully", zap.Stringer("hash", commit.Hash))
476510

511+
// For normal repositories, update working directory to match the new commit
512+
if r.isNormalRepo && r.localPath != "" {
513+
if err := r.updateWorkingDirectory(ctx, commit.Hash); err != nil {
514+
r.logger.Warn("failed to update working directory after commit",
515+
zap.Stringer("commit", commit.Hash),
516+
zap.Error(err))
517+
// Don't return error as commit was successful, just log warning
518+
}
519+
}
520+
477521
if r.remote != nil {
478522
local := plumbing.NewBranchReferenceName(branch)
479523
r.logger.Debug("setting local reference",
@@ -677,6 +721,31 @@ func (r *Repository) newFilesystem(hash plumbing.Hash) (_ *filesystem, err error
677721
)
678722
}
679723

724+
// updateWorkingDirectory updates the working directory files to match the given commit
725+
func (r *Repository) updateWorkingDirectory(_ context.Context, commitHash plumbing.Hash) error {
726+
if !r.isNormalRepo {
727+
return nil // Only needed for normal repositories
728+
}
729+
730+
// Get the worktree to update working directory
731+
worktree, err := r.Repository.Worktree()
732+
if err != nil {
733+
return fmt.Errorf("getting worktree: %w", err)
734+
}
735+
736+
// Checkout the commit to update working directory files
737+
err = worktree.Checkout(&git.CheckoutOptions{
738+
Hash: commitHash,
739+
})
740+
if err != nil {
741+
return fmt.Errorf("checking out commit %s: %w", commitHash.String(), err)
742+
}
743+
744+
r.logger.Debug("updated working directory to match commit",
745+
zap.Stringer("commit", commitHash))
746+
return nil
747+
}
748+
680749
func WithRemote(name, url string) containers.Option[Repository] {
681750
return func(r *Repository) {
682751
r.remote = &config.RemoteConfig{

0 commit comments

Comments
 (0)