Merge bd-xoyh-morsov: GH#517
This commit is contained in:
19250
.beads/deletions.jsonl
19250
.beads/deletions.jsonl
File diff suppressed because it is too large
Load Diff
1802
.beads/issues.jsonl
1802
.beads/issues.jsonl
File diff suppressed because one or more lines are too long
@@ -392,12 +392,20 @@ Use --merge to merge the sync branch back to main branch.`,
|
|||||||
if err := ensureStoreActive(); err == nil && store != nil {
|
if err := ensureStoreActive(); err == nil && store != nil {
|
||||||
syncBranchName, _ = syncbranch.Get(ctx, store)
|
syncBranchName, _ = syncbranch.Get(ctx, store)
|
||||||
if syncBranchName != "" && syncbranch.HasGitRemote(ctx) {
|
if syncBranchName != "" && syncbranch.HasGitRemote(ctx) {
|
||||||
repoRoot, err = syncbranch.GetRepoRoot(ctx)
|
// GH#519: Check if sync.branch equals current branch
|
||||||
if err != nil {
|
// If so, we can't use a worktree (git doesn't allow same branch in multiple worktrees)
|
||||||
fmt.Fprintf(os.Stderr, "Warning: sync.branch configured but failed to get repo root: %v\n", err)
|
// Fall back to direct commits on the current branch
|
||||||
fmt.Fprintf(os.Stderr, "Falling back to current branch commits\n")
|
if syncbranch.IsSyncBranchSameAsCurrent(ctx, syncBranchName) {
|
||||||
|
// sync.branch == current branch - use regular commits, not worktree
|
||||||
|
useSyncBranch = false
|
||||||
} else {
|
} else {
|
||||||
useSyncBranch = true
|
repoRoot, err = syncbranch.GetRepoRoot(ctx)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Warning: sync.branch configured but failed to get repo root: %v\n", err)
|
||||||
|
fmt.Fprintf(os.Stderr, "Falling back to current branch commits\n")
|
||||||
|
} else {
|
||||||
|
useSyncBranch = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1061,3 +1061,25 @@ func HasGitRemote(ctx context.Context) bool {
|
|||||||
}
|
}
|
||||||
return len(strings.TrimSpace(string(output))) > 0
|
return len(strings.TrimSpace(string(output))) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCurrentBranch returns the name of the current git branch
|
||||||
|
func GetCurrentBranch(ctx context.Context) (string, error) {
|
||||||
|
cmd := exec.CommandContext(ctx, "git", "symbolic-ref", "--short", "HEAD")
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to get current branch: %w", err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(output)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSyncBranchSameAsCurrent returns true if the sync branch is the same as the current branch.
|
||||||
|
// This is used to detect the case where we can't use a worktree because the branch is already
|
||||||
|
// checked out. In this case, we should commit directly to the current branch instead.
|
||||||
|
// See: https://github.com/steveyegge/beads/issues/519
|
||||||
|
func IsSyncBranchSameAsCurrent(ctx context.Context, syncBranch string) bool {
|
||||||
|
currentBranch, err := GetCurrentBranch(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return currentBranch == syncBranch
|
||||||
|
}
|
||||||
|
|||||||
@@ -683,3 +683,70 @@ func TestCountIssuesInContent(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestIsSyncBranchSameAsCurrent tests detection of sync.branch == current branch (GH#519)
|
||||||
|
func TestIsSyncBranchSameAsCurrent(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("returns true when sync branch equals current branch", func(t *testing.T) {
|
||||||
|
repoDir := setupTestRepo(t)
|
||||||
|
defer os.RemoveAll(repoDir)
|
||||||
|
|
||||||
|
// Create initial commit so we can get current branch
|
||||||
|
writeFile(t, filepath.Join(repoDir, ".beads", "issues.jsonl"), `{"id":"test-1"}`)
|
||||||
|
runGit(t, repoDir, "add", ".")
|
||||||
|
runGit(t, repoDir, "commit", "-m", "initial commit")
|
||||||
|
|
||||||
|
// Get current branch name
|
||||||
|
currentBranch := strings.TrimSpace(getGitOutput(t, repoDir, "symbolic-ref", "--short", "HEAD"))
|
||||||
|
|
||||||
|
// Save original dir and change to test repo
|
||||||
|
origDir, _ := os.Getwd()
|
||||||
|
os.Chdir(repoDir)
|
||||||
|
defer os.Chdir(origDir)
|
||||||
|
|
||||||
|
// Should return true when sync branch == current branch
|
||||||
|
if !IsSyncBranchSameAsCurrent(ctx, currentBranch) {
|
||||||
|
t.Errorf("IsSyncBranchSameAsCurrent(%q) = false, want true", currentBranch)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("returns false when sync branch differs from current branch", func(t *testing.T) {
|
||||||
|
repoDir := setupTestRepo(t)
|
||||||
|
defer os.RemoveAll(repoDir)
|
||||||
|
|
||||||
|
// Create initial commit
|
||||||
|
writeFile(t, filepath.Join(repoDir, ".beads", "issues.jsonl"), `{"id":"test-1"}`)
|
||||||
|
runGit(t, repoDir, "add", ".")
|
||||||
|
runGit(t, repoDir, "commit", "-m", "initial commit")
|
||||||
|
|
||||||
|
// Save original dir and change to test repo
|
||||||
|
origDir, _ := os.Getwd()
|
||||||
|
os.Chdir(repoDir)
|
||||||
|
defer os.Chdir(origDir)
|
||||||
|
|
||||||
|
// Should return false when sync branch != current branch
|
||||||
|
if IsSyncBranchSameAsCurrent(ctx, "beads-sync") {
|
||||||
|
t.Error("IsSyncBranchSameAsCurrent(\"beads-sync\") = true, want false")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("returns false on error getting current branch", func(t *testing.T) {
|
||||||
|
// Test in a non-git directory
|
||||||
|
tmpDir, _ := os.MkdirTemp("", "non-git-*")
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
origDir, _ := os.Getwd()
|
||||||
|
os.Chdir(tmpDir)
|
||||||
|
defer os.Chdir(origDir)
|
||||||
|
|
||||||
|
// Should return false when not in a git repo
|
||||||
|
if IsSyncBranchSameAsCurrent(ctx, "any-branch") {
|
||||||
|
t.Error("IsSyncBranchSameAsCurrent in non-git dir = true, want false")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func ParseIssueType(content string) (types.IssueType, error) {
|
|||||||
func ValidatePriority(priorityStr string) (int, error) {
|
func ValidatePriority(priorityStr string) (int, error) {
|
||||||
priority := ParsePriority(priorityStr)
|
priority := ParsePriority(priorityStr)
|
||||||
if priority == -1 {
|
if priority == -1 {
|
||||||
return -1, fmt.Errorf("invalid priority %q (expected 0-4 or P0-P4)", priorityStr)
|
return -1, fmt.Errorf("invalid priority %q (expected 0-4 or P0-P4, not words like high/medium/low)", priorityStr)
|
||||||
}
|
}
|
||||||
return priority, nil
|
return priority, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user