Module: Git::Parsers::Branch Private
- Defined in:
- lib/git/parsers/branch.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Parser for git branch command output
Handles parsing of git branch --list and git branch --delete output
into structured data objects.
Design Note: Namespace Organization
This parser creates and returns BranchInfo and BranchDeleteResult
objects, which live at the top-level Git:: namespace rather than within
Git::Parsers::. This is intentional:
- Parsers are infrastructure - marked
@api private, users shouldn't interact with them directly - Info/Result classes are public API - returned by commands and used throughout the codebase
- Info classes are domain entities - represent core git concepts (branches as data)
- Result classes are operation outcomes - represent command results, not parsing details
Keeping Info/Result classes at Git:: improves discoverability and correctly
reflects their role as public types rather than parser internals.
Constant Summary collapse
- FORMAT_STRING =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Format string for git branch --format
Fields (null-delimited):
- refname - full ref name (e.g., refs/heads/main, refs/remotes/origin/main)
- objectname - full SHA of the commit the branch points to
- HEAD - '*' if current branch, empty otherwise
- worktreepath - path if checked out in another worktree, empty otherwise
- symref - target ref if symbolic reference, empty otherwise
- upstream - full upstream ref (e.g., refs/remotes/origin/main), empty if none
Null bytes (%00) are used as field delimiters so that worktree paths containing special characters (including '|') parse correctly.
'%(refname)%00%(objectname)%00%(HEAD)%00%(worktreepath)%00%(symref)%00%(upstream)'- FIELD_DELIMITER =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Delimiter used in format output
"\0"- DELETED_BRANCH_REGEX =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Regex to parse successful deletion lines from stdout Matches: Deleted branch branchname (was abc123). Matches: Deleted remote-tracking branch origin/branchname (was abc123). Uses non-greedy match to capture branch names containing spaces
/^Deleted (?:remote-tracking )?branch (.+?) \(was/- ERROR_BRANCH_REGEX =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Regex to parse error messages from stderr Matches: error: branch 'branchname' not found.
/^error: branch '([^']+)'(.*)$/
Class Method Summary collapse
-
.build_branch_info(fields, remote_names: []) ⇒ Git::BranchInfo
private
Build a BranchInfo from parsed fields.
-
.build_delete_result(requested_names, existing_branches, deleted_names, error_map) ⇒ Git::BranchDeleteResult
private
Build the BranchDeleteResult from parsed data.
-
.build_upstream_info(upstream_ref) ⇒ String?
private
Return the raw upstream refname string, or nil if empty.
-
.non_branch_entry?(refname) ⇒ Boolean
private
Check if the refname represents a detached HEAD state or non-branch entry.
-
.parse_branch_line(line, remote_names: []) ⇒ Git::BranchInfo?
private
Parse a single formatted branch line.
-
.parse_deleted_branches(stdout) ⇒ Array<String>
private
Parse deleted branch names from stdout.
-
.parse_error_messages(stderr) ⇒ Hash<String, String>
private
Parse error messages from stderr into a map.
-
.parse_list(stdout, remote_names: []) ⇒ Array<Git::BranchInfo>
private
Parse git branch --list output into BranchInfo objects.
-
.presence(value) ⇒ String?
private
Return value if non-empty, nil otherwise.
-
.resolve_remote_name(refname, remote_names) ⇒ String?
private
Resolve a remote-tracking refname to a configured remote name.
Class Method Details
.build_branch_info(fields, remote_names: []) ⇒ Git::BranchInfo
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Build a BranchInfo from parsed fields
117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/git/parsers/branch.rb', line 117 def build_branch_info(fields, remote_names: []) raw_refname, objectname, head, worktreepath, symref, upstream = fields Git::BranchInfo.new( refname: raw_refname, target_oid: presence(objectname), current: head == '*', worktree_path: head == '*' ? nil : presence(worktreepath), symref: presence(symref), upstream: build_upstream_info(upstream), remote_name: resolve_remote_name(raw_refname, remote_names) ) end |
.build_delete_result(requested_names, existing_branches, deleted_names, error_map) ⇒ Git::BranchDeleteResult
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Build the BranchDeleteResult from parsed data
228 229 230 231 232 233 234 235 236 237 |
# File 'lib/git/parsers/branch.rb', line 228 def build_delete_result(requested_names, existing_branches, deleted_names, error_map) deleted = deleted_names.filter_map { |name| existing_branches[name] } not_deleted = (requested_names - deleted_names).map do |name| = error_map[name] || "branch '#{name}' could not be deleted" Git::BranchDeleteFailure.new(name: name, error_message: ) end Git::BranchDeleteResult.new(deleted: deleted, not_deleted: not_deleted) end |
.build_upstream_info(upstream_ref) ⇒ String?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return the raw upstream refname string, or nil if empty
169 170 171 172 173 |
# File 'lib/git/parsers/branch.rb', line 169 def build_upstream_info(upstream_ref) return nil if upstream_ref.nil? || upstream_ref.empty? upstream_ref end |
.non_branch_entry?(refname) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Check if the refname represents a detached HEAD state or non-branch entry
Git outputs special entries for detached HEAD and non-branch states:
- "(HEAD detached at )" when in detached HEAD state
- "(not a branch)" for non-branch entries
159 160 161 |
# File 'lib/git/parsers/branch.rb', line 159 def non_branch_entry?(refname) refname.match?(/^\(HEAD detached/) || refname.match?(/^\(not a branch\)/) end |
.parse_branch_line(line, remote_names: []) ⇒ Git::BranchInfo?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse a single formatted branch line
99 100 101 102 103 104 105 |
# File 'lib/git/parsers/branch.rb', line 99 def parse_branch_line(line, remote_names: []) fields = line.split(FIELD_DELIMITER, 6) return nil if non_branch_entry?(fields[0]) build_branch_info(fields, remote_names: remote_names) end |
.parse_deleted_branches(stdout) ⇒ Array<String>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse deleted branch names from stdout
195 196 197 |
# File 'lib/git/parsers/branch.rb', line 195 def parse_deleted_branches(stdout) stdout.scan(DELETED_BRANCH_REGEX).flatten end |
.parse_error_messages(stderr) ⇒ Hash<String, String>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse error messages from stderr into a map
209 210 211 212 213 214 |
# File 'lib/git/parsers/branch.rb', line 209 def (stderr) stderr.each_line.with_object({}) do |line, hash| match = line.match(ERROR_BRANCH_REGEX) hash[match[1]] = line.strip if match end end |
.parse_list(stdout, remote_names: []) ⇒ Array<Git::BranchInfo>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse git branch --list output into BranchInfo objects
86 87 88 |
# File 'lib/git/parsers/branch.rb', line 86 def parse_list(stdout, remote_names: []) stdout.split("\n").filter_map { |line| parse_branch_line(line, remote_names: remote_names) } end |
.presence(value) ⇒ String?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return value if non-empty, nil otherwise
181 182 183 |
# File 'lib/git/parsers/branch.rb', line 181 def presence(value) value.nil? || value.empty? ? nil : value end |
.resolve_remote_name(refname, remote_names) ⇒ String?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Resolve a remote-tracking refname to a configured remote name
138 139 140 141 142 143 144 145 146 147 |
# File 'lib/git/parsers/branch.rb', line 138 def resolve_remote_name(refname, remote_names) remote_path = refname[%r{\A(?:refs/)?remotes/(.+)\z}, 1] return nil if remote_path.nil? configured_remote_name = remote_names .select { |remote_name| remote_path.start_with?("#{remote_name}/") } .max_by(&:length) configured_remote_name || Git::BranchInfo.fallback_remote_name(refname) end |