Merge pull request #934 from peterkc/fix/init-branch-persistence
fix(init): persist --branch flag to config.yaml
This commit is contained in:
@@ -287,24 +287,6 @@ With --stealth: configures per-repository git settings for invisible beads usage
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sync.branch only if explicitly specified via --branch flag
|
|
||||||
// GH#807: Do NOT auto-detect current branch - if sync.branch is set to main/master,
|
|
||||||
// the worktree created by bd sync will check out main, preventing the user from
|
|
||||||
// checking out main in their working directory (git error: "'main' is already checked out")
|
|
||||||
//
|
|
||||||
// When --branch is not specified, bd sync will commit directly to the current branch
|
|
||||||
// (the original behavior before sync branch feature)
|
|
||||||
if branch != "" {
|
|
||||||
if err := syncbranch.Set(ctx, store, branch); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error: failed to set sync branch: %v\n", err)
|
|
||||||
_ = store.Close()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if !quiet {
|
|
||||||
fmt.Printf(" Sync branch: %s\n", branch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === TRACKING METADATA (Pattern B: Warn and Continue) ===
|
// === TRACKING METADATA (Pattern B: Warn and Continue) ===
|
||||||
// Tracking metadata enhances functionality (diagnostics, version checks, collision detection)
|
// Tracking metadata enhances functionality (diagnostics, version checks, collision detection)
|
||||||
// but the system works without it. Failures here degrade gracefully - we warn but continue.
|
// but the system works without it. Failures here degrade gracefully - we warn but continue.
|
||||||
@@ -386,6 +368,27 @@ With --stealth: configures per-repository git settings for invisible beads usage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set sync.branch only if explicitly specified via --branch flag
|
||||||
|
// GH#807: Do NOT auto-detect current branch - if sync.branch is set to main/master,
|
||||||
|
// the worktree created by bd sync will check out main, preventing the user from
|
||||||
|
// checking out main in their working directory (git error: "'main' is already checked out")
|
||||||
|
//
|
||||||
|
// When --branch is not specified, bd sync will commit directly to the current branch
|
||||||
|
// (the original behavior before sync branch feature)
|
||||||
|
//
|
||||||
|
// GH#927: This must run AFTER createConfigYaml() so that config.yaml exists
|
||||||
|
// and syncbranch.Set() can update it via config.SetYamlConfig() (PR#910 mechanism)
|
||||||
|
if branch != "" {
|
||||||
|
if err := syncbranch.Set(ctx, store, branch); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: failed to set sync branch: %v\n", err)
|
||||||
|
_ = store.Close()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if !quiet {
|
||||||
|
fmt.Printf(" Sync branch: %s\n", branch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if git has existing issues to import (fresh clone scenario)
|
// Check if git has existing issues to import (fresh clone scenario)
|
||||||
// With --from-jsonl: import from local file instead of git history
|
// With --from-jsonl: import from local file instead of git history
|
||||||
if fromJSONL {
|
if fromJSONL {
|
||||||
|
|||||||
@@ -1138,6 +1138,114 @@ func TestSetupClaudeSettings_NoExistingFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestInitBranchPersistsToConfigYaml verifies that --branch flag persists to config.yaml
|
||||||
|
// GH#927 Bug 3: The --branch flag sets sync.branch in database but NOT in config.yaml.
|
||||||
|
// This matters because config.yaml is version-controlled and shared across clones,
|
||||||
|
// while the database is local and gitignored.
|
||||||
|
func TestInitBranchPersistsToConfigYaml(t *testing.T) {
|
||||||
|
// Reset global state
|
||||||
|
origDBPath := dbPath
|
||||||
|
defer func() { dbPath = origDBPath }()
|
||||||
|
dbPath = ""
|
||||||
|
|
||||||
|
// Reset Cobra flags
|
||||||
|
initCmd.Flags().Set("branch", "")
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
t.Chdir(tmpDir)
|
||||||
|
|
||||||
|
// Initialize git repo first (needed for sync branch)
|
||||||
|
if err := runCommandInDir(tmpDir, "git", "init", "--initial-branch=dev"); err != nil {
|
||||||
|
t.Fatalf("Failed to init git: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run bd init with --branch flag
|
||||||
|
rootCmd.SetArgs([]string{"init", "--prefix", "test", "--branch", "beads-sync", "--quiet"})
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
t.Fatalf("Init with --branch failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read config.yaml and verify sync-branch is uncommented
|
||||||
|
configPath := filepath.Join(tmpDir, ".beads", "config.yaml")
|
||||||
|
content, err := os.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to read config.yaml: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configStr := string(content)
|
||||||
|
|
||||||
|
// The bug: sync-branch remains commented as "# sync-branch:" instead of "sync-branch:"
|
||||||
|
// This test should FAIL on the current codebase to prove the bug exists
|
||||||
|
if strings.Contains(configStr, "# sync-branch:") && !strings.Contains(configStr, "\nsync-branch:") {
|
||||||
|
t.Errorf("BUG: --branch flag did not persist to config.yaml\n"+
|
||||||
|
"Expected uncommented 'sync-branch: \"beads-sync\"'\n"+
|
||||||
|
"Got commented '# sync-branch:' (only set in database, not config.yaml)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the uncommented line exists with correct value
|
||||||
|
if !strings.Contains(configStr, "sync-branch: \"beads-sync\"") {
|
||||||
|
t.Errorf("config.yaml should contain 'sync-branch: \"beads-sync\"', got:\n%s", configStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInitReinitWithBranch verifies that --branch flag works on reinit
|
||||||
|
// GH#927: When reinitializing with --branch, config.yaml should be updated even if it exists
|
||||||
|
func TestInitReinitWithBranch(t *testing.T) {
|
||||||
|
// Reset global state
|
||||||
|
origDBPath := dbPath
|
||||||
|
defer func() { dbPath = origDBPath }()
|
||||||
|
dbPath = ""
|
||||||
|
|
||||||
|
// Reset Cobra flags
|
||||||
|
initCmd.Flags().Set("branch", "")
|
||||||
|
initCmd.Flags().Set("force", "false")
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
t.Chdir(tmpDir)
|
||||||
|
|
||||||
|
// Initialize git repo first
|
||||||
|
if err := runCommandInDir(tmpDir, "git", "init", "--initial-branch=dev"); err != nil {
|
||||||
|
t.Fatalf("Failed to init git: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// First init WITHOUT --branch (creates config.yaml with commented sync-branch)
|
||||||
|
rootCmd.SetArgs([]string{"init", "--prefix", "test", "--quiet"})
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
t.Fatalf("First init failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify config.yaml has commented sync-branch initially
|
||||||
|
configPath := filepath.Join(tmpDir, ".beads", "config.yaml")
|
||||||
|
content, err := os.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to read config.yaml: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(content), "# sync-branch:") {
|
||||||
|
t.Errorf("Initial config.yaml should have commented sync-branch")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Cobra flags for reinit
|
||||||
|
initCmd.Flags().Set("branch", "")
|
||||||
|
initCmd.Flags().Set("force", "false")
|
||||||
|
|
||||||
|
// Reinit WITH --branch (should update existing config.yaml)
|
||||||
|
rootCmd.SetArgs([]string{"init", "--prefix", "test", "--branch", "beads-sync", "--force", "--quiet"})
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
t.Fatalf("Reinit with --branch failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify config.yaml now has uncommented sync-branch
|
||||||
|
content, err = os.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to read config.yaml after reinit: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configStr := string(content)
|
||||||
|
if !strings.Contains(configStr, "sync-branch: \"beads-sync\"") {
|
||||||
|
t.Errorf("After reinit with --branch, config.yaml should contain uncommented 'sync-branch: \"beads-sync\"', got:\n%s", configStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestSetupGlobalGitIgnore_ReadOnly verifies graceful handling when the
|
// TestSetupGlobalGitIgnore_ReadOnly verifies graceful handling when the
|
||||||
// gitignore file cannot be written (prints manual instructions instead of failing).
|
// gitignore file cannot be written (prints manual instructions instead of failing).
|
||||||
func TestSetupGlobalGitIgnore_ReadOnly(t *testing.T) {
|
func TestSetupGlobalGitIgnore_ReadOnly(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user