Class: RightGit::Git::BranchCollection

Inherits:
Object
  • Object
show all
Includes:
BelongsToRepository
Defined in:
lib/right_git/git/branch_collection.rb

Overview

A collection of Git branches. Acts a bit like an Array, allowing it to be mapped, sorted and compared as such.

Constant Summary collapse

HEAD_REF =

Regexp matching (and capturing) the output of ‘git symbolic-ref’; used to determine which branch is currently checked out.

%r{^refs/heads/(#{Branch::BRANCH_NAME})$}
NO_HEAD_REF =

The output of ‘git symbolic-ref’ when the HEAD ref is not on any branch.

/^HEAD is not a symbolic ref$/
NOT_A_BRANCH =

The output of the ‘git branch’ command when the HEAD ref is not on any branch or in a detached HEAD state (e.g. “* (detached from v1.0)”) when pointing to a tag or the repo has no branches (“* (no branch)”).

This is not useful to RightGit, so we must filter it out of Git’s output when we see it.

/^\* \(.*\)$/

Instance Attribute Summary

Attributes included from BelongsToRepository

#repo

Instance Method Summary collapse

Methods included from BelongsToRepository

#logger

Constructor Details

#initialize(repo, branches = nil) ⇒ BranchCollection

Create a new BranchCollection. Don’t pass in a branches parameter unless you really know what you’re doing; it’s intended more for internal use than anything else.

Parameters:

  • repo (Repository)

    to host branch collection

  • optional (Array)

    branches an array of Branch objects, or nil to auto-populate this collection with ALL branches



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/right_git/git/branch_collection.rb', line 53

def initialize(repo, branches=nil)
  @repo = repo

  if branches
    # Use an arbitrary set of branches that was passed in
    @branches = branches
  else
    @branches = []

    # Initialize ourselves with all branches in the repository
    git_args = ['branch', '-a']
    @repo.git_output(git_args).lines.each do |line|
      line.strip!

      if line =~ NOT_A_BRANCH
        #no-op; ignore this one
      else
        @branches << Branch.new(@repo, line)
      end
    end
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object

Dispatch to the underlying Array of Branch objects, allowing the branch collection to act a bit like an Array.

If the dispatched-to method returns an Array, it is wrapped in another BranchCollection object before returning to the caller. This allows array-like method calls to be chained together without losing the BranchCollection-ness of the underlying object.



175
176
177
178
179
180
181
182
183
# File 'lib/right_git/git/branch_collection.rb', line 175

def method_missing(meth, *args, &block)
  result = @branches.__send__(meth, *args, &block)

  if result.is_a?(::Array)
    BranchCollection.new(@repo, result)
  else
    result
  end
end

Instance Method Details

#[](argument) ⇒ Object

Accessor that acts like either a Hash or Array accessor



159
160
161
162
163
164
165
166
167
# File 'lib/right_git/git/branch_collection.rb', line 159

def [](argument)
  case argument
  when String
    target = Branch.new(@repo, argument)
    @branches.detect { |b| b == target }
  else
    @branches.__send__(:[], argument)
  end
end

#currentBranch

Return a Branch object representing whichever branch is currently checked out, IF AND ONLY IF that branch is a member of the collection. If the current branch isn’t part of the collection or HEAD refers to something other than a branch, return nil.

Returns:

  • (Branch)

    the current branch if any, nil otherwise



92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/right_git/git/branch_collection.rb', line 92

def current
  lines = @repo.git_output(['symbolic-ref', 'HEAD'], :raise_on_failure => false).lines

  if lines.size == 1
    line = lines.first.strip
    if (match = HEAD_REF.match(line))
      @branches.detect { |b| b.fullname == match[1] }
    elsif line == NO_HEAD_REF
      nil
    end
  else
    raise GitError, "Unexpected output from 'git symbolic-ref'; need 1 lines, got #{lines.size}"
  end
end

#inspectObject

Provide a programmer-friendly representation of this collection.



83
84
85
# File 'lib/right_git/git/branch_collection.rb', line 83

def inspect
  '#<%s:%s>' % [self.class.name, @branches.inspect]
end

#localBranchCollection

Return another collection that contains only the local branches in this collection.

Returns:



110
111
112
113
114
115
116
117
118
# File 'lib/right_git/git/branch_collection.rb', line 110

def local
  local = []

  @branches.each do |branch|
    local << branch unless branch.remote?
  end

  BranchCollection.new(@repo, local)
end

#merged(revision) ⇒ BranchCollection

Queries and filters on branches reachable from the given revision, if any.

Parameters:

  • revision (String)

    for listing reachable merged branches

Returns:



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/right_git/git/branch_collection.rb', line 138

def merged(revision)
  # By hand, build a list of all branches known to be merged into master
  git_args = ['branch', '-a', '--merged', revision]
  all_merged = []
  @repo.git_output(git_args).lines.each do |line|
    line.strip!
    all_merged << Branch.new(@repo, line)
  end

  # Filter the contents of this collection according to the big list
  merged = []
  @branches.each do |candidate|
    # For some reason Set#include? does not play nice with our overridden comparison operators
    # for branches, so we need to do this the hard way :(
    merged << candidate if all_merged.detect { |b| candidate == b }
  end

  BranchCollection.new(@repo, merged)
end

#remoteBranchCollection

Return another collection that contains only the local branches in this collection.

Returns:



123
124
125
126
127
128
129
130
131
# File 'lib/right_git/git/branch_collection.rb', line 123

def remote
  remote = []

  @branches.each do |branch|
    remote << branch if branch.remote?
  end

  BranchCollection.new(@repo, remote)
end

#respond_to?(meth) ⇒ Boolean

Polite implementation of #respond_to that honors our #method_missing.

Returns:

  • (Boolean)


186
187
188
# File 'lib/right_git/git/branch_collection.rb', line 186

def respond_to?(meth)
  super || @branches.respond_to?(meth)
end

#to_sObject

Provide a String representation of this collection, depicting it as a comma-separated list of branch names.



78
79
80
# File 'lib/right_git/git/branch_collection.rb', line 78

def to_s
  @branches.join(',')
end