Module: Git::Repository::Branching Private

Included in:
Git::Repository
Defined in:
lib/git/repository/branching.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.

Facade methods for branching operations: creating, checking out, querying, deleting, and updating branches

Included by Git::Repository.

Defined Under Namespace

Classes: HeadState

Instance Method Summary collapse

Instance Method Details

#branch(branch_name = current_branch) ⇒ Git::Branch

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.

Returns a Branch object for the given branch name

Examples:

Get a branch object for 'main'

repo.branch('main')  #=> #<Git::Branch 'main'>

Get a branch object for the current branch

repo.branch  #=> #<Git::Branch 'main'>

Parameters:

  • branch_name (String) (defaults to: current_branch)

    the branch name (defaults to the current branch)

Returns:

Raises:



633
634
635
# File 'lib/git/repository/branching.rb', line 633

def branch(branch_name = current_branch)
  Git::Branch.new(self, branch_name)
end

#branch?(branch) ⇒ 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.

Returns true if the named branch exists locally or as a remote-tracking branch

Examples:

Check whether main exists anywhere

repo.branch?('main')  # => true

Parameters:

  • branch (String)

    the branch name to look up

Returns:

  • (Boolean)

    true if the branch exists locally or remotely, false otherwise

Raises:



276
277
278
# File 'lib/git/repository/branching.rb', line 276

def branch?(branch)
  local_branch?(branch) || remote_branch?(branch)
end

#branch_contains(commit, branch_name = '') ⇒ 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.

Returns the git branch --list --contains stdout for a given commit

The output format is the human-readable git branch listing: each matching branch name appears on its own line, prefixed with two spaces, or * if it is the currently checked-out branch. This is the same format returned by Git::Lib#branch_contains in the 4.x gem series.

Examples:

List all branches that contain a commit

repo.branch_contains('abc1234')
# => "  main\n"

The current branch is marked with an asterisk

repo.branch_contains('abc1234')
# => "* main\n  feature\n"

Limit the search to branches matching a shell wildcard pattern

repo.branch_contains('abc1234', 'feature/*')

Typical usage: check whether any branch contains the commit

repo.branch_contains('abc1234').empty?  # => false

Parameters:

  • commit (String)

    the commit SHA or ref to look up

  • branch_name (String, nil) (defaults to: '')

    a shell wildcard pattern to limit which branches are searched

    When empty or nil, all local branches are searched.

Returns:

  • (String)

    the git branch --list --contains stdout

    Each matching branch appears on its own line, prefixed with two spaces, or * for the currently checked-out branch. Returns an empty string when no matching branch contains the commit.

Raises:



506
507
508
509
510
511
512
# File 'lib/git/repository/branching.rb', line 506

def branch_contains(commit, branch_name = '')
  branch_name = branch_name.to_s
  pattern = branch_name.empty? ? nil : branch_name
  Git::Commands::Branch::List.new(@execution_context)
                             .call(*[pattern].compact, contains: commit, no_color: true)
                             .stdout
end

#branch_delete(*branches, **options) ⇒ 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.

Delete one or more local or remote-tracking branches

Examples:

Delete a single branch

repo.branch_delete('feature') # => "Deleted branch feature (was abc1234)."

Delete multiple branches at once

repo.branch_delete('feature-1', 'feature-2')

Force-delete an unmerged branch

repo.branch_delete('unmerged-branch', force: true)

Delete a remote-tracking branch

repo.branch_delete('origin/feature', remotes: true)

Parameters:

  • branches (Array<String>)

    the name(s) of the branch(es) to delete

  • options (Hash)

    options for the delete command

Options Hash (**options):

  • :force (Boolean, nil) — default: true

    allow deleting the branch irrespective of its merged status

    Defaults to true to match the 4.x behavior.

  • :remotes (Boolean, nil) — default: nil

    delete remote-tracking branches

    Use together with a remote/branch name.

Returns:

  • (String)

    the stdout output from the delete command, e.g. "Deleted branch feature (was abc1234)."

Raises:

  • (ArgumentError)

    if unsupported options are provided

  • (Git::FailedError)

    if git exits outside the allowed range (exit code > 1)

  • (Git::Error)

    if git reports a deletion failure



426
427
428
429
430
431
432
433
434
435
# File 'lib/git/repository/branching.rb', line 426

def branch_delete(*branches, **options)
  options = { force: true }.merge(options)
  SharedPrivate.assert_valid_opts!(BRANCH_DELETE_ALLOWED_OPTS, **options)

  result = Git::Commands::Branch::Delete.new(@execution_context).call(*branches, **options)

  raise Git::Error, result.stderr.strip unless result.status.success?

  result.stdout.strip
end

#branch_list(*patterns, remote_names: nil) ⇒ 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.

Returns all local and remote-tracking branches as structured objects

Examples:

List all branches

repo.branch_list
# => [#<data Git::BranchInfo refname="refs/heads/main", current=true, ...>,
#     #<data Git::BranchInfo refname="refs/remotes/origin/main", current=false, ...>]

Find the currently checked-out branch

repo.branch_list.find(&:current)

List only local branches

repo.branch_list.reject(&:remote?)

Filter to an exact branch name

repo.branch_list('feature/auth')

Filter using glob patterns

repo.branch_list('feature/*', 'hotfix/*')

Parameters:

  • patterns (Array<String>)

    optional shell wildcard patterns passed directly to git branch --list; when empty (the default) all branches are returned. Pattern matching follows git's own rules; behavior may differ between local and remote-tracking branches.

  • remote_names (Array<String>, nil) (defaults to: nil)

    configured remote names used to resolve remote-tracking refs

    Especially useful for remotes whose remote names contain slashes. When omitted, the repository's configured remote names are fetched automatically.

Returns:

  • (Array<Git::BranchInfo>)

    parsed branch information for every local and remote-tracking branch matching the pattern

    Returns an empty array when the repository has no branches or no branches match the given pattern.

Raises:



552
553
554
555
556
557
558
# File 'lib/git/repository/branching.rb', line 552

def branch_list(*patterns, remote_names: nil)
  remote_names ||= self.remote_names
  result = Git::Commands::Branch::List.new(@execution_context).call(
    *patterns, all: true, format: Git::Parsers::Branch::FORMAT_STRING
  )
  Git::Parsers::Branch.parse_list(result.stdout, remote_names:)
end

#branch_new(branch, start_point = nil, branch_options = {})

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.

This method returns an undefined value.

Create a new branch

Examples:

Create a new branch from the current HEAD

repo.branch_new('feature')

Create a new branch from a specific commit or branch

repo.branch_new('feature', 'main')

Parameters:

  • branch (String)

    the name of the branch to create

  • start_point (String, nil) (defaults to: nil)

    the commit, branch, or tag to start the new branch from; defaults to the current HEAD when nil

  • branch_options (Hash) (defaults to: {})

    reserved; must be empty — no options are currently supported

Raises:

  • (ArgumentError)

    if unsupported options are provided

  • (Git::FailedError)

    if git exits with a non-zero exit status



372
373
374
375
376
377
378
379
380
381
382
# File 'lib/git/repository/branching.rb', line 372

def branch_new(branch, start_point = nil, branch_options = {})
  if start_point.is_a?(Hash) && branch_options.empty?
    branch_options = start_point
    start_point = nil
  end

  SharedPrivate.assert_valid_opts!(BRANCH_NEW_ALLOWED_OPTS, **branch_options)
  Git::Commands::Branch::Create.new(@execution_context).call(branch, start_point, **branch_options)

  nil
end

#branchesGit::Branches

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.

Returns a Branches collection of all branches in the repository

Examples:

List all branches

repo.branches
# => #<Git::Branches ...>

Iterate over all branches

repo.branches.each { |b| puts b.name }

Access local branches only

repo.branches.local

Access remote-tracking branches only

repo.branches.remote

Look up a branch by name

repo.branches['main']  # => #<Git::Branch 'main'>

Returns:

  • (Git::Branches)

    a collection wrapping all local and remote-tracking branches in the repository

Raises:



660
661
662
# File 'lib/git/repository/branching.rb', line 660

def branches
  Git::Branches.new(self)
end

#branches_allArray<Array>

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.

Deprecated.

Use #branch_list instead, which returns richer BranchInfo objects.

Returns all local and remote-tracking branches in the 4.x-compatible format

Each entry is a 4-element array: [refname, current, worktree, symref]. The refname uses the short form (main, remotes/origin/main) to match the output of the legacy Git::Lib#branches_all method.

Returns:

  • (Array<Array>)

    array of [refname, current, worktree, symref] tuples

Raises:



573
574
575
576
577
578
579
580
581
582
# File 'lib/git/repository/branching.rb', line 573

def branches_all
  Git::Deprecation.warn(
    'Git::Repository#branches_all is deprecated and will be removed in v6.0.0. ' \
    'Use Git::Repository#branch_list instead.'
  )
  branch_list.map do |info|
    refname = info.remote? ? "remotes/#{info.remote_name}/#{info.short_name}" : info.short_name
    [refname, info.current, info.other_worktree?, info.symref]
  end
end

#change_head_branch(branch_name)

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.

Note:

Pointing HEAD at a branch that does not yet exist places the repository in unborn-branch state. This is intentional for repository initialization workflows — for example, setting a custom default branch name before any commits land — but is unexpected if done by mistake. The repository will appear to have no commits until the first commit is made on the new branch.

This method returns an undefined value.

Writes the HEAD symbolic ref to point at the given branch

Sets HEAD to refs/heads/<branch_name> via git symbolic-ref. This is equivalent to running git symbolic-ref HEAD refs/heads/<branch_name> on the command line and is the mechanism git uses internally for branch renaming and orphan-branch checkout.

Examples:

Change HEAD to point to an existing branch

repo.change_head_branch('main')

Initialize a repository with a custom default branch name (unborn-branch pattern)

repo = Git.init('/path/to/repo')
repo.change_head_branch('my-branch')
# HEAD now points at refs/heads/my-branch before any commits exist

Parameters:

  • branch_name (String)

    the branch name to point HEAD at

Raises:



465
466
467
468
# File 'lib/git/repository/branching.rb', line 465

def change_head_branch(branch_name)
  Git::Commands::SymbolicRef::Update.new(@execution_context).call('HEAD', "refs/heads/#{branch_name}")
  nil
end

#checkout(branch = nil, opts = {}) ⇒ 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.

Switch branches or restore working tree files

Examples:

Check out an existing branch

repo.checkout('main')

Create and check out a new branch from main

repo.checkout('new-feature', new_branch: true, start_point: 'main')

Create a new branch with a name different from the start point

repo.checkout('main', new_branch: 'new-feature')

Create and check out an unborn branch with no history

repo.checkout('gh-pages', orphan: true)

Force checkout discarding local changes

repo.checkout('main', force: true)

Parameters:

  • branch (String, nil) (defaults to: nil)

    the branch to check out; defaults to nil (i.e. restore HEAD state)

  • opts (Hash) (defaults to: {})

    options for the checkout command

Options Hash (opts):

  • :force (Boolean, nil) — default: nil

    discard local changes when switching branches

  • :new_branch (Boolean, String, nil) — default: nil

    when true, creates a new branch named branch from :start_point

    When a String, creates a new branch with that name, using branch as the start point.

  • :b (Boolean, String, nil) — default: nil

    alias for :new_branch

  • :f (Boolean, nil) — default: nil

    alias for :force

  • :orphan (Boolean, String, nil) — default: nil

    when true, creates a new unborn branch named branch whose first commit has no parents

    When a String, creates an unborn branch with that name, using branch as the start point for the working tree and index.

    false and nil are both treated as unset. A blank branch name is rejected rather than ignored.

  • :start_point (String, nil) — default: nil

    the commit or branch to start the new branch from; used together with new_branch: true or orphan: true

Returns:

  • (String)

    git's stdout from the checkout

Raises:

  • (ArgumentError)

    if unsupported options are provided

  • (ArgumentError)

    if :orphan is given a blank or missing branch name

  • (Git::FailedError)

    if git exits with a non-zero exit status



178
179
180
181
182
183
184
185
186
187
188
# File 'lib/git/repository/branching.rb', line 178

def checkout(branch = nil, opts = {})
  if branch.is_a?(Hash) && opts.empty?
    opts = branch
    branch = nil
  end

  SharedPrivate.assert_valid_opts!(CHECKOUT_ALLOWED_OPTS, **opts)

  target, translated_opts = Private.translate_checkout_opts(branch, opts)
  Git::Commands::Checkout::Branch.new(@execution_context).call(target, **translated_opts).stdout
end

#checkout_file(version, file) ⇒ 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.

Restore working tree files from a tree-ish

Examples:

Restore README.md to its HEAD state

repo.checkout_file('HEAD', 'README.md')

Parameters:

  • version (String)

    the tree-ish (branch, tag, commit SHA, etc.) to restore the file from

  • file (String)

    the path to the file to restore

Returns:

  • (String)

    git's stdout from the checkout

Raises:



118
119
120
# File 'lib/git/repository/branching.rb', line 118

def checkout_file(version, file)
  Git::Commands::Checkout::Files.new(@execution_context).call(version, pathspec: [file]).stdout
end

#checkout_index(options = {}) ⇒ 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.

Populate the working tree from the index

Examples:

Check out all files from the index

repo.checkout_index(all: true)

Force check out a specific file

repo.checkout_index(force: true, path_limiter: 'README.md')

Check out files to a staging prefix

repo.checkout_index(prefix: 'tmp/stage/', all: true)

Parameters:

  • options (Hash) (defaults to: {})

    options for the checkout-index command

Options Hash (options):

  • :all (Boolean, nil) — default: nil

    check out all files in the index

  • :force (Boolean, nil) — default: nil

    overwrite existing files

  • :prefix (String, nil) — default: nil

    write files under this path prefix rather than the working directory root

  • :path_limiter (String, Pathname, Array<String, Pathname>, nil) — default: nil

    limit the check out to the given path(s)

Returns:

  • (String)

    git's stdout from the checkout-index command

Raises:

  • (ArgumentError)

    if unsupported options are provided

  • (Git::FailedError)

    if git exits with a non-zero exit status



219
220
221
222
223
224
225
# File 'lib/git/repository/branching.rb', line 219

def checkout_index(options = {})
  SharedPrivate.assert_valid_opts!(CHECKOUT_INDEX_ALLOWED_OPTS, **options)

  paths = Private.normalize_pathspecs(options[:path_limiter], 'path_limiter')
  keyword_opts = options.except(:path_limiter)
  Git::Commands::CheckoutIndex.new(@execution_context).call(*paths.to_a, **keyword_opts).stdout
end

#current_branchString

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.

Returns the name of the current branch

Examples:

Get the current branch name

repo.current_branch  # => "main"

In detached HEAD state

repo.current_branch  # => "HEAD"

Returns:

  • (String)

    the current branch name, or 'HEAD' when in detached HEAD state

Raises:



65
66
67
68
69
# File 'lib/git/repository/branching.rb', line 65

def current_branch
  result = Git::Commands::Branch::ShowCurrent.new(@execution_context).call
  name = result.stdout.strip
  name.empty? ? 'HEAD' : name
end

#current_branch_stateGit::Repository::Branching::HeadState

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.

Returns the current HEAD state as a structured value object

HEAD can be in one of three states:

  • :active — HEAD points to a branch ref that has at least one commit.
  • :unborn — HEAD points to a branch ref that has been created but has no commits yet (e.g. immediately after git init before any commit).
  • :detached — HEAD points directly to a commit SHA rather than a branch.

Examples:

Active branch

repo.current_branch_state
# => #<data Git::Repository::Branching::HeadState state=:active, name="main">

Unborn branch (no commits yet)

repo.current_branch_state
# => #<data Git::Repository::Branching::HeadState state=:unborn, name="main">

Detached HEAD

repo.current_branch_state
# => #<data Git::Repository::Branching::HeadState state=:detached, name="HEAD">

Returns:

Raises:



96
97
98
99
100
101
102
# File 'lib/git/repository/branching.rb', line 96

def current_branch_state
  branch_name = Git::Commands::Branch::ShowCurrent.new(@execution_context).call.stdout.strip
  return HeadState.new(state: :detached, name: 'HEAD') if branch_name.empty?

  state = Private.get_branch_state(@execution_context, branch_name)
  HeadState.new(state: state, name: branch_name)
end

#is_branch?(branch) ⇒ 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.

Deprecated.

use #branch? instead

Checks whether the named branch exists locally or as a remote-tracking branch

Examples:

Check whether main exists anywhere

repo.is_branch?('main')  # => true

Parameters:

  • branch (String)

    the branch name to look up

Returns:

  • (Boolean)

    true if the branch exists locally or remotely, false otherwise

Raises:



337
338
339
340
341
342
343
# File 'lib/git/repository/branching.rb', line 337

def is_branch?(branch) # rubocop:disable Naming/PredicatePrefix
  Git::Deprecation.warn(
    'Git::Repository#is_branch? is deprecated and will be removed in v6.0.0. ' \
    'Use Git::Repository#branch? instead.'
  )
  branch?(branch)
end

#is_local_branch?(branch) ⇒ 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.

Deprecated.

use #local_branch? instead

Checks whether the named branch exists locally

Examples:

Check whether main exists locally

repo.is_local_branch?('main')  # => true

Parameters:

  • branch (String)

    the local branch name to look up

Returns:

  • (Boolean)

    true if the branch exists locally, false otherwise

Raises:



293
294
295
296
297
298
299
# File 'lib/git/repository/branching.rb', line 293

def is_local_branch?(branch) # rubocop:disable Naming/PredicatePrefix
  Git::Deprecation.warn(
    'Git::Repository#is_local_branch? is deprecated and will be removed in v6.0.0. ' \
    'Use Git::Repository#local_branch? instead.'
  )
  local_branch?(branch)
end

#is_remote_branch?(branch) ⇒ 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.

Deprecated.

use #remote_branch? instead

Checks whether the named branch exists as a remote-tracking branch

Examples:

Check whether master exists on any remote

repo.is_remote_branch?('master')  # => true

Parameters:

  • branch (String)

    the short branch name to look up across all remotes

Returns:

  • (Boolean)

    true if a remote-tracking branch with that short name exists, false otherwise

Raises:



315
316
317
318
319
320
321
# File 'lib/git/repository/branching.rb', line 315

def is_remote_branch?(branch) # rubocop:disable Naming/PredicatePrefix
  Git::Deprecation.warn(
    'Git::Repository#is_remote_branch? is deprecated and will be removed in v6.0.0. ' \
    'Use Git::Repository#remote_branch? instead.'
  )
  remote_branch?(branch)
end

#local_branch?(branch) ⇒ 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.

Returns true if the named branch exists as a local branch

Examples:

Check whether main exists locally

repo.local_branch?('main')  # => true

Parameters:

  • branch (String)

    the local branch name to look up

Returns:

  • (Boolean)

    true if the branch exists locally, false otherwise

Raises:



238
239
240
241
# File 'lib/git/repository/branching.rb', line 238

def local_branch?(branch)
  result = Git::Commands::Branch::List.new(@execution_context).call(branch, format: '%(refname:short)')
  result.stdout.chomp == branch
end

#remote_branch?(branch) ⇒ 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.

Returns true if the named branch exists as a remote-tracking branch

The branch argument must be the short branch name (e.g. 'master'), not the combined remote/branch form (e.g. 'origin/master').

Examples:

Check whether master exists on any remote

repo.remote_branch?('master')  # => true

Parameters:

  • branch (String)

    the short branch name to look up across all remotes

Returns:

  • (Boolean)

    true if a remote-tracking branch with that short name exists, false otherwise

Raises:



258
259
260
261
262
# File 'lib/git/repository/branching.rb', line 258

def remote_branch?(branch)
  result = Git::Commands::Branch::List.new(@execution_context)
                                      .call("*/#{branch}", remotes: true, format: '%(refname:lstrip=3)')
  result.stdout.each_line.any? { |line| line.chomp == branch }
end

#update_ref(branch, commit) ⇒ Git::CommandLine::Result

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.

Update a branch ref to point to a new commit

Derives the full ref from the branch argument:

  • remotes/<remote>/<name> or refs/remotes/<remote>/<name> → writes to refs/remotes/<remote>/<name> (remote-tracking branch)
  • Any other value → writes to refs/heads/<branch> (local branch)

Examples:

Advance a local branch to the current HEAD

repo.update_ref('feature', repo.rev_parse('HEAD'))

Reset a local branch to an older commit

repo.update_ref('main', 'abc1234def5678')

Update a remote-tracking branch ref

repo.update_ref('remotes/origin/main', 'abc1234def5678')

Parameters:

  • branch (String)

    a local or remote-tracking branch name

    Short local names (e.g. 'main') resolve to refs/heads/<branch>. Remote-tracking names with a remotes/<remote>/ or refs/remotes/<remote>/ prefix (e.g. 'remotes/origin/main') resolve to refs/remotes/<remote>/<name>.

  • commit (String)

    the commit SHA to point the branch at

Returns:

Raises:



614
615
616
617
# File 'lib/git/repository/branching.rb', line 614

def update_ref(branch, commit)
  ref = Private.build_update_ref(branch)
  Git::Commands::UpdateRef::Update.new(@execution_context).call(ref, commit)
end