Class: Git::BranchInfo
- Inherits:
-
Data
- Object
- Data
- Git::BranchInfo
- Defined in:
- lib/git/branch_info.rb
Overview
Value object representing branch metadata from git branch output
This is a lightweight, immutable data structure returned by branch listing commands. It contains only the data parsed from git output without any repository context or operations.
Instance Attribute Summary collapse
-
#current ⇒ Boolean
readonly
Whether this branch is currently checked out in the current worktree.
-
#refname ⇒ String
readonly
The full reference name of the branch.
-
#remote_name ⇒ String?
readonly
The resolved or fallback-derived remote name, or nil for local branches.
-
#symref ⇒ String?
readonly
The target reference if this is a symbolic reference.
-
#target_oid ⇒ String?
readonly
The commit object ID (SHA) that this branch points to (aka HEAD).
-
#upstream ⇒ String?
readonly
The configured upstream/tracking branch refname as reported by git.
-
#worktree_path ⇒ String?
readonly
The absolute path of the other linked worktree this branch is checked out in, or nil.
Class Method Summary collapse
-
.fallback_remote_name(refname) ⇒ String?
The regex-derived remote name, or nil for local branches.
-
.remote_tracking_refname?(refname) ⇒ Boolean
True if the refname is a remote-tracking refname.
- .validate_remote_name!(refname, remote_name)
Instance Method Summary collapse
-
#current? ⇒ Boolean
True if this is the currently checked out branch.
-
#detached? ⇒ Boolean
Always false for BranchInfo (see DetachedHeadInfo for detached state).
-
#initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, remote_name: REMOTE_NAME_NOT_GIVEN) ⇒ BranchInfo
constructor
A new instance of BranchInfo.
-
#other_worktree? ⇒ Boolean
True if this branch is checked out in another linked worktree.
-
#remote? ⇒ Boolean
True if this is a remote-tracking branch.
-
#short_name ⇒ String
The short branch name without any remote or heads prefix (e.g., 'main' or 'feature/foo').
-
#symref? ⇒ Boolean
True if this is a symbolic reference.
-
#to_s ⇒ String
String representation (the full refname).
-
#unborn? ⇒ Boolean
True if this is an unborn branch (no commits yet).
Constructor Details
#initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, remote_name: REMOTE_NAME_NOT_GIVEN) ⇒ BranchInfo
Returns a new instance of BranchInfo.
165 166 167 168 169 170 171 |
# File 'lib/git/branch_info.rb', line 165 def initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, # rubocop:disable Metrics/ParameterLists remote_name: REMOTE_NAME_NOT_GIVEN) remote_name = self.class.fallback_remote_name(refname) if remote_name.equal?(REMOTE_NAME_NOT_GIVEN) self.class.validate_remote_name!(refname, remote_name) super end |
Instance Attribute Details
#current ⇒ Boolean (readonly)
A branch can be current (#current? true) or in another worktree (#other_worktree? true), but never both. A branch not checked out anywhere has both false.
Whether this branch is currently checked out in the current worktree
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/git/branch_info.rb', line 149 BranchInfo = Data.define(:refname, :remote_name, :target_oid, :current, :worktree_path, :symref, :upstream) do # @param refname [String] the full branch refname # # @param remote_name [String, nil] resolved remote name, nil for local branches, # or omitted to derive from `refname` # # @param target_oid [String, nil] the commit object ID, or nil for unborn branches # # @param current [Boolean] whether this branch is currently checked out # # @param worktree_path [String, nil] path to another linked worktree, or nil # # @param symref [String, nil] symbolic reference target, or nil # # @param upstream [String, nil] upstream refname, or nil # def initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, # rubocop:disable Metrics/ParameterLists remote_name: REMOTE_NAME_NOT_GIVEN) remote_name = self.class.fallback_remote_name(refname) if remote_name.equal?(REMOTE_NAME_NOT_GIVEN) self.class.validate_remote_name!(refname, remote_name) super end # @param refname [String] the branch refname to validate # # @param remote_name [String, nil] the remote name to validate # # @return [void] # # @raise [ArgumentError] if the remote name contradicts the refname type def self.validate_remote_name!(refname, remote_name) if remote_tracking_refname?(refname) unless remote_name.is_a?(String) && !remote_name.empty? raise ArgumentError, 'remote_name must be a non-empty String for remote-tracking refname' end remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} raise ArgumentError, 'remote_name must match remote-tracking refname' unless refname.match?(remote_ref_prefix) elsif !remote_name.nil? raise ArgumentError, 'remote_name must be nil for local branch refname' end end # @param refname [String] the branch refname to parse # # @return [String, nil] the regex-derived remote name, or nil for local branches def self.fallback_remote_name(refname) refname.match(Git::BRANCH_REFNAME_REGEXP)[:remote_name] end # @param refname [String] the branch refname to inspect # # @return [Boolean] true if the refname is a remote-tracking refname def self.remote_tracking_refname?(refname) refname.match?(%r{\A(?:refs/)?remotes/[^/]+/.+}) end # @return [Boolean] always false for BranchInfo (see DetachedHeadInfo for detached state) def detached? = false # @return [Boolean] true if this is an unborn branch (no commits yet) def unborn? = target_oid.nil? # @return [String] the short branch name without any remote or heads prefix # (e.g., 'main' or 'feature/foo') def short_name return refname.delete_prefix('refs/heads/') if remote_name.nil? remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} refname.sub(remote_ref_prefix, '') end # @return [Boolean] true if this is the currently checked out branch def current? = current # @return [Boolean] true if this branch is checked out in another linked worktree def other_worktree? = !worktree_path.nil? # @return [Boolean] true if this is a symbolic reference def symref? = !symref.nil? # @return [Boolean] true if this is a remote-tracking branch def remote? = !remote_name.nil? # @return [String] string representation (the full refname) def to_s = refname end |
#refname ⇒ String (readonly)
The full reference name of the branch
Must be the full refname as returned by git (e.g., 'refs/heads/main', 'refs/remotes/origin/main') because the short name alone is not guaranteed to be unique (e.g., 'main' could exist as both a local and remote branch).
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/git/branch_info.rb', line 149 BranchInfo = Data.define(:refname, :remote_name, :target_oid, :current, :worktree_path, :symref, :upstream) do # @param refname [String] the full branch refname # # @param remote_name [String, nil] resolved remote name, nil for local branches, # or omitted to derive from `refname` # # @param target_oid [String, nil] the commit object ID, or nil for unborn branches # # @param current [Boolean] whether this branch is currently checked out # # @param worktree_path [String, nil] path to another linked worktree, or nil # # @param symref [String, nil] symbolic reference target, or nil # # @param upstream [String, nil] upstream refname, or nil # def initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, # rubocop:disable Metrics/ParameterLists remote_name: REMOTE_NAME_NOT_GIVEN) remote_name = self.class.fallback_remote_name(refname) if remote_name.equal?(REMOTE_NAME_NOT_GIVEN) self.class.validate_remote_name!(refname, remote_name) super end # @param refname [String] the branch refname to validate # # @param remote_name [String, nil] the remote name to validate # # @return [void] # # @raise [ArgumentError] if the remote name contradicts the refname type def self.validate_remote_name!(refname, remote_name) if remote_tracking_refname?(refname) unless remote_name.is_a?(String) && !remote_name.empty? raise ArgumentError, 'remote_name must be a non-empty String for remote-tracking refname' end remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} raise ArgumentError, 'remote_name must match remote-tracking refname' unless refname.match?(remote_ref_prefix) elsif !remote_name.nil? raise ArgumentError, 'remote_name must be nil for local branch refname' end end # @param refname [String] the branch refname to parse # # @return [String, nil] the regex-derived remote name, or nil for local branches def self.fallback_remote_name(refname) refname.match(Git::BRANCH_REFNAME_REGEXP)[:remote_name] end # @param refname [String] the branch refname to inspect # # @return [Boolean] true if the refname is a remote-tracking refname def self.remote_tracking_refname?(refname) refname.match?(%r{\A(?:refs/)?remotes/[^/]+/.+}) end # @return [Boolean] always false for BranchInfo (see DetachedHeadInfo for detached state) def detached? = false # @return [Boolean] true if this is an unborn branch (no commits yet) def unborn? = target_oid.nil? # @return [String] the short branch name without any remote or heads prefix # (e.g., 'main' or 'feature/foo') def short_name return refname.delete_prefix('refs/heads/') if remote_name.nil? remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} refname.sub(remote_ref_prefix, '') end # @return [Boolean] true if this is the currently checked out branch def current? = current # @return [Boolean] true if this branch is checked out in another linked worktree def other_worktree? = !worktree_path.nil? # @return [Boolean] true if this is a symbolic reference def symref? = !symref.nil? # @return [Boolean] true if this is a remote-tracking branch def remote? = !remote_name.nil? # @return [String] string representation (the full refname) def to_s = refname end |
#remote_name ⇒ String? (readonly)
Returns the resolved or fallback-derived remote name, or nil for local branches.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/git/branch_info.rb', line 149 BranchInfo = Data.define(:refname, :remote_name, :target_oid, :current, :worktree_path, :symref, :upstream) do # @param refname [String] the full branch refname # # @param remote_name [String, nil] resolved remote name, nil for local branches, # or omitted to derive from `refname` # # @param target_oid [String, nil] the commit object ID, or nil for unborn branches # # @param current [Boolean] whether this branch is currently checked out # # @param worktree_path [String, nil] path to another linked worktree, or nil # # @param symref [String, nil] symbolic reference target, or nil # # @param upstream [String, nil] upstream refname, or nil # def initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, # rubocop:disable Metrics/ParameterLists remote_name: REMOTE_NAME_NOT_GIVEN) remote_name = self.class.fallback_remote_name(refname) if remote_name.equal?(REMOTE_NAME_NOT_GIVEN) self.class.validate_remote_name!(refname, remote_name) super end # @param refname [String] the branch refname to validate # # @param remote_name [String, nil] the remote name to validate # # @return [void] # # @raise [ArgumentError] if the remote name contradicts the refname type def self.validate_remote_name!(refname, remote_name) if remote_tracking_refname?(refname) unless remote_name.is_a?(String) && !remote_name.empty? raise ArgumentError, 'remote_name must be a non-empty String for remote-tracking refname' end remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} raise ArgumentError, 'remote_name must match remote-tracking refname' unless refname.match?(remote_ref_prefix) elsif !remote_name.nil? raise ArgumentError, 'remote_name must be nil for local branch refname' end end # @param refname [String] the branch refname to parse # # @return [String, nil] the regex-derived remote name, or nil for local branches def self.fallback_remote_name(refname) refname.match(Git::BRANCH_REFNAME_REGEXP)[:remote_name] end # @param refname [String] the branch refname to inspect # # @return [Boolean] true if the refname is a remote-tracking refname def self.remote_tracking_refname?(refname) refname.match?(%r{\A(?:refs/)?remotes/[^/]+/.+}) end # @return [Boolean] always false for BranchInfo (see DetachedHeadInfo for detached state) def detached? = false # @return [Boolean] true if this is an unborn branch (no commits yet) def unborn? = target_oid.nil? # @return [String] the short branch name without any remote or heads prefix # (e.g., 'main' or 'feature/foo') def short_name return refname.delete_prefix('refs/heads/') if remote_name.nil? remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} refname.sub(remote_ref_prefix, '') end # @return [Boolean] true if this is the currently checked out branch def current? = current # @return [Boolean] true if this branch is checked out in another linked worktree def other_worktree? = !worktree_path.nil? # @return [Boolean] true if this is a symbolic reference def symref? = !symref.nil? # @return [Boolean] true if this is a remote-tracking branch def remote? = !remote_name.nil? # @return [String] string representation (the full refname) def to_s = refname end |
#symref ⇒ String? (readonly)
The target reference if this is a symbolic reference
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/git/branch_info.rb', line 149 BranchInfo = Data.define(:refname, :remote_name, :target_oid, :current, :worktree_path, :symref, :upstream) do # @param refname [String] the full branch refname # # @param remote_name [String, nil] resolved remote name, nil for local branches, # or omitted to derive from `refname` # # @param target_oid [String, nil] the commit object ID, or nil for unborn branches # # @param current [Boolean] whether this branch is currently checked out # # @param worktree_path [String, nil] path to another linked worktree, or nil # # @param symref [String, nil] symbolic reference target, or nil # # @param upstream [String, nil] upstream refname, or nil # def initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, # rubocop:disable Metrics/ParameterLists remote_name: REMOTE_NAME_NOT_GIVEN) remote_name = self.class.fallback_remote_name(refname) if remote_name.equal?(REMOTE_NAME_NOT_GIVEN) self.class.validate_remote_name!(refname, remote_name) super end # @param refname [String] the branch refname to validate # # @param remote_name [String, nil] the remote name to validate # # @return [void] # # @raise [ArgumentError] if the remote name contradicts the refname type def self.validate_remote_name!(refname, remote_name) if remote_tracking_refname?(refname) unless remote_name.is_a?(String) && !remote_name.empty? raise ArgumentError, 'remote_name must be a non-empty String for remote-tracking refname' end remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} raise ArgumentError, 'remote_name must match remote-tracking refname' unless refname.match?(remote_ref_prefix) elsif !remote_name.nil? raise ArgumentError, 'remote_name must be nil for local branch refname' end end # @param refname [String] the branch refname to parse # # @return [String, nil] the regex-derived remote name, or nil for local branches def self.fallback_remote_name(refname) refname.match(Git::BRANCH_REFNAME_REGEXP)[:remote_name] end # @param refname [String] the branch refname to inspect # # @return [Boolean] true if the refname is a remote-tracking refname def self.remote_tracking_refname?(refname) refname.match?(%r{\A(?:refs/)?remotes/[^/]+/.+}) end # @return [Boolean] always false for BranchInfo (see DetachedHeadInfo for detached state) def detached? = false # @return [Boolean] true if this is an unborn branch (no commits yet) def unborn? = target_oid.nil? # @return [String] the short branch name without any remote or heads prefix # (e.g., 'main' or 'feature/foo') def short_name return refname.delete_prefix('refs/heads/') if remote_name.nil? remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} refname.sub(remote_ref_prefix, '') end # @return [Boolean] true if this is the currently checked out branch def current? = current # @return [Boolean] true if this branch is checked out in another linked worktree def other_worktree? = !worktree_path.nil? # @return [Boolean] true if this is a symbolic reference def symref? = !symref.nil? # @return [Boolean] true if this is a remote-tracking branch def remote? = !remote_name.nil? # @return [String] string representation (the full refname) def to_s = refname end |
#target_oid ⇒ String? (readonly)
The commit object ID (SHA) that this branch points to (aka HEAD)
unborn (no commits yet)
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/git/branch_info.rb', line 149 BranchInfo = Data.define(:refname, :remote_name, :target_oid, :current, :worktree_path, :symref, :upstream) do # @param refname [String] the full branch refname # # @param remote_name [String, nil] resolved remote name, nil for local branches, # or omitted to derive from `refname` # # @param target_oid [String, nil] the commit object ID, or nil for unborn branches # # @param current [Boolean] whether this branch is currently checked out # # @param worktree_path [String, nil] path to another linked worktree, or nil # # @param symref [String, nil] symbolic reference target, or nil # # @param upstream [String, nil] upstream refname, or nil # def initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, # rubocop:disable Metrics/ParameterLists remote_name: REMOTE_NAME_NOT_GIVEN) remote_name = self.class.fallback_remote_name(refname) if remote_name.equal?(REMOTE_NAME_NOT_GIVEN) self.class.validate_remote_name!(refname, remote_name) super end # @param refname [String] the branch refname to validate # # @param remote_name [String, nil] the remote name to validate # # @return [void] # # @raise [ArgumentError] if the remote name contradicts the refname type def self.validate_remote_name!(refname, remote_name) if remote_tracking_refname?(refname) unless remote_name.is_a?(String) && !remote_name.empty? raise ArgumentError, 'remote_name must be a non-empty String for remote-tracking refname' end remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} raise ArgumentError, 'remote_name must match remote-tracking refname' unless refname.match?(remote_ref_prefix) elsif !remote_name.nil? raise ArgumentError, 'remote_name must be nil for local branch refname' end end # @param refname [String] the branch refname to parse # # @return [String, nil] the regex-derived remote name, or nil for local branches def self.fallback_remote_name(refname) refname.match(Git::BRANCH_REFNAME_REGEXP)[:remote_name] end # @param refname [String] the branch refname to inspect # # @return [Boolean] true if the refname is a remote-tracking refname def self.remote_tracking_refname?(refname) refname.match?(%r{\A(?:refs/)?remotes/[^/]+/.+}) end # @return [Boolean] always false for BranchInfo (see DetachedHeadInfo for detached state) def detached? = false # @return [Boolean] true if this is an unborn branch (no commits yet) def unborn? = target_oid.nil? # @return [String] the short branch name without any remote or heads prefix # (e.g., 'main' or 'feature/foo') def short_name return refname.delete_prefix('refs/heads/') if remote_name.nil? remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} refname.sub(remote_ref_prefix, '') end # @return [Boolean] true if this is the currently checked out branch def current? = current # @return [Boolean] true if this branch is checked out in another linked worktree def other_worktree? = !worktree_path.nil? # @return [Boolean] true if this is a symbolic reference def symref? = !symref.nil? # @return [Boolean] true if this is a remote-tracking branch def remote? = !remote_name.nil? # @return [String] string representation (the full refname) def to_s = refname end |
#upstream ⇒ String? (readonly)
Remote-tracking branches (e.g., 'refs/remotes/origin/main') have upstream: nil
This is the raw refname snapshot from when the branch list was read. It does not reflect live git state after the snapshot was taken.
The configured upstream/tracking branch refname as reported by git
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/git/branch_info.rb', line 149 BranchInfo = Data.define(:refname, :remote_name, :target_oid, :current, :worktree_path, :symref, :upstream) do # @param refname [String] the full branch refname # # @param remote_name [String, nil] resolved remote name, nil for local branches, # or omitted to derive from `refname` # # @param target_oid [String, nil] the commit object ID, or nil for unborn branches # # @param current [Boolean] whether this branch is currently checked out # # @param worktree_path [String, nil] path to another linked worktree, or nil # # @param symref [String, nil] symbolic reference target, or nil # # @param upstream [String, nil] upstream refname, or nil # def initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, # rubocop:disable Metrics/ParameterLists remote_name: REMOTE_NAME_NOT_GIVEN) remote_name = self.class.fallback_remote_name(refname) if remote_name.equal?(REMOTE_NAME_NOT_GIVEN) self.class.validate_remote_name!(refname, remote_name) super end # @param refname [String] the branch refname to validate # # @param remote_name [String, nil] the remote name to validate # # @return [void] # # @raise [ArgumentError] if the remote name contradicts the refname type def self.validate_remote_name!(refname, remote_name) if remote_tracking_refname?(refname) unless remote_name.is_a?(String) && !remote_name.empty? raise ArgumentError, 'remote_name must be a non-empty String for remote-tracking refname' end remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} raise ArgumentError, 'remote_name must match remote-tracking refname' unless refname.match?(remote_ref_prefix) elsif !remote_name.nil? raise ArgumentError, 'remote_name must be nil for local branch refname' end end # @param refname [String] the branch refname to parse # # @return [String, nil] the regex-derived remote name, or nil for local branches def self.fallback_remote_name(refname) refname.match(Git::BRANCH_REFNAME_REGEXP)[:remote_name] end # @param refname [String] the branch refname to inspect # # @return [Boolean] true if the refname is a remote-tracking refname def self.remote_tracking_refname?(refname) refname.match?(%r{\A(?:refs/)?remotes/[^/]+/.+}) end # @return [Boolean] always false for BranchInfo (see DetachedHeadInfo for detached state) def detached? = false # @return [Boolean] true if this is an unborn branch (no commits yet) def unborn? = target_oid.nil? # @return [String] the short branch name without any remote or heads prefix # (e.g., 'main' or 'feature/foo') def short_name return refname.delete_prefix('refs/heads/') if remote_name.nil? remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} refname.sub(remote_ref_prefix, '') end # @return [Boolean] true if this is the currently checked out branch def current? = current # @return [Boolean] true if this branch is checked out in another linked worktree def other_worktree? = !worktree_path.nil? # @return [Boolean] true if this is a symbolic reference def symref? = !symref.nil? # @return [Boolean] true if this is a remote-tracking branch def remote? = !remote_name.nil? # @return [String] string representation (the full refname) def to_s = refname end |
#worktree_path ⇒ String? (readonly)
The absolute path of the other linked worktree this branch is checked out in, or nil.
This is nil in two distinct cases:
- The branch is the current branch in this worktree (use #current? to distinguish that case)
- The branch is not checked out in any worktree
This path is suppressed for the current branch even though git reports it
via %(worktreepath), because the current worktree's path is already
known from the repository object and storing it here would make
#other_worktree? incorrect.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/git/branch_info.rb', line 149 BranchInfo = Data.define(:refname, :remote_name, :target_oid, :current, :worktree_path, :symref, :upstream) do # @param refname [String] the full branch refname # # @param remote_name [String, nil] resolved remote name, nil for local branches, # or omitted to derive from `refname` # # @param target_oid [String, nil] the commit object ID, or nil for unborn branches # # @param current [Boolean] whether this branch is currently checked out # # @param worktree_path [String, nil] path to another linked worktree, or nil # # @param symref [String, nil] symbolic reference target, or nil # # @param upstream [String, nil] upstream refname, or nil # def initialize(refname:, target_oid:, current:, worktree_path:, symref:, upstream:, # rubocop:disable Metrics/ParameterLists remote_name: REMOTE_NAME_NOT_GIVEN) remote_name = self.class.fallback_remote_name(refname) if remote_name.equal?(REMOTE_NAME_NOT_GIVEN) self.class.validate_remote_name!(refname, remote_name) super end # @param refname [String] the branch refname to validate # # @param remote_name [String, nil] the remote name to validate # # @return [void] # # @raise [ArgumentError] if the remote name contradicts the refname type def self.validate_remote_name!(refname, remote_name) if remote_tracking_refname?(refname) unless remote_name.is_a?(String) && !remote_name.empty? raise ArgumentError, 'remote_name must be a non-empty String for remote-tracking refname' end remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} raise ArgumentError, 'remote_name must match remote-tracking refname' unless refname.match?(remote_ref_prefix) elsif !remote_name.nil? raise ArgumentError, 'remote_name must be nil for local branch refname' end end # @param refname [String] the branch refname to parse # # @return [String, nil] the regex-derived remote name, or nil for local branches def self.fallback_remote_name(refname) refname.match(Git::BRANCH_REFNAME_REGEXP)[:remote_name] end # @param refname [String] the branch refname to inspect # # @return [Boolean] true if the refname is a remote-tracking refname def self.remote_tracking_refname?(refname) refname.match?(%r{\A(?:refs/)?remotes/[^/]+/.+}) end # @return [Boolean] always false for BranchInfo (see DetachedHeadInfo for detached state) def detached? = false # @return [Boolean] true if this is an unborn branch (no commits yet) def unborn? = target_oid.nil? # @return [String] the short branch name without any remote or heads prefix # (e.g., 'main' or 'feature/foo') def short_name return refname.delete_prefix('refs/heads/') if remote_name.nil? remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} refname.sub(remote_ref_prefix, '') end # @return [Boolean] true if this is the currently checked out branch def current? = current # @return [Boolean] true if this branch is checked out in another linked worktree def other_worktree? = !worktree_path.nil? # @return [Boolean] true if this is a symbolic reference def symref? = !symref.nil? # @return [Boolean] true if this is a remote-tracking branch def remote? = !remote_name.nil? # @return [String] string representation (the full refname) def to_s = refname end |
Class Method Details
.fallback_remote_name(refname) ⇒ String?
Returns the regex-derived remote name, or nil for local branches.
196 197 198 |
# File 'lib/git/branch_info.rb', line 196 def self.fallback_remote_name(refname) refname.match(Git::BRANCH_REFNAME_REGEXP)[:remote_name] end |
.remote_tracking_refname?(refname) ⇒ Boolean
Returns true if the refname is a remote-tracking refname.
203 204 205 |
# File 'lib/git/branch_info.rb', line 203 def self.remote_tracking_refname?(refname) refname.match?(%r{\A(?:refs/)?remotes/[^/]+/.+}) end |
.validate_remote_name!(refname, remote_name)
This method returns an undefined value.
180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/git/branch_info.rb', line 180 def self.validate_remote_name!(refname, remote_name) if remote_tracking_refname?(refname) unless remote_name.is_a?(String) && !remote_name.empty? raise ArgumentError, 'remote_name must be a non-empty String for remote-tracking refname' end remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} raise ArgumentError, 'remote_name must match remote-tracking refname' unless refname.match?(remote_ref_prefix) elsif !remote_name.nil? raise ArgumentError, 'remote_name must be nil for local branch refname' end end |
Instance Method Details
#current? ⇒ Boolean
Returns true if this is the currently checked out branch.
223 |
# File 'lib/git/branch_info.rb', line 223 def current? = current |
#detached? ⇒ Boolean
Returns always false for BranchInfo (see DetachedHeadInfo for detached state).
208 |
# File 'lib/git/branch_info.rb', line 208 def detached? = false |
#other_worktree? ⇒ Boolean
Returns true if this branch is checked out in another linked worktree.
226 |
# File 'lib/git/branch_info.rb', line 226 def other_worktree? = !worktree_path.nil? |
#remote? ⇒ Boolean
Returns true if this is a remote-tracking branch.
232 |
# File 'lib/git/branch_info.rb', line 232 def remote? = !remote_name.nil? |
#short_name ⇒ String
Returns the short branch name without any remote or heads prefix (e.g., 'main' or 'feature/foo').
215 216 217 218 219 220 |
# File 'lib/git/branch_info.rb', line 215 def short_name return refname.delete_prefix('refs/heads/') if remote_name.nil? remote_ref_prefix = %r{\A(?:refs/)?remotes/#{Regexp.escape(remote_name)}/} refname.sub(remote_ref_prefix, '') end |
#symref? ⇒ Boolean
Returns true if this is a symbolic reference.
229 |
# File 'lib/git/branch_info.rb', line 229 def symref? = !symref.nil? |
#to_s ⇒ String
Returns string representation (the full refname).
235 |
# File 'lib/git/branch_info.rb', line 235 def to_s = refname |
#unborn? ⇒ Boolean
Returns true if this is an unborn branch (no commits yet).
211 |
# File 'lib/git/branch_info.rb', line 211 def unborn? = target_oid.nil? |