Skip to content

Commit 508090e

Browse files
authored
[0.15] fix incorrect worktree usage, release 0.15.1 (#714)
In #696, internal/git learned about worktres, but the code that "opens" a worktree was using the wrong Git directory when constructing the `Repository` object and `Worktree` objects. This resulted in many operations, primarily `restack` operating on the incorrect worktree.
1 parent 3c4a7c9 commit 508090e

File tree

5 files changed

+118
-2
lines changed

5 files changed

+118
-2
lines changed

.changes/v0.15.1.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## <a name="v0.15.1">v0.15.1</a> - 2025-06-25
2+
### Fixed
3+
- Fix several operations using the incorrect Git worktree when invoked from the non-primary worktree.

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
66
and is generated by [Changie](https://github.com/miniscruff/changie).
77

8+
## <a name="v0.15.1">v0.15.1</a> - 2025-06-25
9+
### Fixed
10+
- Fix several operations using the incorrect Git worktree when invoked from the non-primary worktree.
11+
812
## <a name="v0.15.0">v0.15.0</a> - 2025-06-23
913
### Added
1014
- log short: Add `spice.logShort.crFormat` configuration option. This takes precedence over `spice.log.crFormat` for `gs log short`/`gs ls`.

internal/git/repo.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,12 @@ func OpenWorktree(ctx context.Context, dir string, opts OpenOptions) (*Worktree,
9191
if !ok {
9292
return nil, fmt.Errorf("unexpected output from git rev-parse: %q", out)
9393
}
94-
gitDir, repoGitDir, ok := strings.Cut(out, "\n")
94+
gitCommonDir, gitDir, ok := strings.Cut(out, "\n")
9595
if !ok {
9696
return nil, fmt.Errorf("unexpected output from git rev-parse: %q", out)
9797
}
9898

99-
repo := newRepository(repoGitDir, opts.Log, opts.exec)
99+
repo := newRepository(gitCommonDir, opts.Log, opts.exec)
100100
wt := newWorktree(gitDir, rootDir, repo, opts.Log, opts.exec)
101101
return wt, nil
102102
}

internal/git/repo_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import (
77
"testing"
88

99
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
"go.abhg.dev/gs/internal/git/gittest"
1012
"go.abhg.dev/gs/internal/silog/silogtest"
13+
"go.abhg.dev/gs/internal/text"
1114
)
1215

1316
func NewFakeRepository(t testing.TB, dir string, execer execer) (*Repository, *Worktree) {
@@ -26,6 +29,50 @@ func NewFakeRepository(t testing.TB, dir string, execer execer) (*Repository, *W
2629
return repo, wt
2730
}
2831

32+
func TestOpenWorktree_correctGitDirectory(t *testing.T) {
33+
// This test verifies the fix for the worktree bug where OpenWorktree
34+
// was using the wrong git directory when constructing Repository objects.
35+
t.Parallel()
36+
37+
fixture, err := gittest.LoadFixtureScript([]byte(text.Dedent(`
38+
as 'Test <[email protected]>'
39+
at '2025-06-26T21:28:29Z'
40+
41+
mkdir repo
42+
cd repo
43+
git init
44+
git add main.txt
45+
git commit -m 'Initial commit'
46+
47+
# Create a worktree
48+
git worktree add ../worktree -b feature
49+
50+
-- repo/main.txt --
51+
main content
52+
`)))
53+
require.NoError(t, err)
54+
dir := fixture.Dir()
55+
56+
ctx := t.Context()
57+
mainWt, err := OpenWorktree(ctx, filepath.Join(dir, "repo"), OpenOptions{
58+
Log: silogtest.New(t),
59+
})
60+
require.NoError(t, err)
61+
62+
wt, err := OpenWorktree(ctx, filepath.Join(dir, "worktree"), OpenOptions{
63+
Log: silogtest.New(t),
64+
})
65+
require.NoError(t, err)
66+
67+
// Both should reference the same repository git directory
68+
// This ensures the fix where gitCommonDir is used instead of gitDir
69+
assert.Equal(t, mainWt.Repository().gitDir, wt.Repository().gitDir,
70+
"repositories for both worktrees should share the same git directory")
71+
72+
assert.NotEqual(t, mainWt.gitDir, wt.gitDir,
73+
"worktrees should have different git directories")
74+
}
75+
2976
func TestExtraConfig_Args(t *testing.T) {
3077
tests := []struct {
3178
name string
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# 'branch restack' with worktrees: main in wt1, feature in wt2, conflict resolution with 'gs rbc'
2+
3+
as 'Test <[email protected]>'
4+
at '2025-06-26T21:28:29Z'
5+
6+
# setup main repository (this will be wt1)
7+
cd wt1
8+
git init
9+
git add init.txt
10+
git commit -m 'Initial commit'
11+
gs repo init
12+
13+
# create feature branch
14+
cp $WORK/extra/init.feature.txt init.txt
15+
git add init.txt
16+
gs bc -m feature
17+
gs trunk
18+
19+
# create worktree wt2 for feature branch
20+
git worktree add ../wt2 feature
21+
22+
# now change the main branch in wt1
23+
gs trunk
24+
cp $WORK/extra/init.main.txt init.txt
25+
git add init.txt
26+
git commit -m 'Change init on main'
27+
28+
# go to wt2 (feature worktree) and attempt restack
29+
cd ../wt2
30+
git branch --show-current
31+
stdout 'feature'
32+
33+
# restack the feature branch from wt2 (this will conflict)
34+
! gs branch restack
35+
stderr 'There was a conflict while rebasing'
36+
37+
# resolve the conflict
38+
cp $WORK/extra/init.resolved.txt init.txt
39+
git add init.txt
40+
env EDITOR=true
41+
gs rbc
42+
43+
# verify state in wt2
44+
git graph --branches
45+
cmp stdout $WORK/golden/graph.txt
46+
47+
-- wt1/init.txt --
48+
initial init
49+
50+
-- extra/init.main.txt --
51+
changed init on main
52+
53+
-- extra/init.feature.txt --
54+
feature's init
55+
56+
-- extra/init.resolved.txt --
57+
resolved init content
58+
59+
-- golden/graph.txt --
60+
* b05ac5a (HEAD -> feature) feature
61+
* e6e3766 (main) Change init on main
62+
* 26ee912 Initial commit

0 commit comments

Comments
 (0)