Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Git merge strategies, conflict resolution approaches, merge vs rebase recommendations, and branch integration patterns in sidecar. Covers pull strategy menu, direct merge workflow, squash merge, commit message templates, configurable defaults, and protected branches. Use when working on git merge features or making decisions about merge strategies.
.claude/skills/marcus-merge-strategy/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 33% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 34% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 77% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 54% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 27% | 0% |
This skill covers sidecar's git merge and pull operations, their current implementation, known gaps, and recommended configuration patterns.
Location: internal/plugins/gitstatus/pull_menu.go, internal/plugins/gitstatus/remote.go
The git-status plugin offers four pull strategies via a modal menu:
| Strategy | Command | Use Case | |----------|---------|----------| | Pull (merge) | git pull | Creates merge commit, preserves branch topology | | Pull (rebase) | git pull --rebase | Replays local commits on top of upstream | | Pull (fast-forward only) | git pull --ff-only | Only pulls if fast-forward possible (safest) | | Pull (rebase + autostash) | git pull --rebase --autostash | Rebase with automatic stash/unstash |
Location: internal/plugins/workspace/merge.go
PR Workflow:
gh pr createDirect Merge (No PR) at merge.go:430-498:
1. git fetch origin <baseBranch>
2. git checkout <baseBranch>
3. git pull origin <baseBranch>
4. git merge <branch> --no-ff -m "Merge branch '<branch>'" // Hardcoded --no-ff
5. git push origin <baseBranch>Post-Merge Pull at merge.go:500-551:
git pull --ff-only origin <branch> (hardcoded)git fetch + git update-refDivergence Resolution at merge.go:644-705:
git pull --rebase origin <branch>git pull origin <branch>--no-ff, missing --ff, --ff-only, --squash, rebase-based integrationfmt.Sprintf("Merge branch '%s'", branch), no templates--verify-signatures, no --force-with-leaseorigin, no configurable trackingAdd to internal/config/config.go:
gotype GitConfig struct { DefaultPullStrategy string `json:"defaultPullStrategy,omitempty"` // "merge", "rebase", "ff-only", "autostash" DefaultMergeStrategy string `json:"defaultMergeStrategy,omitempty"` // "no-ff", "ff", "ff-only", "squash", "rebase" MergeCommitTemplate string `json:"mergeCommitTemplate,omitempty"` // Go template: .Branch, .BaseBranch, .PRTitle, .PRNumber SignCommits bool `json:"signCommits,omitempty"` SignMerges bool `json:"signMerges,omitempty"` AutostashOnPull bool `json:"autostashOnPull,omitempty"` DefaultRemote string `json:"defaultRemote,omitempty"` // Default: "origin" SetUpstreamOnPush bool `json:"setUpstreamOnPush,omitempty"` ProtectedBranches []string `json:"protectedBranches,omitempty"` // e.g. ["main", "master", "release/*"] PreMergeChecks []string `json:"preMergeChecks,omitempty"` // e.g. ["go test ./..."] }
Add to PluginsConfig:
gotype PluginsConfig struct { Git GitConfig `json:"git"` GitStatus GitStatusPluginConfig `json:"git-status"` // ... existing fields }
Example user config (~/.config/sidecar/config.json):
json{ "plugins": { "git": { "defaultPullStrategy": "rebase", "defaultMergeStrategy": "squash", "mergeCommitTemplate": "Merge {{.Branch}} into {{.BaseBranch}}", "signCommits": true, "autostashOnPull": true, "protectedBranches": ["main", "production"] } } }
Files: internal/config/config.go, internal/plugins/gitstatus/pull_menu.go, internal/plugins/gitstatus/update_handlers.go
defaultPullStrategy is set, execute directly (skip menu)File: internal/plugins/workspace/merge.go -- performDirectMerge()
gofunc (p *Plugin) performDirectMerge(wt *Worktree) tea.Cmd { strategy := p.ctx.Config.Plugins.Git.DefaultMergeStrategy if strategy == "" { strategy = "no-ff" // backward compatible default } var mergeArgs []string switch strategy { case "ff": mergeArgs = []string{"merge", branch, "-m", mergeMsg} case "ff-only": mergeArgs = []string{"merge", branch, "--ff-only"} case "squash": mergeArgs = []string{"merge", branch, "--squash"} case "rebase": // 1. git rebase baseBranch branch // 2. git checkout baseBranch // 3. git merge branch --ff-only default: // "no-ff" mergeArgs = []string{"merge", branch, "--no-ff", "-m", mergeMsg} } }
After git merge --squash, a separate commit is needed:
gocase "squash": mergeCmd := exec.Command("git", "merge", branch, "--squash") // execute... commitMsg := fmt.Sprintf("Squash merge branch '%s'", branch) commitCmd := exec.Command("git", "commit", "-m", commitMsg)
gotype MergeTemplateData struct { Branch, BaseBranch, PRTitle, PRNumber string } func renderMergeMessage(tmpl string, data MergeTemplateData) (string, error) { if tmpl == "" { tmpl = "Merge branch '{{.Branch}}'" } t, err := template.New("merge").Parse(tmpl) // ... execute template }
gofunc isProtectedBranch(branch string, patterns []string) bool { for _, pattern := range patterns { if matched, _ := filepath.Match(pattern, branch); matched { return true } } return false }
Show confirmation modal before direct merge to protected branches.
| Strategy | History | Commit Count | Best For | |----------|---------|--------------|----------| | No Fast-Forward (--no-ff) | Preserves branch topology | +1 merge commit | Feature branches, audit trails | | Fast-Forward (--ff) | Linear when possible | No extra commits | Small changes, single commits | | Fast-Forward Only (--ff-only) | Always linear | Fails if not possible | Strict linear history | | Squash | Linear | Single commit | Clean history, large features | | Rebase | Linear, preserves commits | No merge commit | Clean history with detail |
squash, PR workflow recommendedno-ff, direct merge acceptablerebase or ff, direct merge for speed| File | Purpose | |------|---------| | internal/config/config.go | Config struct definitions | | internal/config/loader.go | Config loading and defaults | | internal/plugins/gitstatus/remote.go | Pull/fetch operations | | internal/plugins/gitstatus/pull_menu.go | Pull strategy UI | | internal/plugins/workspace/merge.go | Merge workflow | | internal/plugins/workspace/diff.go | Base branch detection | | internal/plugins/workspace/worktree.go | Branch operations |
Other measured skills in the registry, with their headline benchmark lift.