module Git::Repository::Merging
Facade methods for merge operations: merging branches into the current branch, and finding common ancestors between commits
Included by {Git::Repository}.
@api private
Constants
- MERGE_ALLOWED_OPTS
-
Option keys accepted by {#merge}
Derived from the 4.x option map for ‘Git::Lib#merge`.
- MERGE_BASE_ALLOWED_OPTS
-
Option keys accepted by {#merge_base}
Derived from the 4.x option map for ‘Git::Lib#merge_base`.
- REVERT_ALLOWED_OPTS
-
Option keys accepted by {#revert}
Derived from the 4.x option map for ‘Git::Lib#revert`.
Public Instance Methods
Source
# File lib/git/repository/merging.rb, line 246 def conflicts(&) Git::Deprecation.warn( 'Git::Repository#conflicts is deprecated and will be removed in v6.0.0. ' \ 'Use Git::Repository#each_conflict instead.' ) each_conflict(&) end
Iterate over files with merge conflicts, yielding conflict details for each
For each unmerged file, the staged content for both sides of the conflict (stage 2 “ours” and stage 3 “theirs”) is written to temporary files whose paths are yielded alongside the file path. The temporary files are deleted automatically when the block returns.
@example Inspect conflicting files
repo.conflicts do |file, your_version, their_version| puts "Conflict in #{file}" puts File.read(your_version) puts File.read(their_version) end
@return [Array<String>] the list of unmerged file paths
@raise [Git::FailedError] when ‘git diff –cached` exits outside the
allowed range (exit code > 2)
@yield [file, your_version, their_version] passes conflict details for
each unmerged file
@yieldparam file [String] path to the conflicting file, relative to the
working tree
@yieldparam your_version [String] path to a temporary file containing the
stage-2 (ours) content for the conflicting file
@yieldparam their_version [String] path to a temporary file containing the
stage-3 (theirs) content for the conflicting file
@yieldreturn [void]
@deprecated Use {#each_conflict} instead
Source
# File lib/git/repository/merging.rb, line 201 def each_conflict Private.unmerged_paths(@execution_context).each do |file_path| Private.write_staged_file(@execution_context, file_path, 2) do |your_file| Private.write_staged_file(@execution_context, file_path, 3) do |their_file| yield(file_path, your_file.path, their_file.path) end end end end
Iterate over files with merge conflicts, yielding conflict details for each
For each unmerged file, the staged content for both sides of the conflict (stage 2 “ours” and stage 3 “theirs”) is written to temporary files whose paths are yielded alongside the file path. The temporary files are deleted automatically when the block returns.
@example Inspect conflicting files
repo.each_conflict do |file, your_version, their_version| puts "Conflict in #{file}" puts "Your version:" puts File.read(your_version) puts "Their version:" puts File.read(their_version) end
@return [Array<String>] the list of unmerged file paths
@raise [Git::FailedError] when ‘git diff –cached` exits outside the
allowed range (exit code > 2)
@yield [file, your_version, their_version] passes conflict details for
each unmerged file
@yieldparam file [String] path to the conflicting file, relative to the
working tree
@yieldparam your_version [String] path to a temporary file containing the
stage-2 (ours) content for the conflicting file
@yieldparam their_version [String] path to a temporary file containing the
stage-3 (theirs) content for the conflicting file
@yieldreturn [void]
Source
# File lib/git/repository/merging.rb, line 84 def merge(branch, message = nil, opts = {}) SharedPrivate.assert_valid_opts!(MERGE_ALLOWED_OPTS, **opts) # Dup so callers who reuse the same opts hash are not affected opts = opts.dup # Merge positional message into opts so the rest of the logic is uniform opts[:message] = message if message # git merge uses -m, not --message; translate the key opts[:m] = opts.delete(:message) if opts.key?(:message) branches = Array(branch).map(&:to_s) Git::Commands::Merge::Start.new(@execution_context).call(*branches, no_edit: true, **opts).stdout end
Merge one or more branches into the current branch
The merge commit message may be given by the message positional argument, the ‘:message` option, or the `:m` option; if more than one is provided, the precedence is positional argument > `:message` > `:m`.
@example Merge a single branch
repo.merge('feature')
@example Merge a branch with a no-fast-forward commit message
repo.merge('feature', 'Merge feature into main', no_ff: true)
@example Octopus merge of multiple branches
repo.merge(%w[feature-a feature-b])
@example Merge without committing
repo.merge('feature', nil, no_commit: true)
@param branch [#to_s, Array<#to_s>] the branch or branches to merge into the
current branch
When an Array is given, an octopus merge is performed; each branch-ish
object (e.g., {Git::BranchInfo}) is coerced to a String via `#to_s`.
@param message [String, nil] optional commit message for the merge commit
Translated to the `-m` flag internally. For fast-forward merges git ignores this value; use `no_ff: true` to ensure a merge commit is created and the message is recorded.
@param opts [Hash] additional options forwarded to ‘git merge`
@option opts [Boolean, nil] :no_commit (nil) stop before creating the merge commit
(`--no-commit`)
@option opts [Boolean, nil] :no_ff (nil) create a merge commit even when
fast-forward is possible (`--no-ff`)
@option opts [String] :message (nil) commit message
Prefer the `:m` option instead of this one. Translated to the `-m` flag. Identical to the positional `message` argument and the `:m` option.
@option opts [String] :m (nil) commit message (‘-m` flag)
@return [String] git’s stdout from the merge command
@raise [ArgumentError] when unsupported options are provided
@raise [Git::FailedError] when git exits with a non-zero exit status
Source
# File lib/git/repository/merging.rb, line 141 def merge_base(*args) opts = args.last.is_a?(Hash) ? args.pop : {} SharedPrivate.assert_valid_opts!(MERGE_BASE_ALLOWED_OPTS, **opts) result = Git::Commands::MergeBase.new(@execution_context).call(*args, **opts) result.stdout.lines.map(&:strip).reject(&:empty?) end
Find common ancestor commit(s) for use in a merge
@example Find the common ancestor of two branches
repo.merge_base('main', 'feature') #=> ["abc123def456..."]
@example Find all common ancestors of two branches
repo.merge_base('branch-a', 'branch-b', all: true)
@example Find the fork point of a branch (consults the reflog)
repo.merge_base('main', 'feature', fork_point: true)
@example Find independent commits not reachable from each other
repo.merge_base('abc1234', 'main', 'feature', independent: true)
@overload merge_base(*commits, options = {})
@param commits [Array<String>] two or more commit SHAs, branch names, or refs to find the common ancestor(s) of @param options [Hash] merge-base options @option options [Boolean, nil] :octopus (nil) compute the best common ancestor for an n-way merge (intersection of all merge bases) @option options [Boolean, nil] :independent (nil) list commits not reachable from any other; useful for finding minimal merge points @option options [Boolean, nil] :fork_point (nil) find the fork point where a branch diverged from another, consulting the reflog @option options [Boolean, nil] :all (nil) output all merge bases instead of just the first when multiple equally good bases exist @return [Array<String>] commit SHAs of the common ancestor(s); empty when no common ancestor exists or `--fork-point` finds none @raise [ArgumentError] when unsupported options are provided @raise [Git::FailedError] when `git merge-base` exits outside the allowed range (exit code > 1)
Source
# File lib/git/repository/merging.rb, line 294 def revert(commitish = nil, opts = {}) commitish = 'HEAD' if commitish.nil? SharedPrivate.assert_valid_opts!(REVERT_ALLOWED_OPTS, **opts) opts = { no_edit: true }.merge(opts) Git::Commands::Revert::Start.new(@execution_context).call(commitish, **opts).stdout end
Revert one or more existing commits by creating new commits that undo the changes those commits introduced
The working tree must be clean before calling this method. By default the editor is suppressed (‘–no-edit`) so the commit message is taken from git’s default revert message without prompting.
@example Revert the most recent commit
repo.revert('HEAD')
@example Revert a specific commit by SHA
repo.revert('abc1234')
@example Revert a range of commits
repo.revert('HEAD~3..HEAD~1')
@example Revert without suppressing the editor
repo.revert('HEAD', no_edit: false)
@param commitish [String, nil] the commit, ref, or rev range to revert;
see `gitrevisions(7)` for accepted forms; defaults to `'HEAD'` when `nil`
@param opts [Hash] additional options forwarded to ‘git revert`
@option opts [Boolean, nil] :no_edit (true) suppress the commit-message
editor (`--no-edit`); pass `false` to open the editor
@return [String] git’s stdout from the revert command
@raise [ArgumentError] when unsupported options are provided
@raise [Git::FailedError] when git exits with a non-zero exit status
Source
# File lib/git/repository/merging.rb, line 162 def unmerged Private.unmerged_paths(@execution_context) end
Return the paths of files with unresolved merge conflicts
@example List conflicting files after a failed merge
paths = repo.unmerged # => ["config/settings.rb", "lib/git/base.rb"] paths.each { |path| puts "Conflict in #{path}" }
@return [Array<String>] repository-relative paths of files with unresolved
merge conflicts; empty array when the working tree has no conflicts
@raise [Git::FailedError] if git exits outside the allowed range (exit code > 2)
@see each_conflict