|
5 | 5 | "fmt"
|
6 | 6 | "maps"
|
7 | 7 | "os"
|
| 8 | + "path/filepath" |
8 | 9 | "slices"
|
9 | 10 | "strings"
|
10 | 11 | "sync"
|
@@ -44,6 +45,7 @@ type Repository struct {
|
44 | 45 | sigEmail string
|
45 | 46 | signer signing.Signer
|
46 | 47 | maxOpenDescriptors int
|
| 48 | + isNormalRepo bool // true if opened with PlainOpen, false if bare repository |
47 | 49 |
|
48 | 50 | subs []Subscriber
|
49 | 51 |
|
@@ -137,10 +139,42 @@ func newRepository(ctx context.Context, logger *zap.Logger, opts ...containers.O
|
137 | 139 | return nil, empty, err
|
138 | 140 | }
|
139 | 141 | } 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 | + } |
144 | 178 | }
|
145 | 179 | }
|
146 | 180 | }
|
@@ -474,6 +508,16 @@ func (r *Repository) UpdateAndPush(
|
474 | 508 |
|
475 | 509 | r.logger.Debug("commit created successfully", zap.Stringer("hash", commit.Hash))
|
476 | 510 |
|
| 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 | + |
477 | 521 | if r.remote != nil {
|
478 | 522 | local := plumbing.NewBranchReferenceName(branch)
|
479 | 523 | r.logger.Debug("setting local reference",
|
@@ -677,6 +721,31 @@ func (r *Repository) newFilesystem(hash plumbing.Hash) (_ *filesystem, err error
|
677 | 721 | )
|
678 | 722 | }
|
679 | 723 |
|
| 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 | + |
680 | 749 | func WithRemote(name, url string) containers.Option[Repository] {
|
681 | 750 | return func(r *Repository) {
|
682 | 751 | r.remote = &config.RemoteConfig{
|
|
0 commit comments