Skip to content

Commit cb387fd

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

File tree

3 files changed

+53
-10
lines changed

3 files changed

+53
-10
lines changed

lib/git/lib.rb

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

363+
BRANCH_LINE_REGEXP = /
364+
^
365+
# Prefix indicates if this branch is checked out. The prefix is one of:
366+
(?:
367+
(?<current>\*[[:blank:]]) | # Current branch (checked out in the current worktree)
368+
(?<worktree>\+[[:blank:]]) | # Branch checked out in a different worktree
369+
[[:blank:]]{2} # Branch not checked out
370+
)
371+
372+
# The branch's full refname
373+
(?<refname>[^[[:blank:]]]+)
374+
375+
# Optional symref
376+
# If this ref is a symbolic reference, this is the ref referenced
377+
(?:
378+
[[:blank:]]->[[:blank:]](?<symref>.*)
379+
)?
380+
$
381+
/x
382+
363383
def branches_all
364-
arr = []
365-
command_lines('branch', '-a').each do |b|
366-
current = (b[0, 2] == '* ')
367-
arr << [b.gsub('* ', '').strip, current]
384+
command_lines('branch', '--all').map do |line|
385+
match_data = line.match(BRANCH_LINE_REGEXP)
386+
raise GitExecuteError, 'Unexpected branch line format' unless match_data
387+
[
388+
match_data[:refname],
389+
!match_data[:current].nil?,
390+
!match_data[:worktree].nil?,
391+
match_data[:symref]
392+
]
368393
end
369-
arr
370394
end
371395

372396
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

tests/units/test_logger.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_logger
2828

2929
logc = File.read(log.path)
3030

31-
expected_log_entry = /INFO -- : \["git", "(?<global_options>.*?)", "branch", "-a"/
31+
expected_log_entry = /INFO -- : \["git", "(?<global_options>.*?)", "branch", "--all"/
3232
assert_match(expected_log_entry, logc, missing_log_entry)
3333

3434
expected_log_entry = /DEBUG -- : stdout:\n" cherry/
@@ -46,7 +46,7 @@ def test_logging_at_info_level_should_not_show_debug_messages
4646

4747
logc = File.read(log.path)
4848

49-
expected_log_entry = /INFO -- : \["git", "(?<global_options>.*?)", "branch", "-a"/
49+
expected_log_entry = /INFO -- : \["git", "(?<global_options>.*?)", "branch", "--all"/
5050
assert_match(expected_log_entry, logc, missing_log_entry)
5151

5252
expected_log_entry = /DEBUG -- : stdout:\n" cherry/

0 commit comments

Comments
 (0)