@@ -2,7 +2,9 @@ package worktree
22
33import (
44 "os"
5+ "os/exec"
56 "path/filepath"
7+ "strings"
68 "testing"
79 "time"
810)
@@ -202,8 +204,6 @@ func TestEntryProtected(t *testing.T) {
202204}
203205
204206func TestIsMainWorktree (t * testing.T ) {
205- t .Parallel ()
206-
207207 root := t .TempDir ()
208208 mainPath := filepath .Join (root , "main" )
209209 separateMainPath := filepath .Join (root , "separate-main" )
@@ -224,6 +224,12 @@ func TestIsMainWorktree(t *testing.T) {
224224 if err := os .MkdirAll (linkedGitDir , 0o750 ); err != nil {
225225 t .Fatalf ("mkdir linked gitdir: %v" , err )
226226 }
227+ if err := os .WriteFile (filepath .Join (separateGitDir , "HEAD" ), []byte ("ref: refs/heads/main\n " ), 0o600 ); err != nil {
228+ t .Fatalf ("write separate gitdir HEAD: %v" , err )
229+ }
230+ if err := os .WriteFile (filepath .Join (separateGitDir , "config" ), []byte ("[core]\n " ), 0o600 ); err != nil {
231+ t .Fatalf ("write separate gitdir config: %v" , err )
232+ }
227233 if err := os .WriteFile (filepath .Join (separateMainPath , ".git" ), []byte ("gitdir: " + separateGitDir + "\n " ), 0o600 ); err != nil {
228234 t .Fatalf ("write separate main .git file: %v" , err )
229235 }
@@ -237,10 +243,89 @@ func TestIsMainWorktree(t *testing.T) {
237243 if ! isMainWorktree (separateMainPath ) {
238244 t .Fatalf ("expected %q with separate git dir to be detected as the main worktree" , separateMainPath )
239245 }
246+ if ! isMainWorktree (separateGitDir ) {
247+ t .Fatalf ("expected %q gitdir path to be detected as the main worktree entry" , separateGitDir )
248+ }
240249 if isMainWorktree (linkedPath ) {
241250 t .Fatalf ("expected %q to be detected as a linked worktree" , linkedPath )
242251 }
243252 if isMainWorktree (missingPath ) {
244253 t .Fatalf ("expected %q without .git metadata to be non-main" , missingPath )
245254 }
246255}
256+
257+ func TestListProtectsSeparateGitDirMainWorktree (t * testing.T ) {
258+ root := t .TempDir ()
259+ mainPath := filepath .Join (root , "main" )
260+ gitDir := filepath .Join (root , "repo.git" )
261+ linkedPath := filepath .Join (root , "feature" )
262+
263+ runGit (t , root , "init" , "-b" , "main" , "--separate-git-dir" , gitDir , mainPath )
264+ runGit (t , mainPath , "config" , "user.name" , "Test User" )
265+ runGit (t , mainPath , "config" , "user.email" , "test@example.com" )
266+
267+ if err := os .WriteFile (filepath .Join (mainPath , "README.md" ), []byte ("hello\n " ), 0o600 ); err != nil {
268+ t .Fatalf ("write README.md: %v" , err )
269+ }
270+ runGit (t , mainPath , "add" , "README.md" )
271+ runGit (t , mainPath , "commit" , "-m" , "initial commit" )
272+ runGit (t , mainPath , "worktree" , "add" , "-b" , "feature" , linkedPath , "HEAD" )
273+
274+ t .Chdir (mainPath )
275+
276+ entries , err := List ()
277+ if err != nil {
278+ t .Fatalf ("List(): %v" , err )
279+ }
280+
281+ var mainEntry * Entry
282+ var linkedEntry * Entry
283+ for i := range entries {
284+ e := & entries [i ]
285+ switch {
286+ case e .IsMain :
287+ mainEntry = e
288+ case samePath (e .Path , linkedPath ):
289+ linkedEntry = e
290+ }
291+ }
292+
293+ if mainEntry == nil {
294+ t .Fatalf ("expected a main worktree entry, got %+v" , entries )
295+ }
296+ if ! samePath (mainEntry .Path , gitDir ) {
297+ t .Fatalf ("expected main entry path %q from git porcelain, got %q" , gitDir , mainEntry .Path )
298+ }
299+ if ! mainEntry .IsCurrent {
300+ t .Fatalf ("expected separate-git-dir main entry to be current: %+v" , * mainEntry )
301+ }
302+ if ! mainEntry .Protected () {
303+ t .Fatalf ("expected separate-git-dir main entry to be protected: %+v" , * mainEntry )
304+ }
305+ merged := map [string ]bool {mainEntry .Branch : true }
306+ if shouldCleanEntry (* mainEntry , merged ) {
307+ t .Fatalf ("expected main entry to be skipped by clean: %+v" , * mainEntry )
308+ }
309+ if shouldNukeEntry (* mainEntry ) {
310+ t .Fatalf ("expected main entry to be skipped by nuke: %+v" , * mainEntry )
311+ }
312+
313+ if linkedEntry == nil {
314+ t .Fatalf ("expected linked worktree entry, got %+v" , entries )
315+ }
316+ if linkedEntry .IsMain {
317+ t .Fatalf ("expected linked entry to remain non-main: %+v" , * linkedEntry )
318+ }
319+ }
320+
321+ func runGit (t * testing.T , dir string , args ... string ) string {
322+ t .Helper ()
323+
324+ cmd := exec .Command ("git" , args ... )
325+ cmd .Dir = dir
326+ out , err := cmd .CombinedOutput ()
327+ if err != nil {
328+ t .Fatalf ("git %s (dir=%s): %v\n %s" , strings .Join (args , " " ), dir , err , out )
329+ }
330+ return strings .TrimSpace (string (out ))
331+ }
0 commit comments