From e1b13e9446bdbc8b06c44bddf09860000c22d7d7 Mon Sep 17 00:00:00 2001 From: Timo Date: Fri, 21 Aug 2026 00:05:08 +0200 Subject: [PATCH 1/3] fix: empty git repo bug Git 2.47.0 introduced a new feature which spawns a detached `git maintenance run` in the background. This can result in a problem because it creates a `maintenance.lock` file. The current IsEmpty implementation then interprets that incorrectly. One option is to disable this with the config `maintenance.auto=false` but I think it's more safe to just check if `.git` exists and contains at least one commit ref. But we should keep that feature in mind when using concurrency on the same repository! See also https://github.com/argoproj/argo-cd/issues/25101 --- internal/gitclient/gitclient.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/internal/gitclient/gitclient.go b/internal/gitclient/gitclient.go index b40032a..a0e5507 100644 --- a/internal/gitclient/gitclient.go +++ b/internal/gitclient/gitclient.go @@ -3,10 +3,9 @@ package gitclient import ( "bytes" "fmt" - "io/ioutil" "os" "os/exec" - "path" + "path/filepath" "repo/internal/say" "repo/internal/util" "strconv" @@ -24,7 +23,7 @@ func PrepareSsh(host string, sshUser string, sshPort int) { } func Clone(rootDir string, repoDir string, sshUrl string) error { - dirRepository := path.Join(rootDir, repoDir) + dirRepository := filepath.Join(rootDir, repoDir) cmdGo := exec.Command("git", "clone", sshUrl, dirRepository) if say.VerboseEnabled { cmdGo.Stdout = os.Stdout @@ -53,18 +52,18 @@ func GetLocalChanges(repoDir string) string { } func IsEmpty(repoDir string) bool { - fis, err := ioutil.ReadDir(path.Join(repoDir, ".git/objects")) - if err != nil { + gitDir := filepath.Join(repoDir, ".git") + if _, err := os.Stat(gitDir); os.IsNotExist(err) { return true } - for _, fi := range fis { - if !fi.IsDir() { - return true - } + + refsHeads := filepath.Join(gitDir, "refs", "heads") + entries, err := os.ReadDir(refsHeads) + if err != nil { + return true } - return false - //o, _, _ := util.RunCommandDir(&repoDir, "find", ".git/objects", "-type", "f") - //return len(o) == 0 + + return len(entries) == 0 } func GetCurrentBranch(repoDir string) string { From f22eb6f55d1e0bac3133165891e97d07d413e730 Mon Sep 17 00:00:00 2001 From: Timo Date: Fri, 21 Aug 2026 00:05:37 +0200 Subject: [PATCH 2/3] fix: use the filepath pkg, not URL path --- internal/cmd/cleanup.go | 5 ++--- internal/cmd/clone.go | 6 +++--- internal/cmd/common.go | 7 +++---- internal/model/repo.go | 4 ++-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/internal/cmd/cleanup.go b/internal/cmd/cleanup.go index b46bdf4..7dfbf66 100644 --- a/internal/cmd/cleanup.go +++ b/internal/cmd/cleanup.go @@ -3,7 +3,6 @@ package cmd import ( "errors" "os" - "path" "path/filepath" "repo/internal/config" h "repo/internal/hoster" @@ -129,8 +128,8 @@ func processDir(dirReposRoot string, hoster h.Hoster, counter *int32, total int, func move(dirReposRoot string, dirRepository string, dirTarget string) error { dirRepoRelative := getRelativRepoDir(dirRepository, dirReposRoot) dirAbsSource := dirRepository - dirAbsTarget := path.Join(dirReposRoot, dirTarget) - dirAbsTargetRepository := path.Join(dirReposRoot, dirTarget, dirRepoRelative) + dirAbsTarget := filepath.Join(dirReposRoot, dirTarget) + dirAbsTargetRepository := filepath.Join(dirReposRoot, dirTarget, dirRepoRelative) // check & prepare target // create if not exists diff --git a/internal/cmd/clone.go b/internal/cmd/clone.go index d1ecddd..f9811d5 100644 --- a/internal/cmd/clone.go +++ b/internal/cmd/clone.go @@ -2,7 +2,7 @@ package cmd import ( "os" - "path" + "path/filepath" "repo/internal/config" "repo/internal/gitclient" h "repo/internal/hoster" @@ -67,9 +67,9 @@ func filterExisting(dirReposRoot string, repos []h.HosterRepository) (result []h var dirRepository string switch config.Values.Options.Style { case config.StyleFlat: - dirRepository = path.Join(dirReposRoot, r.Path) + dirRepository = filepath.Join(dirReposRoot, r.Path) case config.StyleRecursive: - dirRepository = path.Join(dirReposRoot, r.PathWithNamespace) + dirRepository = filepath.Join(dirReposRoot, r.PathWithNamespace) } _, err := os.Stat(dirRepository) diff --git a/internal/cmd/common.go b/internal/cmd/common.go index 6eeb663..b7dbba4 100644 --- a/internal/cmd/common.go +++ b/internal/cmd/common.go @@ -5,7 +5,6 @@ import ( "io/fs" "math" "os" - "path" "path/filepath" h "repo/internal/hoster" "repo/internal/model" @@ -63,7 +62,7 @@ func validateArgGitDir(argIndex int, repoParent bool, repoRoot bool) cobra.Posit if !util.ExistsDir(repoPath) { return errors.New(msg + " (directory does not exist)") } - condParent := repoParent && util.ExistsDir(path.Join(repoPath, ".git")) + condParent := repoParent && util.ExistsDir(filepath.Join(repoPath, ".git")) condRoot := repoRoot if !condParent && !condRoot { @@ -77,7 +76,7 @@ func validateArgGitDir(argIndex int, repoParent bool, repoRoot bool) cobra.Posit // collect them and return the array func collectGitDirs(root string, hoster h.Hoster) (result []model.RepoDir, err error) { - ignored := []string{path.Join(root, dirArchived), path.Join(root, dirRemoved)} + ignored := []string{filepath.Join(root, dirArchived), filepath.Join(root, dirRemoved)} walk := func(dir string, d fs.DirEntry, e error) error { if !d.IsDir() { @@ -88,7 +87,7 @@ func collectGitDirs(root string, hoster h.Hoster) (result []model.RepoDir, err e return fs.SkipDir } - if util.ExistsDir(path.Join(dir, ".git")) { // check if given path is git-repository + if util.ExistsDir(filepath.Join(dir, ".git")) { // check if given path is git-repository repo, err := model.MakeRepoDir(dir, hoster.Host()) if err != nil { say.Verbose("Failed determine repository directory: %s", e) diff --git a/internal/model/repo.go b/internal/model/repo.go index 49eead2..b78183d 100644 --- a/internal/model/repo.go +++ b/internal/model/repo.go @@ -4,7 +4,7 @@ import ( "bytes" "os" "os/exec" - "path" + "path/filepath" "regexp" "repo/internal/say" "repo/internal/util" @@ -30,7 +30,7 @@ type RepoRemote struct { } func (rd RepoDir) RepoYamlFilename() string { - return path.Join(rd.Path, RepoYamlFilename) + return filepath.Join(rd.Path, RepoYamlFilename) } func (rd RepoDir) PathDirName() string { From 76560c31d72326202a50dbe2746c1b8c0d1611e9 Mon Sep 17 00:00:00 2001 From: Timo Date: Fri, 21 Aug 2026 00:21:45 +0200 Subject: [PATCH 3/3] docs: Changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52b4477..715edec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Shorter apply output, json dump available on verbose * Rounded execution times +### Fixed + +* Fix `Empty git repository` bug +* Fix wrong used `path` import for file paths + ## [0.4.3] - 2026-07-30 ### Changed