Skip to content

Commit 2aaecde

Browse files
committed
fix: recover when there is unreleased lock file
If a previous git invocation crashes, it is possible that an orphaned lock file (e.g. shallow.lock) is left on the filesystem. This previously caused git-sync to crash loop because the lock file is never deleted. This change adds a check in sanityCheckRepo for the existence of a git lock file. If the git lock file exists at this stage, then initRepo will re-initialize the repository.
1 parent f73ee00 commit 2aaecde

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

main.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,19 @@ func (git *repoSync) removeStaleWorktrees() (int, error) {
12271227
return count, nil
12281228
}
12291229

1230+
func hasGitLockFile(gitRoot absPath) (bool, error) {
1231+
gitLockFiles := []string{"shallow.lock"}
1232+
for _, lockFile := range gitLockFiles {
1233+
_, err := os.Stat(gitRoot.Join(".git", lockFile).String())
1234+
if err == nil {
1235+
return true, nil
1236+
} else if !errors.Is(err, os.ErrNotExist) {
1237+
return false, err
1238+
}
1239+
}
1240+
return false, nil
1241+
}
1242+
12301243
// sanityCheckRepo tries to make sure that the repo dir is a valid git repository.
12311244
func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
12321245
git.log.V(3).Info("sanity-checking git repo", "repo", git.root)
@@ -1258,6 +1271,16 @@ func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
12581271
return false
12591272
}
12601273

1274+
// Check if the repository contains an unreleased lock file. This can happen if
1275+
// a previous git invocation crashed.
1276+
if hasLock, err := hasGitLockFile(git.root); err != nil {
1277+
git.log.Error(err, "error calling stat on file", "path", git.root)
1278+
return false
1279+
} else if hasLock {
1280+
git.log.Error(nil, "repo contains lock file", "path", git.root)
1281+
return false
1282+
}
1283+
12611284
return true
12621285
}
12631286

main_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,3 +424,42 @@ func TestTouch(t *testing.T) {
424424
t.Errorf("touch(newfile) mtime %v is not after %v", newfileInfo.ModTime(), stamp)
425425
}
426426
}
427+
428+
func TestHasGitLockFile(t *testing.T) {
429+
testCases := map[string]struct {
430+
inputFilePath []string
431+
expectLockFile bool
432+
}{
433+
"missing .git directory": {
434+
expectLockFile: false,
435+
},
436+
"has git directory but no lock files": {
437+
inputFilePath: []string{".git", "HEAD"},
438+
expectLockFile: false,
439+
},
440+
"shallow.lock file": {
441+
inputFilePath: []string{".git", "shallow.lock"},
442+
expectLockFile: true,
443+
},
444+
}
445+
446+
for name, tc := range testCases {
447+
t.Run(name, func(t *testing.T) {
448+
root := absPath(t.TempDir())
449+
450+
if len(tc.inputFilePath) > 0 {
451+
if err := touch(root.Join(tc.inputFilePath...)); err != nil {
452+
t.Fatal(err)
453+
}
454+
}
455+
456+
hasLock, err := hasGitLockFile(root)
457+
if err != nil {
458+
t.Fatal(err)
459+
}
460+
if hasLock != tc.expectLockFile {
461+
t.Fatalf("expected hasGitLockFile to return %v, but got %v", tc.expectLockFile, hasLock)
462+
}
463+
})
464+
}
465+
}

0 commit comments

Comments
 (0)