diff --git a/get-shit-done/bin/lib/config.cjs b/get-shit-done/bin/lib/config.cjs index 6b66d2668..5aecaac42 100644 --- a/get-shit-done/bin/lib/config.cjs +++ b/get-shit-done/bin/lib/config.cjs @@ -23,7 +23,7 @@ const VALID_CONFIG_KEYS = new Set([ 'workflow.skip_discuss', 'workflow._auto_chain_active', 'workflow.use_worktrees', - 'git.branching_strategy', 'git.phase_branch_template', 'git.milestone_branch_template', 'git.quick_branch_template', + 'git.branching_strategy', 'git.base_branch', 'git.phase_branch_template', 'git.milestone_branch_template', 'git.quick_branch_template', 'planning.commit_docs', 'planning.search_gitignored', 'hooks.context_warnings', 'project_code', 'phase_naming', diff --git a/get-shit-done/references/planning-config.md b/get-shit-done/references/planning-config.md index 20ee56f37..225852006 100644 --- a/get-shit-done/references/planning-config.md +++ b/get-shit-done/references/planning-config.md @@ -10,6 +10,7 @@ Configuration options for `.planning/` directory behavior. }, "git": { "branching_strategy": "none", + "base_branch": null, "phase_branch_template": "gsd/phase-{phase}-{slug}", "milestone_branch_template": "gsd/{milestone}-{slug}", "quick_branch_template": null @@ -21,6 +22,7 @@ Configuration options for `.planning/` directory behavior. | `commit_docs` | `true` | Whether to commit planning artifacts to git | | `search_gitignored` | `false` | Add `--no-ignore` to broad rg searches | | `git.branching_strategy` | `"none"` | Git branching approach: `"none"`, `"phase"`, or `"milestone"` | +| `git.base_branch` | `null` (auto-detect) | Target branch for PRs and merges (e.g. `"master"`, `"develop"`). When `null`, auto-detects from `git symbolic-ref refs/remotes/origin/HEAD`, falling back to `"main"`. | | `git.phase_branch_template` | `"gsd/phase-{phase}-{slug}"` | Branch template for phase strategy | | `git.milestone_branch_template` | `"gsd/{milestone}-{slug}"` | Branch template for milestone strategy | | `git.quick_branch_template` | `null` | Optional branch template for quick-task runs | diff --git a/get-shit-done/workflows/complete-milestone.md b/get-shit-done/workflows/complete-milestone.md index e95e7cb61..302d26494 100644 --- a/get-shit-done/workflows/complete-milestone.md +++ b/get-shit-done/workflows/complete-milestone.md @@ -537,6 +537,15 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi Extract `branching_strategy`, `phase_branch_template`, `milestone_branch_template`, and `commit_docs` from init JSON. +Detect base branch: +```bash +BASE_BRANCH=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get git.base_branch 2>/dev/null || echo "") +if [ -z "$BASE_BRANCH" ] || [ "$BASE_BRANCH" = "null" ]; then + BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||') + BASE_BRANCH="${BASE_BRANCH:-main}" +fi +``` + **If "none":** Skip to git_tag. **For "phase" strategy:** @@ -575,7 +584,7 @@ AskUserQuestion with options: Squash merge (Recommended), Merge with history, De ```bash CURRENT_BRANCH=$(git branch --show-current) -git checkout main +git checkout ${BASE_BRANCH} if [ "$BRANCHING_STRATEGY" = "phase" ]; then for branch in $PHASE_BRANCHES; do @@ -604,7 +613,7 @@ git checkout "$CURRENT_BRANCH" ```bash CURRENT_BRANCH=$(git branch --show-current) -git checkout main +git checkout ${BASE_BRANCH} if [ "$BRANCHING_STRATEGY" = "phase" ]; then for branch in $PHASE_BRANCHES; do diff --git a/get-shit-done/workflows/ship.md b/get-shit-done/workflows/ship.md index 3c29de1ff..49ee35ccd 100644 --- a/get-shit-done/workflows/ship.md +++ b/get-shit-done/workflows/ship.md @@ -24,6 +24,15 @@ CONFIG=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" state load) ``` Extract: `branching_strategy`, `branch_name`. + +Detect base branch for PRs and merges: +```bash +BASE_BRANCH=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get git.base_branch 2>/dev/null || echo "") +if [ -z "$BASE_BRANCH" ] || [ "$BASE_BRANCH" = "null" ]; then + BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||') + BASE_BRANCH="${BASE_BRANCH:-main}" +fi +``` @@ -46,7 +55,7 @@ Verify the work is ready to ship: ```bash CURRENT_BRANCH=$(git branch --show-current) ``` - If on `main`/`master`: warn — should be on a feature branch. + If on `${BASE_BRANCH}`: warn — should be on a feature branch. If branching_strategy is `none`: offer to create a branch now. 4. **Remote configured?** @@ -74,7 +83,7 @@ If push fails (e.g., no upstream): set upstream: git push --set-upstream origin ${CURRENT_BRANCH} 2>&1 ``` -Report: "Pushed `{branch}` to origin ({commit_count} commits ahead of main)" +Report: "Pushed `{branch}` to origin ({commit_count} commits ahead of ${BASE_BRANCH})" @@ -141,7 +150,7 @@ Create the PR using the generated body: gh pr create \ --title "Phase ${PHASE_NUMBER}: ${PHASE_NAME}" \ --body "${PR_BODY}" \ - --base main + --base ${BASE_BRANCH} ``` If `--draft` flag was passed: add `--draft`. @@ -194,7 +203,7 @@ node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs(${padded_phase ## ✓ Phase {X}: {Name} — Shipped PR: #{number} ({url}) -Branch: {branch} → main +Branch: {branch} → ${BASE_BRANCH} Commits: {count} Verification: ✓ Passed Requirements: {N} REQ-IDs addressed diff --git a/tests/config.test.cjs b/tests/config.test.cjs index 6280df25e..1167d8a36 100644 --- a/tests/config.test.cjs +++ b/tests/config.test.cjs @@ -242,6 +242,16 @@ describe('config-set command', () => { assert.strictEqual(config.workflow.use_worktrees, false); }); + test('sets git.base_branch for non-main default branches', () => { + writeConfig(tmpDir, {}); + + const result = runGsdTools('config-set git.base_branch master', tmpDir); + assert.ok(result.success, `Command failed: ${result.error}`); + + const config = readConfig(tmpDir); + assert.strictEqual(config.git.base_branch, 'master'); + }); + test('errors when no key path provided', () => { const result = runGsdTools('config-set', tmpDir); assert.strictEqual(result.success, false);