|
1 | 1 | package stack |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "fmt" |
5 | 4 | "sort" |
6 | 5 | "strings" |
7 | 6 |
|
@@ -54,39 +53,42 @@ func BuildTree() *BranchStack { |
54 | 53 | } |
55 | 54 | } |
56 | 55 |
|
57 | | - // Self-heal: detect parents for unknown branches |
58 | | - // Only check against trunk and existing stack parents (not all branches - avoids O(N^2)) |
| 56 | + // Clean stale parent references (parent branch was deleted) |
59 | 57 | changed := false |
60 | | - candidates := map[string]bool{mainBranch: true} |
61 | | - for _, meta := range cfg.Branches { |
62 | | - candidates[meta.Parent] = true |
63 | | - } |
64 | | - for branch := range branchSHAs { |
65 | | - if branch == mainBranch { |
66 | | - continue |
67 | | - } |
68 | | - if meta, ok := cfg.Branches[branch]; ok { |
69 | | - if _, exists := branchSHAs[meta.Parent]; exists { |
70 | | - continue |
| 58 | + for name, meta := range cfg.Branches { |
| 59 | + if _, exists := branchSHAs[meta.Parent]; !exists { |
| 60 | + // Parent no longer exists, default to trunk |
| 61 | + if meta.Parent != mainBranch { |
| 62 | + cfg.Branches[name] = &BranchMeta{Parent: mainBranch, ParentHead: meta.ParentHead} |
| 63 | + changed = true |
71 | 64 | } |
72 | 65 | } |
73 | | - // Only check against trunk and known parents, not all branches |
74 | | - detected := detectParentFast(branch, mainBranch, candidates, branchSHAs) |
75 | | - if detected != "" { |
76 | | - parentHead, _ := git.MergeBase(branch, detected) |
77 | | - cfg.Branches[branch] = &BranchMeta{Parent: detected, ParentHead: parentHead} |
78 | | - changed = true |
79 | | - } |
80 | 66 | } |
81 | 67 | if changed { |
82 | 68 | _ = cfg.Save() |
83 | 69 | } |
84 | 70 |
|
85 | | - // Build nodes |
| 71 | + // No self-healing: only show branches explicitly in stack.json. |
| 72 | + // Use `gx stack` to add branches to the stack. |
| 73 | + |
| 74 | + // Build nodes only for trunk + branches in the stack config |
86 | 75 | current, _ := git.CurrentBranch() |
87 | 76 | nodes := make(map[string]*BranchNode) |
88 | | - for name, sha := range branchSHAs { |
89 | | - nodes[name] = &BranchNode{Name: name, SHA: sha, IsHead: name == current} |
| 77 | + |
| 78 | + // Always include trunk |
| 79 | + if sha, exists := branchSHAs[mainBranch]; exists { |
| 80 | + nodes[mainBranch] = &BranchNode{Name: mainBranch, SHA: sha, IsHead: mainBranch == current} |
| 81 | + } |
| 82 | + // Include all stacked branches and their parents |
| 83 | + for name, meta := range cfg.Branches { |
| 84 | + if sha, exists := branchSHAs[name]; exists { |
| 85 | + nodes[name] = &BranchNode{Name: name, SHA: sha, IsHead: name == current} |
| 86 | + } |
| 87 | + if _, exists := nodes[meta.Parent]; !exists { |
| 88 | + if sha, exists := branchSHAs[meta.Parent]; exists { |
| 89 | + nodes[meta.Parent] = &BranchNode{Name: meta.Parent, SHA: sha, IsHead: meta.Parent == current} |
| 90 | + } |
| 91 | + } |
90 | 92 | } |
91 | 93 |
|
92 | 94 | // Wire parent-child links |
@@ -179,42 +181,3 @@ func BuildTree() *BranchStack { |
179 | 181 | } |
180 | 182 | } |
181 | 183 |
|
182 | | -// detectParentFast checks only trunk and known stack parents (not all branches). |
183 | | -func detectParentFast(branch, mainBranch string, candidates map[string]bool, branchSHAs map[string]string) string { |
184 | | - // Try trunk first (most common case) |
185 | | - if _, exists := branchSHAs[mainBranch]; exists { |
186 | | - if mb, err := git.MergeBase(branch, mainBranch); err == nil && mb != "" { |
187 | | - return mainBranch |
188 | | - } |
189 | | - } |
190 | | - // Try other known parents |
191 | | - var bestParent string |
192 | | - bestDistance := int(^uint(0) >> 1) |
193 | | - for candidate := range candidates { |
194 | | - if candidate == branch || candidate == mainBranch { |
195 | | - continue |
196 | | - } |
197 | | - if _, exists := branchSHAs[candidate]; !exists { |
198 | | - continue |
199 | | - } |
200 | | - mb, err := git.MergeBase(branch, candidate) |
201 | | - if err != nil || mb == "" { |
202 | | - continue |
203 | | - } |
204 | | - countStr, err := git.Run("rev-list", "--count", mb+".."+branch) |
205 | | - if err != nil { |
206 | | - continue |
207 | | - } |
208 | | - var distance int |
209 | | - if _, err := fmt.Sscanf(countStr, "%d", &distance); err == nil { |
210 | | - if distance < bestDistance { |
211 | | - bestDistance = distance |
212 | | - bestParent = candidate |
213 | | - } |
214 | | - } |
215 | | - } |
216 | | - if bestParent != "" { |
217 | | - return bestParent |
218 | | - } |
219 | | - return mainBranch |
220 | | -} |
0 commit comments