Skip to content

Commit 1891f42

Browse files
committed
Speed up graph: only show stacked branches, remove auto-discovery
graph now only processes branches in stack.json (not all repo branches). Removed detectParentFast which ran merge-base for every untracked branch. 9 git calls total regardless of repo branch count.
1 parent d022ad0 commit 1891f42

3 files changed

Lines changed: 32 additions & 63 deletions

File tree

gx.exe

7.26 MB
Binary file not shown.

internal/git/git.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ func (e *Error) Error() string {
2525
return fmt.Sprintf("git %s failed: %v", strings.Join(e.Args, " "), e.Err)
2626
}
2727

28+
var gitCallCount int
29+
2830
// Run executes a git command and returns trimmed stdout.
2931
func Run(args ...string) (string, error) {
32+
gitCallCount++
3033
cmd := exec.Command("git", args...)
3134
var stdout, stderr bytes.Buffer
3235
cmd.Stdout = &stdout
@@ -38,6 +41,9 @@ func Run(args ...string) (string, error) {
3841
return strings.TrimSpace(stdout.String()), nil
3942
}
4043

44+
// CallCount returns the number of git subprocess calls made.
45+
func CallCount() int { return gitCallCount }
46+
4147
// RunDir executes a git command in a specific directory.
4248
func RunDir(dir string, args ...string) (string, error) {
4349
cmd := exec.Command("git", args...)

internal/stack/tree.go

Lines changed: 26 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package stack
22

33
import (
4-
"fmt"
54
"sort"
65
"strings"
76

@@ -54,39 +53,42 @@ func BuildTree() *BranchStack {
5453
}
5554
}
5655

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)
5957
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
7164
}
7265
}
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-
}
8066
}
8167
if changed {
8268
_ = cfg.Save()
8369
}
8470

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
8675
current, _ := git.CurrentBranch()
8776
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+
}
9092
}
9193

9294
// Wire parent-child links
@@ -179,42 +181,3 @@ func BuildTree() *BranchStack {
179181
}
180182
}
181183

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

Comments
 (0)