Skip to content

Commit f861c26

Browse files
committed
Fix parsing of symbolic refs in Git::Lib#branches_all
Signed-off-by: James Couball <jcouball@yahoo.com>
1 parent 7d8848c commit f861c26

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

lib/git/lib.rb

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,37 @@ def change_head_branch(branch_name)
347347
command('symbolic-ref', 'HEAD', "refs/heads/#{branch_name}")
348348
end
349349

350+
BRANCH_LINE_REGEXP = /
351+
^
352+
# Prefix indicates if this branch is checked out. The prefix is one of:
353+
(?:
354+
(?<current>\*[[:blank:]]) | # Current branch (checked out in the current worktree)
355+
(?<worktree>\+[[:blank:]]) | # Branch checked out in a different worktree
356+
[[:blank:]]{2} # Branch not checked out
357+
)
358+
359+
# The branch's full refname
360+
(?<refname>[^[[:blank:]]]+)
361+
362+
# Optional symref
363+
# If this ref is a symbolic reference, this is the ref referenced
364+
(?:
365+
[[:blank:]]->[[:blank:]](?<symref>.*)
366+
)?
367+
$
368+
/x
369+
350370
def branches_all
351-
arr = []
352-
command_lines('branch', '-a').each do |b|
353-
current = (b[0, 2] == '* ')
354-
arr << [b.gsub('* ', '').strip, current]
371+
command_lines('branch', '-a').map do |line|
372+
match_data = line.match(BRANCH_LINE_REGEXP)
373+
raise GitExecuteError, 'Unexpected branch line format' unless match_data
374+
[
375+
match_data[:refname],
376+
!match_data[:current].nil?,
377+
!match_data[:worktree].nil?,
378+
match_data[:symref]
379+
]
355380
end
356-
arr
357381
end
358382

359383
def worktrees_all

tests/units/test_branch.rb

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,28 @@ def setup
2626
end
2727
end
2828

29-
def test_branches_all
30-
assert(@git.branches[:master].is_a?(Git::Branch))
31-
assert(@git.branches.size > 5)
29+
test 'Git::Base#branches' do
30+
in_temp_dir do
31+
remote_git = Git.init('remote_git', initial_branch: 'master')
32+
File.write('remote_git/file.txt', 'hello world')
33+
remote_git.add('file.txt')
34+
remote_git.commit('Initial commit')
35+
remote_branches = remote_git.branches
36+
assert_equal(1, remote_branches.size)
37+
assert(remote_branches.first.current)
38+
assert_equal('master', remote_branches.first.name)
39+
40+
# Test that remote tracking branches are handled correctly
41+
#
42+
local_git = Git.clone('remote_git/.git', 'local_git')
43+
local_branches = assert_nothing_raised { local_git.branches }
44+
assert_equal(3, local_branches.size)
45+
assert(remote_branches.first.current)
46+
local_branch_refs = local_branches.map(&:full)
47+
assert_include(local_branch_refs, 'master')
48+
assert_include(local_branch_refs, 'remotes/origin/master')
49+
assert_include(local_branch_refs, 'remotes/origin/HEAD')
50+
end
3251
end
3352

3453
def test_branches_local

0 commit comments

Comments
 (0)