← back to joescharf__wt

Function bodies 244 total

All specs Real LLM only Function bodies
mocks.MockClient.WorktreeAdd method · go · L1235-L1250 (16 LOC)
pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreeAdd(repoPath string, wtPath string, branch string, base string, newBranch bool) error {
	ret := _m.Called(repoPath, wtPath, branch, base, newBranch)

	if len(ret) == 0 {
		panic("no return value specified for WorktreeAdd")
	}

	var r0 error
	if rf, ok := ret.Get(0).(func(string, string, string, string, bool) error); ok {
		r0 = rf(repoPath, wtPath, branch, base, newBranch)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
mocks.MockClient_WorktreeAdd_Call.Run method · go · L1267-L1272 (6 LOC)
pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreeAdd_Call) Run(run func(repoPath string, wtPath string, branch string, base string, newBranch bool)) *MockClient_WorktreeAdd_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string), args[1].(string), args[2].(string), args[3].(string), args[4].(bool))
	})
	return _c
}
mocks.MockClient.WorktreeList method · go · L1285-L1312 (28 LOC)
pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreeList(repoPath string) ([]gitops.WorktreeInfo, error) {
	ret := _m.Called(repoPath)

	if len(ret) == 0 {
		panic("no return value specified for WorktreeList")
	}

	var r0 []gitops.WorktreeInfo
	var r1 error
	if rf, ok := ret.Get(0).(func(string) ([]gitops.WorktreeInfo, error)); ok {
		return rf(repoPath)
	}
	if rf, ok := ret.Get(0).(func(string) []gitops.WorktreeInfo); ok {
		r0 = rf(repoPath)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]gitops.WorktreeInfo)
		}
	}

	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(repoPath)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
mocks.MockClient_WorktreeList_Call.Run method · go · L1325-L1330 (6 LOC)
pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreeList_Call) Run(run func(repoPath string)) *MockClient_WorktreeList_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string))
	})
	return _c
}
mocks.MockClient.WorktreePrune method · go · L1343-L1358 (16 LOC)
pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreePrune(repoPath string) error {
	ret := _m.Called(repoPath)

	if len(ret) == 0 {
		panic("no return value specified for WorktreePrune")
	}

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(repoPath)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
mocks.MockClient_WorktreePrune_Call.Run method · go · L1371-L1376 (6 LOC)
pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreePrune_Call) Run(run func(repoPath string)) *MockClient_WorktreePrune_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string))
	})
	return _c
}
mocks.MockClient.WorktreeRemove method · go · L1389-L1404 (16 LOC)
pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreeRemove(repoPath string, wtPath string, force bool) error {
	ret := _m.Called(repoPath, wtPath, force)

	if len(ret) == 0 {
		panic("no return value specified for WorktreeRemove")
	}

	var r0 error
	if rf, ok := ret.Get(0).(func(string, string, bool) error); ok {
		r0 = rf(repoPath, wtPath, force)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
All rows scored by the Repobility analyzer (https://repobility.com)
mocks.MockClient_WorktreeRemove_Call.Run method · go · L1419-L1424 (6 LOC)
pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreeRemove_Call) Run(run func(repoPath string, wtPath string, force bool)) *MockClient_WorktreeRemove_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string), args[1].(string), args[2].(bool))
	})
	return _c
}
mocks.MockClient.WorktreesDir method · go · L1437-L1462 (26 LOC)
pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreesDir(repoPath string) (string, error) {
	ret := _m.Called(repoPath)

	if len(ret) == 0 {
		panic("no return value specified for WorktreesDir")
	}

	var r0 string
	var r1 error
	if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
		return rf(repoPath)
	}
	if rf, ok := ret.Get(0).(func(string) string); ok {
		r0 = rf(repoPath)
	} else {
		r0 = ret.Get(0).(string)
	}

	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(repoPath)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
mocks.MockClient_WorktreesDir_Call.Run method · go · L1475-L1480 (6 LOC)
pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreesDir_Call) Run(run func(repoPath string)) *MockClient_WorktreesDir_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string))
	})
	return _c
}
mocks.NewMockClient function · go · L1494-L1504 (11 LOC)
pkg/gitops/mocks/mock_Client.go
func NewMockClient(t interface {
	mock.TestingT
	Cleanup(func())
}) *MockClient {
	mock := &MockClient{}
	mock.Mock.Test(t)

	t.Cleanup(func() { mock.AssertExpectations(t) })

	return mock
}
iterm.ScriptCreateWorktreeWindow function · go · L15-L44 (30 LOC)
pkg/iterm/applescript.go
func ScriptCreateWorktreeWindow(wtPath, sessionName string, noClaude bool) string {
	// Escape single quotes in paths for AppleScript
	safePath := escapeAppleScript(wtPath)
	safeName := escapeAppleScript(sessionName)

	claudeCmd := fmt.Sprintf("cd '%s' && claude", safePath)
	if noClaude {
		claudeCmd = fmt.Sprintf("cd '%s'", safePath)
	}

	return fmt.Sprintf(`tell application "iTerm2"
	set newWindow to (create window with default profile)
	tell newWindow
		tell current session of current tab
			set name to "%s:claude"
			write text "%s"
			set claudeID to unique ID
		end tell
		tell current session of current tab
			set shellSession to (split horizontally with default profile)
		end tell
		tell shellSession
			set name to "%s:shell"
			write text "cd '%s'"
			set shellID to unique ID
		end tell
	end tell
	return claudeID & "\t" & shellID
end tell`, safeName, claudeCmd, safeName, safePath)
}
iterm.ScriptSessionExists function · go · L47-L61 (15 LOC)
pkg/iterm/applescript.go
func ScriptSessionExists(sessionID string) string {
	safe := escapeAppleScript(sessionID)
	return fmt.Sprintf(`tell application "iTerm2"
	repeat with w in windows
		repeat with t in tabs of w
			repeat with s in sessions of t
				if unique ID of s is "%s" then
					return "true"
				end if
			end repeat
		end repeat
	end repeat
	return "false"
end tell`, safe)
}
iterm.ScriptFocusWindow function · go · L64-L81 (18 LOC)
pkg/iterm/applescript.go
func ScriptFocusWindow(sessionID string) string {
	safe := escapeAppleScript(sessionID)
	return fmt.Sprintf(`tell application "iTerm2"
	repeat with w in windows
		repeat with t in tabs of w
			repeat with s in sessions of t
				if unique ID of s is "%s" then
					select t
					tell w to select
					activate
					return true
				end if
			end repeat
		end repeat
	end repeat
	return false
end tell`, safe)
}
iterm.ScriptCloseWindow function · go · L84-L99 (16 LOC)
pkg/iterm/applescript.go
func ScriptCloseWindow(sessionID string) string {
	safe := escapeAppleScript(sessionID)
	return fmt.Sprintf(`tell application "iTerm2"
	repeat with w in windows
		repeat with t in tabs of w
			repeat with s in sessions of t
				if unique ID of s is "%s" then
					close w
					return true
				end if
			end repeat
		end repeat
	end repeat
	return false
end tell`, safe)
}
Repobility · open methodology · https://repobility.com/research/
iterm.RealClient.IsRunning method · go · L34-L40 (7 LOC)
pkg/iterm/iterm.go
func (c *RealClient) IsRunning() bool {
	out, err := exec.Command("osascript", "-e", ScriptIsRunning()).Output()
	if err != nil {
		return false
	}
	return strings.TrimSpace(string(out)) == "true"
}
iterm.RealClient.EnsureRunning method · go · L42-L61 (20 LOC)
pkg/iterm/iterm.go
func (c *RealClient) EnsureRunning() error {
	if c.IsRunning() {
		return nil
	}

	if err := exec.Command("open", "-a", "iTerm").Start(); err != nil {
		return fmt.Errorf("failed to launch iTerm2: %w", err)
	}

	// Wait up to 10 seconds
	for i := 0; i < 20; i++ {
		if c.IsRunning() {
			time.Sleep(1 * time.Second) // extra settle time
			return nil
		}
		time.Sleep(500 * time.Millisecond)
	}

	return fmt.Errorf("timed out waiting for iTerm2 to start")
}
iterm.RealClient.CreateWorktreeWindow method · go · L63-L83 (21 LOC)
pkg/iterm/iterm.go
func (c *RealClient) CreateWorktreeWindow(path, name string, noClaude bool) (*SessionIDs, error) {
	if err := c.EnsureRunning(); err != nil {
		return nil, err
	}

	script := ScriptCreateWorktreeWindow(path, name, noClaude)
	out, err := exec.Command("osascript", "-e", script).Output()
	if err != nil {
		return nil, fmt.Errorf("failed to create iTerm2 window: %w", err)
	}

	parts := strings.SplitN(strings.TrimSpace(string(out)), "\t", 2)
	if len(parts) != 2 {
		return nil, fmt.Errorf("unexpected osascript output: %s", string(out))
	}

	return &SessionIDs{
		ClaudeSessionID: parts[0],
		ShellSessionID:  parts[1],
	}, nil
}
iterm.RealClient.SessionExists method · go · L85-L94 (10 LOC)
pkg/iterm/iterm.go
func (c *RealClient) SessionExists(sessionID string) bool {
	if sessionID == "" {
		return false
	}
	out, err := exec.Command("osascript", "-e", ScriptSessionExists(sessionID)).Output()
	if err != nil {
		return false
	}
	return strings.TrimSpace(string(out)) == "true"
}
iterm.RealClient.FocusWindow method · go · L96-L102 (7 LOC)
pkg/iterm/iterm.go
func (c *RealClient) FocusWindow(sessionID string) error {
	if sessionID == "" {
		return fmt.Errorf("empty session ID")
	}
	_, err := exec.Command("osascript", "-e", ScriptFocusWindow(sessionID)).Output()
	return err
}
iterm.RealClient.CloseWindow method · go · L104-L110 (7 LOC)
pkg/iterm/iterm.go
func (c *RealClient) CloseWindow(sessionID string) error {
	if sessionID == "" {
		return fmt.Errorf("empty session ID")
	}
	_, err := exec.Command("osascript", "-e", ScriptCloseWindow(sessionID)).Output()
	return err
}
mocks.MockClient.CloseWindow method · go · L24-L39 (16 LOC)
pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) CloseWindow(sessionID string) error {
	ret := _m.Called(sessionID)

	if len(ret) == 0 {
		panic("no return value specified for CloseWindow")
	}

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(sessionID)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
mocks.MockClient_CloseWindow_Call.Run method · go · L52-L57 (6 LOC)
pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_CloseWindow_Call) Run(run func(sessionID string)) *MockClient_CloseWindow_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string))
	})
	return _c
}
Powered by Repobility — scan your code at https://repobility.com
mocks.MockClient.CreateWorktreeWindow method · go · L70-L97 (28 LOC)
pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) CreateWorktreeWindow(path string, name string, noClaude bool) (*iterm.SessionIDs, error) {
	ret := _m.Called(path, name, noClaude)

	if len(ret) == 0 {
		panic("no return value specified for CreateWorktreeWindow")
	}

	var r0 *iterm.SessionIDs
	var r1 error
	if rf, ok := ret.Get(0).(func(string, string, bool) (*iterm.SessionIDs, error)); ok {
		return rf(path, name, noClaude)
	}
	if rf, ok := ret.Get(0).(func(string, string, bool) *iterm.SessionIDs); ok {
		r0 = rf(path, name, noClaude)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*iterm.SessionIDs)
		}
	}

	if rf, ok := ret.Get(1).(func(string, string, bool) error); ok {
		r1 = rf(path, name, noClaude)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
mocks.MockClient_CreateWorktreeWindow_Call.Run method · go · L112-L117 (6 LOC)
pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_CreateWorktreeWindow_Call) Run(run func(path string, name string, noClaude bool)) *MockClient_CreateWorktreeWindow_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string), args[1].(string), args[2].(bool))
	})
	return _c
}
mocks.MockClient.EnsureRunning method · go · L130-L145 (16 LOC)
pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) EnsureRunning() error {
	ret := _m.Called()

	if len(ret) == 0 {
		panic("no return value specified for EnsureRunning")
	}

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
mocks.MockClient_EnsureRunning_Call.Run method · go · L157-L162 (6 LOC)
pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_EnsureRunning_Call) Run(run func()) *MockClient_EnsureRunning_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run()
	})
	return _c
}
mocks.MockClient.FocusWindow method · go · L175-L190 (16 LOC)
pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) FocusWindow(sessionID string) error {
	ret := _m.Called(sessionID)

	if len(ret) == 0 {
		panic("no return value specified for FocusWindow")
	}

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(sessionID)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
mocks.MockClient_FocusWindow_Call.Run method · go · L203-L208 (6 LOC)
pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_FocusWindow_Call) Run(run func(sessionID string)) *MockClient_FocusWindow_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string))
	})
	return _c
}
mocks.MockClient.IsRunning method · go · L221-L236 (16 LOC)
pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) IsRunning() bool {
	ret := _m.Called()

	if len(ret) == 0 {
		panic("no return value specified for IsRunning")
	}

	var r0 bool
	if rf, ok := ret.Get(0).(func() bool); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(bool)
	}

	return r0
}
mocks.MockClient_IsRunning_Call.Run method · go · L248-L253 (6 LOC)
pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_IsRunning_Call) Run(run func()) *MockClient_IsRunning_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run()
	})
	return _c
}
Repobility — same analyzer, your code, free for public repos · /scan/
mocks.MockClient.SessionExists method · go · L266-L281 (16 LOC)
pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) SessionExists(sessionID string) bool {
	ret := _m.Called(sessionID)

	if len(ret) == 0 {
		panic("no return value specified for SessionExists")
	}

	var r0 bool
	if rf, ok := ret.Get(0).(func(string) bool); ok {
		r0 = rf(sessionID)
	} else {
		r0 = ret.Get(0).(bool)
	}

	return r0
}
mocks.MockClient_SessionExists_Call.Run method · go · L294-L299 (6 LOC)
pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_SessionExists_Call) Run(run func(sessionID string)) *MockClient_SessionExists_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string))
	})
	return _c
}
mocks.NewMockClient function · go · L313-L323 (11 LOC)
pkg/iterm/mocks/mock_Client.go
func NewMockClient(t interface {
	mock.TestingT
	Cleanup(func())
}) *MockClient {
	mock := &MockClient{}
	mock.Mock.Test(t)

	t.Cleanup(func() { mock.AssertExpectations(t) })

	return mock
}
lifecycle.NewManager function · go · L28-L36 (9 LOC)
pkg/lifecycle/lifecycle.go
func NewManager(git gitops.Client, it iterm.Client, sm *state.Manager, trust *claude.TrustManager, log ops.Logger) *Manager {
	return &Manager{
		git:   git,
		iterm: it,
		state: sm,
		trust: trust,
		log:   log,
	}
}
lifecycle.Manager.Create method · go · L59-L185 (127 LOC)
pkg/lifecycle/lifecycle.go
func (m *Manager) Create(opts CreateOptions) (*CreateResult, error) {
	repoName, err := m.git.RepoName(opts.RepoPath)
	if err != nil {
		return nil, err
	}

	wtDir, err := m.git.WorktreesDir(opts.RepoPath)
	if err != nil {
		return nil, err
	}

	dirname := gitops.BranchToDirname(opts.Branch)
	wtPath := filepath.Join(wtDir, dirname)

	m.log.Info("Creating worktree for branch '%s' in repo '%s'", opts.Branch, repoName)
	m.log.Verbose("Worktrees dir: %s", wtDir)
	m.log.Verbose("Worktree path: %s", wtPath)
	m.log.Verbose("Base branch: %s", opts.BaseBranch)

	// If worktree already exists, delegate to open
	if isDirectory(wtPath) {
		m.log.Info("Worktree already exists, opening iTerm2 window")
		openResult, err := m.Open(OpenOptions{
			RepoPath: opts.RepoPath,
			WtPath:   wtPath,
			Branch:   opts.Branch,
			NoClaude: opts.NoClaude,
			DryRun:   opts.DryRun,
		})
		if err != nil {
			return nil, err
		}
		return &CreateResult{
			WtPath:    openResult.WtPath,
			Branch:    openResult.Branc
lifecycle.Manager.Open method · go · L205-L266 (62 LOC)
pkg/lifecycle/lifecycle.go
func (m *Manager) Open(opts OpenOptions) (*OpenResult, error) {
	repoName, err := m.git.RepoName(opts.RepoPath)
	if err != nil {
		return nil, err
	}

	dirname := filepath.Base(opts.WtPath)

	// Check if window already exists
	ws, err := m.state.GetWorktree(opts.WtPath)
	if err != nil {
		return nil, err
	}
	if ws != nil && ws.ClaudeSessionID != "" {
		if m.iterm.IsRunning() && m.iterm.SessionExists(ws.ClaudeSessionID) {
			m.log.Info("iTerm2 window already open, focusing it")
			if err := m.iterm.FocusWindow(ws.ClaudeSessionID); err != nil {
				return nil, err
			}
			return &OpenResult{WtPath: opts.WtPath, Branch: opts.Branch, SessionID: ws.ClaudeSessionID, Focused: true}, nil
		}
	}

	if opts.DryRun {
		m.log.Info("Would open iTerm2 window for %s", opts.WtPath)
		return &OpenResult{WtPath: opts.WtPath, Branch: opts.Branch}, nil
	}

	// Pre-approve Claude Code trust
	m.trustProject(opts.WtPath)

	sessionName := fmt.Sprintf("wt:%s:%s", repoName, dirname)
	m.log.Info("Opening iTerm2 w
lifecycle.Manager.Delete method · go · L280-L350 (71 LOC)
pkg/lifecycle/lifecycle.go
func (m *Manager) Delete(opts DeleteOptions) error {
	dirname := filepath.Base(opts.WtPath)

	// Close iTerm2 window if it exists
	ws, _ := m.state.GetWorktree(opts.WtPath)
	if ws != nil && ws.ClaudeSessionID != "" {
		if opts.DryRun {
			m.log.Info("Would close iTerm2 window")
		} else if m.iterm.IsRunning() && m.iterm.SessionExists(ws.ClaudeSessionID) {
			if err := m.iterm.CloseWindow(ws.ClaudeSessionID); err != nil {
				m.log.Warning("Failed to close iTerm2 window: %v", err)
			} else {
				m.log.Success("Closed iTerm2 window")
				time.Sleep(500 * time.Millisecond)
			}
		}
	}

	// Remove worktree
	if opts.DryRun {
		m.log.Info("Would remove git worktree: %s", opts.WtPath)
	} else {
		m.log.Info("Removing git worktree")
		if err := m.git.WorktreeRemove(opts.RepoPath, opts.WtPath, opts.Force); err != nil {
			return err
		}
		m.log.Success("Removed git worktree")
	}

	// Delete branch if requested
	if opts.DeleteBranch {
		branchName := opts.Branch
		if ws != nil && ws.Branch != "
lifecycle.Manager.trustProject method · go · L353-L363 (11 LOC)
pkg/lifecycle/lifecycle.go
func (m *Manager) trustProject(wtPath string) {
	if m.trust == nil {
		return
	}
	added, err := m.trust.TrustProject(wtPath)
	if err != nil {
		m.log.Warning("Failed to set Claude trust: %v", err)
	} else if added {
		m.log.Verbose("Claude trust set for %s", wtPath)
	}
}
All rows scored by the Repobility analyzer (https://repobility.com)
ops.Delete function · go · L13-L36 (24 LOC)
pkg/ops/delete.go
func Delete(git gitops.Client, log Logger, opts DeleteOptions, safetyCheck SafetyCheckFunc, cleanup CleanupFunc) error {
	dirname := filepath.Base(opts.WtPath)

	log.Info("Deleting worktree '%s'", dirname)

	// Safety checks (skip with --force)
	if !opts.Force && safetyCheck != nil {
		safe, err := safetyCheck(opts.WtPath)
		if err != nil {
			return err
		}
		if !safe {
			return fmt.Errorf("delete aborted")
		}
	}

	if cleanup != nil {
		if err := cleanup(opts.WtPath, opts.Branch); err != nil {
			return err
		}
	}

	return nil
}
ops.DeleteAll function · go · L41-L101 (61 LOC)
pkg/ops/delete.go
func DeleteAll(git gitops.Client, log Logger, opts DeleteOptions, safetyCheck SafetyCheckFunc, cleanup CleanupFunc) (int, error) {
	worktrees, err := git.WorktreeList(opts.RepoPath)
	if err != nil {
		return 0, err
	}

	// Filter out main repo
	var toDelete []gitops.WorktreeInfo
	for _, wt := range worktrees {
		if wt.Path != opts.RepoPath {
			toDelete = append(toDelete, wt)
		}
	}

	if len(toDelete) == 0 {
		log.Info("No worktrees to delete")
		return 0, nil
	}

	log.Info("Found %d worktrees to delete", len(toDelete))

	deleted := 0
	for _, wt := range toDelete {
		dirname := filepath.Base(wt.Path)

		if !isDirectory(wt.Path) {
			continue
		}

		// Safety checks
		if !opts.Force && safetyCheck != nil {
			safe, err := safetyCheck(wt.Path)
			if err != nil {
				log.Warning("Safety check failed for '%s': %v (skipping)", dirname, err)
				continue
			}
			if !safe {
				log.Info("Skipping '%s'", dirname)
				continue
			}
		}

		// Cleanup (iTerm, worktree remove, branch delete, state
ops.Discover function · go · L8-L83 (76 LOC)
pkg/ops/discover.go
func Discover(git gitops.Client, log Logger, opts DiscoverOptions, stateCheck StateChecker, stateAdopt StateAdopter) (*DiscoverResult, error) {
	repoName, err := git.RepoName(opts.RepoPath)
	if err != nil {
		return nil, err
	}

	wtDir, err := git.WorktreesDir(opts.RepoPath)
	if err != nil {
		return nil, err
	}

	worktrees, err := git.WorktreeList(opts.RepoPath)
	if err != nil {
		return nil, err
	}

	result := &DiscoverResult{RepoName: repoName}

	// Find worktrees not in state
	for _, wt := range worktrees {
		if wt.Path == opts.RepoPath {
			continue
		}

		managed, err := stateCheck(wt.Path)
		if err != nil {
			log.Verbose("Could not check state for '%s': %v", wt.Path, err)
			continue
		}
		if managed {
			continue
		}

		result.Unmanaged = append(result.Unmanaged, UnmanagedWorktree{
			Path:   wt.Path,
			Branch: wt.Branch,
			Source: classifySource(wt.Path, wtDir),
		})
	}

	if len(result.Unmanaged) == 0 {
		log.Success("No unmanaged worktrees found")
		return result, nil
	}

ops.Merge function · go · L15-L45 (31 LOC)
pkg/ops/merge.go
func Merge(git gitops.Client, log Logger, opts MergeOptions, cleanup CleanupFunc, prCreate PRCreateFunc) (*MergeResult, error) {
	result := &MergeResult{Branch: opts.Branch}
	dirname := filepath.Base(opts.WtPath)

	// Safety check: dirty worktree
	if !opts.Force {
		dirty, err := git.IsWorktreeDirty(opts.WtPath)
		if err != nil {
			log.Warning("Could not check worktree status: %v", err)
		}
		if dirty {
			return result, fmt.Errorf("worktree '%s' has uncommitted changes (use --force to skip)", dirname)
		}
	}

	// Check if there are commits to merge
	hasCommits, err := git.HasUnpushedCommits(opts.WtPath, opts.BaseBranch)
	if err != nil {
		log.Verbose("Could not check for commits: %v", err)
	}
	if !hasCommits {
		log.Info("No commits to merge for '%s'", opts.Branch)
		result.Success = true
		return result, nil
	}

	if opts.CreatePR {
		return mergePR(git, log, opts, result, prCreate)
	}
	return mergeLocal(git, log, opts, result, cleanup)
}
ops.mergeLocal function · go · L48-L134 (87 LOC)
pkg/ops/merge.go
func mergeLocal(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, cleanup CleanupFunc) (*MergeResult, error) {
	// Check if a merge is already in progress in main repo
	mergeInProgress, err := git.IsMergeInProgress(opts.RepoPath)
	if err != nil {
		log.Verbose("Could not check merge status: %v", err)
	}
	if mergeInProgress {
		return mergeLocalContinue(git, log, opts, result, cleanup)
	}

	// Check if a rebase is in progress in the worktree (rebase-then-ff flow)
	rebaseInProgress, err := git.IsRebaseInProgress(opts.WtPath)
	if err != nil {
		log.Verbose("Could not check rebase status: %v", err)
	}
	if rebaseInProgress {
		return mergeLocalContinueRebase(git, log, opts, result, cleanup)
	}

	// Verify main repo is on the base branch
	currentBranch, err := git.CurrentBranch(opts.RepoPath)
	if err != nil {
		return result, err
	}
	if currentBranch != opts.BaseBranch {
		return result, fmt.Errorf("main repo is on '%s', expected '%s' — switch to '%s' first", currentBran
ops.mergeLocalContinue function · go · L137-L158 (22 LOC)
pkg/ops/merge.go
func mergeLocalContinue(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, cleanup CleanupFunc) (*MergeResult, error) {
	log.Info("Merge in progress — continuing merge of '%s' into '%s'", opts.Branch, opts.BaseBranch)

	hasConflicts, err := git.HasConflicts(opts.RepoPath)
	if err != nil {
		log.Verbose("Could not check conflict status: %v", err)
	}
	if hasConflicts {
		return result, fmt.Errorf("main repo has unresolved conflicts — resolve all conflicts and stage files, then run merge again")
	}

	if opts.DryRun {
		log.Info("Would run: git merge --continue")
	} else {
		if err := git.MergeContinue(opts.RepoPath); err != nil {
			return result, fmt.Errorf("merge --continue failed: %w", err)
		}
		log.Success("Merge continued — '%s' merged into '%s'", opts.Branch, opts.BaseBranch)
	}

	return mergeLocalFinish(git, log, opts, result, cleanup)
}
ops.mergeLocalContinueRebase function · go · L161-L191 (31 LOC)
pkg/ops/merge.go
func mergeLocalContinueRebase(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, cleanup CleanupFunc) (*MergeResult, error) {
	dirname := filepath.Base(opts.WtPath)
	log.Info("Rebase in progress — continuing merge of '%s' into '%s'", opts.Branch, opts.BaseBranch)

	hasConflicts, err := git.HasConflicts(opts.WtPath)
	if err != nil {
		log.Verbose("Could not check conflict status: %v", err)
	}
	if hasConflicts {
		return result, fmt.Errorf("worktree has unresolved conflicts — resolve all conflicts and stage files, then run merge '%s' again (or 'git -C %s rebase --abort' to cancel)", dirname, opts.WtPath)
	}

	if opts.DryRun {
		log.Info("Would run: git rebase --continue")
		log.Info("Would fast-forward merge '%s' into '%s'", opts.Branch, opts.BaseBranch)
	} else {
		if err := git.RebaseContinue(opts.WtPath); err != nil {
			return result, fmt.Errorf("rebase --continue failed: %w", err)
		}
		log.Success("Rebase continued — '%s' rebased onto '%s'", opts.Branch, opts.Ba
ops.mergeLocalFinish function · go · L194-L225 (32 LOC)
pkg/ops/merge.go
func mergeLocalFinish(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, cleanup CleanupFunc) (*MergeResult, error) {
	// Push base branch if remote exists
	hasRemote, err := git.HasRemote(opts.RepoPath)
	if err != nil {
		log.Verbose("Could not check for remote: %v", err)
	}

	if hasRemote {
		if opts.DryRun {
			log.Info("Would push '%s'", opts.BaseBranch)
		} else {
			log.Info("Pushing '%s'", opts.BaseBranch)
			if err := git.Push(opts.RepoPath, opts.BaseBranch, false); err != nil {
				log.Warning("Push failed: %v (merge succeeded locally)", err)
			} else {
				log.Success("Pushed '%s'", opts.BaseBranch)
			}
		}
	}

	// Cleanup unless --no-cleanup
	if !opts.NoCleanup && cleanup != nil {
		log.Info("Cleaning up worktree")
		if err := cleanup(opts.WtPath, opts.Branch); err != nil {
			log.Warning("Cleanup failed: %v (merge succeeded)", err)
		}
	}

	result.Success = true
	log.Success("Merge complete")
	return result, nil
}
Repobility · open methodology · https://repobility.com/research/
ops.mergePR function · go · L228-L282 (55 LOC)
pkg/ops/merge.go
func mergePR(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, prCreate PRCreateFunc) (*MergeResult, error) {
	if opts.Strategy == "rebase" {
		log.Warning("--rebase is ignored for PR mode (merge strategy is configured on GitHub)")
	}

	log.Info("Creating PR for '%s' → '%s'", opts.Branch, opts.BaseBranch)

	// Push branch
	if opts.DryRun {
		log.Info("Would push branch '%s'", opts.Branch)
	} else {
		log.Info("Pushing branch '%s'", opts.Branch)
		if err := git.Push(opts.WtPath, opts.Branch, true); err != nil {
			return result, fmt.Errorf("push failed: %w", err)
		}
		log.Success("Pushed '%s'", opts.Branch)
	}

	// Build gh pr create args
	args := []string{"pr", "create", "--base", opts.BaseBranch, "--head", opts.Branch}
	if opts.PRTitle != "" {
		args = append(args, "--title", opts.PRTitle)
	}
	if opts.PRBody != "" {
		args = append(args, "--body", opts.PRBody)
	}
	if opts.PRTitle == "" && opts.PRBody == "" {
		args = append(args, "--fill")
	}
	if opts.PRDraft {
	
mocks.MockCleanupFunc.Execute method · go · L21-L36 (16 LOC)
pkg/ops/mocks/mock_CleanupFunc.go
func (_m *MockCleanupFunc) Execute(wtPath string, branch string) error {
	ret := _m.Called(wtPath, branch)

	if len(ret) == 0 {
		panic("no return value specified for Execute")
	}

	var r0 error
	if rf, ok := ret.Get(0).(func(string, string) error); ok {
		r0 = rf(wtPath, branch)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
mocks.MockCleanupFunc_Execute_Call.Run method · go · L50-L55 (6 LOC)
pkg/ops/mocks/mock_CleanupFunc.go
func (_c *MockCleanupFunc_Execute_Call) Run(run func(wtPath string, branch string)) *MockCleanupFunc_Execute_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string), args[1].(string))
	})
	return _c
}
‹ prevpage 4 / 5next ›