Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 75 additions & 2 deletions lib/git/branch_shortcuts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,84 @@ function _scmb_git_branch_shortcuts {
# Use ruby to inject numbers into git branch output
ruby -e "$(
cat <<EOF
def build_worktree_to_branch_map(git_cmd)
worktree_map = {}
worktree_output = %x(#{git_cmd} worktree list --porcelain 2>/dev/null)
current_worktree = nil
worktree_output.lines.each do |line|
if line.start_with?('worktree ')
current_worktree = line[9..-1].strip
elsif line.start_with?('branch refs/heads/') && current_worktree
branch_name = line[18..-1].strip
worktree_map[branch_name] = current_worktree
current_worktree = nil
end
end
worktree_map
Comment on lines +26 to +39

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Handle detached-current-worktree cases when deciding to show paths.

show_worktrees is keyed off worktree_map.size, which only counts worktrees that have a branch line. If the current worktree is detached and there is only one other worktree branch, paths won’t be shown even though worktrees are in use. Consider tracking the total number of worktrees from git worktree list --porcelain and use that to gate show_worktrees.

🔧 Suggested fix
     def build_worktree_to_branch_map(git_cmd)
       worktree_map = {}
       worktree_output = %x(#{git_cmd} worktree list --porcelain 2>/dev/null)
+      worktree_count = 0
       current_worktree = nil
       worktree_output.lines.each do |line|
         if line.start_with?('worktree ')
+          worktree_count += 1
           current_worktree = line[9..-1].strip
         elsif line.start_with?('branch refs/heads/') && current_worktree
           branch_name = line[18..-1].strip
           worktree_map[branch_name] = current_worktree
           current_worktree = nil
         end
       end
-      worktree_map
+      [worktree_map, worktree_count]
     end
@@
-    worktree_map = build_worktree_to_branch_map('$_git_cmd')
+    worktree_map, worktree_count = build_worktree_to_branch_map('$_git_cmd')
@@
-    show_worktrees = worktree_map.size > 1
+    show_worktrees = worktree_count > 1

Also applies to: 91-96

🤖 Prompt for AI Agents
In `@lib/git/branch_shortcuts.sh` around lines 26 - 39, The
build_worktree_to_branch_map function currently only records worktrees that have
a branch line (worktree_map), so detached current worktrees are ignored; update
this routine to also count total worktrees discovered from git worktree list
--porcelain (e.g., increment a total_worktrees counter whenever you see a
"worktree " line) and return that count alongside worktree_map (or expose it via
a renamed return like [worktree_map, total_worktrees]) so callers (where
show_worktrees is decided) can use total_worktrees instead of worktree_map.size
to decide whether to show paths; keep using the existing variables
(worktree_output, current_worktree, worktree_map) and only add a total counter
and the corresponding return change so callers at the other usage sites (lines
~91-96) can be updated to read the new count.

end

def extract_branch_name(line)
line.strip.gsub(/^\*\s+|^\+\s+|\s+/, '').gsub(/\e\[[0-9;]*m/, '')
end

def strip_ansi_codes(str)
str.gsub(/\e\[[0-9;]*m/, '')
end

def find_current_branch(output)
output.lines.each do |line|
return extract_branch_name(line) if line.start_with?('* ')
end
nil
end

def calculate_max_branch_width(output, line_count, current_branch, worktree_map)
max_width = 0
output.lines.each_with_index do |line, i|
branch_name = extract_branch_name(line)

if worktree_map[branch_name] && branch_name != current_branch
# Add extra space for single-digit numbers when we have 10+ branches
number_spacing = (line_count > 9 && i < 9) ? ' ' : ' '
numbered_line = line.sub(/^([ *+]{2})/, "\\\1\033[2;37m[\033[0m#{i+1}\033[2;37m]\033[0m" << number_spacing)
width = strip_ansi_codes(numbered_line.chomp).length
max_width = width if width > max_width
end
end
max_width
end

def format_branch_line(line, index, line_count, branch_name, current_branch, worktree_map, max_width, show_worktrees)
# Add extra space for single-digit numbers when we have 10+ branches
number_spacing = (line_count > 9 && index < 9) ? ' ' : ' '

# Insert branch number after the leading marker (* or +)
formatted = line.sub(/^([ *+]{2})/, "\\\1\033[2;37m[\033[0m#{index+1}\033[2;37m]\033[0m" << number_spacing)

# Append worktree path if we have multiple worktrees and this isn't the current branch
if show_worktrees && worktree_map[branch_name] && branch_name != current_branch
current_width = strip_ansi_codes(formatted.chomp).length
padding = ' ' * (max_width - current_width)
formatted = formatted.chomp + padding + " \033[2;37m(#{worktree_map[branch_name]})\033[0m\n"
end

formatted
end

output = %x($_git_cmd branch --color=always $(token_quote "$@"))
worktree_map = build_worktree_to_branch_map('$_git_cmd')
line_count = output.lines.to_a.size
current_branch = find_current_branch(output)

show_worktrees = worktree_map.size > 1

# Align the parenthesis in worktree output
max_width = show_worktrees ? calculate_max_branch_width(output, line_count, current_branch, worktree_map) : 0

output.lines.each_with_index do |line, i|
spaces = (line_count > 9 && i < 9 ? " " : " ")
puts line.sub(/^([ *+]{2})/, "\\\1\033[2;37m[\033[0m#{i+1}\033[2;37m]\033[0m" << spaces)
branch_name = extract_branch_name(line)
formatted_line = format_branch_line(line, i, line_count, branch_name, current_branch, worktree_map, max_width, show_worktrees)
puts formatted_line
end
EOF
)"
Expand Down