git 4.3.2 → 5.0.0.beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/copilot-instructions.md +73 -2705
- data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +188 -0
- data/.github/pull_request_template.md +3 -1
- data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
- data/.github/skills/command-implementation/REFERENCE.md +993 -0
- data/.github/skills/command-implementation/SKILL.md +229 -0
- data/.github/skills/command-test-conventions/SKILL.md +660 -0
- data/.github/skills/command-yard-documentation/SKILL.md +426 -0
- data/.github/skills/dependency-management/SKILL.md +72 -0
- data/.github/skills/development-workflow/SKILL.md +506 -0
- data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
- data/.github/skills/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +22 -0
- data/.github/skills/extract-facade-from-base-lib/SKILL.md +600 -0
- data/.github/skills/facade-implementation/REFERENCE.md +840 -0
- data/.github/skills/facade-implementation/SKILL.md +274 -0
- data/.github/skills/facade-test-conventions/SKILL.md +394 -0
- data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
- data/.github/skills/make-skill-template/SKILL.md +176 -0
- data/.github/skills/pr-readiness-review/SKILL.md +185 -0
- data/.github/skills/project-context/SKILL.md +313 -0
- data/.github/skills/pull-request-review/SKILL.md +168 -0
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
- data/.github/skills/release-management/SKILL.md +125 -0
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
- data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
- data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
- data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
- data/.github/skills/reviewing-skills/SKILL.md +189 -0
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
- data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
- data/.github/skills/test-debugging/SKILL.md +160 -0
- data/.github/skills/yard-documentation/SKILL.md +793 -0
- data/.github/workflows/continuous_integration.yml +3 -2
- data/.github/workflows/enforce_conventional_commits.yml +1 -1
- data/.github/workflows/experimental_continuous_integration.yml +2 -2
- data/.github/workflows/release.yml +3 -4
- data/.gitignore +8 -0
- data/.husky/pre-commit +13 -0
- data/.release-please-manifest.json +1 -1
- data/.rspec +3 -0
- data/.rubocop.yml +12 -3
- data/.rubocop_todo.yml +23 -5
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -40
- data/CONTRIBUTING.md +694 -53
- data/README.md +67 -15
- data/Rakefile +61 -9
- data/UPGRADING.md +141 -0
- data/commitlint.test +4 -0
- data/git.gemspec +18 -7
- data/lib/git/args_builder.rb +0 -8
- data/lib/git/branch.rb +369 -43
- data/lib/git/branch_delete_failure.rb +31 -0
- data/lib/git/branch_delete_result.rb +63 -0
- data/lib/git/branch_info.rb +178 -0
- data/lib/git/branches.rb +122 -24
- data/lib/git/command_line/base.rb +255 -0
- data/lib/git/command_line/capturing.rb +251 -0
- data/lib/git/command_line/result.rb +96 -0
- data/lib/git/command_line/streaming.rb +196 -0
- data/lib/git/command_line.rb +43 -322
- data/lib/git/command_line_result.rb +4 -88
- data/lib/git/commands/add.rb +131 -0
- data/lib/git/commands/am/abort.rb +43 -0
- data/lib/git/commands/am/apply.rb +252 -0
- data/lib/git/commands/am/continue.rb +43 -0
- data/lib/git/commands/am/quit.rb +43 -0
- data/lib/git/commands/am/retry.rb +47 -0
- data/lib/git/commands/am/show_current_patch.rb +64 -0
- data/lib/git/commands/am/skip.rb +42 -0
- data/lib/git/commands/am.rb +33 -0
- data/lib/git/commands/apply.rb +237 -0
- data/lib/git/commands/archive/list_formats.rb +46 -0
- data/lib/git/commands/archive.rb +140 -0
- data/lib/git/commands/arguments.rb +3510 -0
- data/lib/git/commands/base.rb +404 -0
- data/lib/git/commands/branch/copy.rb +94 -0
- data/lib/git/commands/branch/create.rb +173 -0
- data/lib/git/commands/branch/delete.rb +80 -0
- data/lib/git/commands/branch/list.rb +162 -0
- data/lib/git/commands/branch/move.rb +94 -0
- data/lib/git/commands/branch/set_upstream.rb +86 -0
- data/lib/git/commands/branch/show_current.rb +49 -0
- data/lib/git/commands/branch/unset_upstream.rb +57 -0
- data/lib/git/commands/branch.rb +34 -0
- data/lib/git/commands/cat_file/batch.rb +369 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +216 -0
- data/lib/git/commands/cat_file.rb +49 -0
- data/lib/git/commands/checkout/branch.rb +151 -0
- data/lib/git/commands/checkout/files.rb +115 -0
- data/lib/git/commands/checkout.rb +38 -0
- data/lib/git/commands/checkout_index.rb +105 -0
- data/lib/git/commands/clean.rb +100 -0
- data/lib/git/commands/clone.rb +240 -0
- data/lib/git/commands/commit.rb +272 -0
- data/lib/git/commands/commit_tree.rb +100 -0
- data/lib/git/commands/config_option_syntax/add.rb +83 -0
- data/lib/git/commands/config_option_syntax/get.rb +117 -0
- data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
- data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +107 -0
- data/lib/git/commands/config_option_syntax/list.rb +107 -0
- data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
- data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
- data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
- data/lib/git/commands/config_option_syntax/set.rb +114 -0
- data/lib/git/commands/config_option_syntax/unset.rb +89 -0
- data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
- data/lib/git/commands/config_option_syntax.rb +56 -0
- data/lib/git/commands/describe.rb +155 -0
- data/lib/git/commands/diff.rb +656 -0
- data/lib/git/commands/diff_files.rb +518 -0
- data/lib/git/commands/diff_index.rb +496 -0
- data/lib/git/commands/fetch.rb +352 -0
- data/lib/git/commands/fsck.rb +136 -0
- data/lib/git/commands/gc.rb +132 -0
- data/lib/git/commands/grep.rb +338 -0
- data/lib/git/commands/init.rb +99 -0
- data/lib/git/commands/log.rb +632 -0
- data/lib/git/commands/ls_files.rb +191 -0
- data/lib/git/commands/ls_remote.rb +155 -0
- data/lib/git/commands/ls_tree.rb +131 -0
- data/lib/git/commands/maintenance/register.rb +75 -0
- data/lib/git/commands/maintenance/run.rb +104 -0
- data/lib/git/commands/maintenance/start.rb +66 -0
- data/lib/git/commands/maintenance/stop.rb +55 -0
- data/lib/git/commands/maintenance/unregister.rb +79 -0
- data/lib/git/commands/maintenance.rb +31 -0
- data/lib/git/commands/merge/abort.rb +44 -0
- data/lib/git/commands/merge/continue.rb +44 -0
- data/lib/git/commands/merge/quit.rb +46 -0
- data/lib/git/commands/merge/start.rb +245 -0
- data/lib/git/commands/merge.rb +28 -0
- data/lib/git/commands/merge_base.rb +86 -0
- data/lib/git/commands/mv.rb +77 -0
- data/lib/git/commands/name_rev.rb +114 -0
- data/lib/git/commands/pull.rb +377 -0
- data/lib/git/commands/push.rb +246 -0
- data/lib/git/commands/read_tree.rb +149 -0
- data/lib/git/commands/remote/add.rb +91 -0
- data/lib/git/commands/remote/get_url.rb +66 -0
- data/lib/git/commands/remote/list.rb +54 -0
- data/lib/git/commands/remote/prune.rb +61 -0
- data/lib/git/commands/remote/remove.rb +52 -0
- data/lib/git/commands/remote/rename.rb +69 -0
- data/lib/git/commands/remote/set_branches.rb +63 -0
- data/lib/git/commands/remote/set_head.rb +82 -0
- data/lib/git/commands/remote/set_url.rb +71 -0
- data/lib/git/commands/remote/set_url_add.rb +61 -0
- data/lib/git/commands/remote/set_url_delete.rb +64 -0
- data/lib/git/commands/remote/show.rb +71 -0
- data/lib/git/commands/remote/update.rb +72 -0
- data/lib/git/commands/remote.rb +42 -0
- data/lib/git/commands/repack.rb +277 -0
- data/lib/git/commands/reset.rb +147 -0
- data/lib/git/commands/rev_parse.rb +297 -0
- data/lib/git/commands/revert/abort.rb +45 -0
- data/lib/git/commands/revert/continue.rb +57 -0
- data/lib/git/commands/revert/quit.rb +47 -0
- data/lib/git/commands/revert/skip.rb +44 -0
- data/lib/git/commands/revert/start.rb +153 -0
- data/lib/git/commands/revert.rb +29 -0
- data/lib/git/commands/rm.rb +114 -0
- data/lib/git/commands/show.rb +632 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
- data/lib/git/commands/show_ref/exists.rb +78 -0
- data/lib/git/commands/show_ref/list.rb +145 -0
- data/lib/git/commands/show_ref/verify.rb +120 -0
- data/lib/git/commands/show_ref.rb +42 -0
- data/lib/git/commands/stash/apply.rb +75 -0
- data/lib/git/commands/stash/branch.rb +65 -0
- data/lib/git/commands/stash/clear.rb +41 -0
- data/lib/git/commands/stash/create.rb +58 -0
- data/lib/git/commands/stash/drop.rb +67 -0
- data/lib/git/commands/stash/list.rb +39 -0
- data/lib/git/commands/stash/pop.rb +78 -0
- data/lib/git/commands/stash/push.rb +103 -0
- data/lib/git/commands/stash/show.rb +149 -0
- data/lib/git/commands/stash/store.rb +63 -0
- data/lib/git/commands/stash.rb +38 -0
- data/lib/git/commands/status.rb +169 -0
- data/lib/git/commands/symbolic_ref/delete.rb +68 -0
- data/lib/git/commands/symbolic_ref/read.rb +95 -0
- data/lib/git/commands/symbolic_ref/update.rb +76 -0
- data/lib/git/commands/symbolic_ref.rb +38 -0
- data/lib/git/commands/tag/create.rb +139 -0
- data/lib/git/commands/tag/delete.rb +55 -0
- data/lib/git/commands/tag/list.rb +143 -0
- data/lib/git/commands/tag/verify.rb +71 -0
- data/lib/git/commands/tag.rb +26 -0
- data/lib/git/commands/update_ref/batch.rb +140 -0
- data/lib/git/commands/update_ref/delete.rb +92 -0
- data/lib/git/commands/update_ref/update.rb +106 -0
- data/lib/git/commands/update_ref.rb +42 -0
- data/lib/git/commands/version.rb +57 -0
- data/lib/git/commands/worktree/add.rb +140 -0
- data/lib/git/commands/worktree/list.rb +64 -0
- data/lib/git/commands/worktree/lock.rb +58 -0
- data/lib/git/commands/worktree/management_base.rb +51 -0
- data/lib/git/commands/worktree/move.rb +66 -0
- data/lib/git/commands/worktree/prune.rb +67 -0
- data/lib/git/commands/worktree/remove.rb +63 -0
- data/lib/git/commands/worktree/repair.rb +76 -0
- data/lib/git/commands/worktree/unlock.rb +47 -0
- data/lib/git/commands/worktree.rb +43 -0
- data/lib/git/commands/write_tree.rb +68 -0
- data/lib/git/commands.rb +87 -0
- data/lib/git/config.rb +17 -0
- data/lib/git/config_entry_info.rb +106 -0
- data/lib/git/configuring.rb +665 -0
- data/lib/git/deprecation.rb +9 -0
- data/lib/git/detached_head_info.rb +54 -0
- data/lib/git/diff.rb +293 -7
- data/lib/git/diff_file_numstat_info.rb +29 -0
- data/lib/git/diff_file_patch_info.rb +134 -0
- data/lib/git/diff_file_raw_info.rb +127 -0
- data/lib/git/diff_info.rb +169 -0
- data/lib/git/diff_path_status.rb +67 -19
- data/lib/git/diff_result.rb +32 -0
- data/lib/git/diff_stats.rb +51 -14
- data/lib/git/dirstat_info.rb +86 -0
- data/lib/git/errors.rb +65 -2
- data/lib/git/execution_context/global.rb +31 -0
- data/lib/git/execution_context/repository.rb +136 -0
- data/lib/git/execution_context.rb +501 -0
- data/lib/git/file_ref.rb +74 -0
- data/lib/git/fsck_object.rb +9 -9
- data/lib/git/fsck_result.rb +1 -1
- data/lib/git/log.rb +9 -2
- data/lib/git/object.rb +90 -27
- data/lib/git/parsers/branch.rb +224 -0
- data/lib/git/parsers/cat_file.rb +111 -0
- data/lib/git/parsers/config_entry.rb +110 -0
- data/lib/git/parsers/diff.rb +585 -0
- data/lib/git/parsers/fsck.rb +133 -0
- data/lib/git/parsers/grep.rb +42 -0
- data/lib/git/parsers/ls_remote.rb +79 -0
- data/lib/git/parsers/ls_tree.rb +58 -0
- data/lib/git/parsers/stash.rb +208 -0
- data/lib/git/parsers/tag.rb +257 -0
- data/lib/git/remote.rb +120 -9
- data/lib/git/repository/branching.rb +743 -0
- data/lib/git/repository/committing.rb +187 -0
- data/lib/git/repository/configuring.rb +351 -0
- data/lib/git/repository/context_helpers.rb +264 -0
- data/lib/git/repository/diffing.rb +775 -0
- data/lib/git/repository/factories.rb +682 -0
- data/lib/git/repository/inspecting.rb +252 -0
- data/lib/git/repository/logging.rb +247 -0
- data/lib/git/repository/maintenance.rb +65 -0
- data/lib/git/repository/merging.rb +357 -0
- data/lib/git/repository/object_operations.rb +1199 -0
- data/lib/git/repository/path_resolver.rb +207 -0
- data/lib/git/repository/remote_operations.rb +898 -0
- data/lib/git/repository/shared_private.rb +51 -0
- data/lib/git/repository/staging.rb +554 -0
- data/lib/git/repository/stashing.rb +143 -0
- data/lib/git/repository/status_operations.rb +201 -0
- data/lib/git/repository/worktree_operations.rb +159 -0
- data/lib/git/repository.rb +203 -1
- data/lib/git/stash.rb +78 -4
- data/lib/git/stash_info.rb +104 -0
- data/lib/git/stashes.rb +125 -13
- data/lib/git/status.rb +215 -18
- data/lib/git/tag_delete_failure.rb +31 -0
- data/lib/git/tag_delete_result.rb +63 -0
- data/lib/git/tag_info.rb +105 -0
- data/lib/git/version.rb +109 -2
- data/lib/git/version_constraint.rb +81 -0
- data/lib/git/worktree.rb +108 -6
- data/lib/git/worktrees.rb +94 -7
- data/lib/git.rb +260 -61
- data/redesign/1_architecture_existing.md +54 -18
- data/redesign/2_architecture_redesign.md +365 -46
- data/redesign/3_architecture_implementation.md +1497 -63
- data/redesign/Phase 4 - Step A.md +360 -0
- data/redesign/beta_release.md +107 -0
- data/redesign/c1c2_audit.md +566 -0
- data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
- data/redesign/config_design.rb +501 -0
- data/tasks/gem_tasks.rake +4 -0
- data/tasks/npm_tasks.rake +7 -0
- data/tasks/rspec.rake +48 -0
- data/tasks/test.rake +13 -1
- data/tasks/yard.rake +34 -7
- metadata +365 -22
- data/lib/git/base.rb +0 -1128
- data/lib/git/index.rb +0 -6
- data/lib/git/lib.rb +0 -2277
- data/lib/git/path.rb +0 -38
- data/lib/git/working_directory.rb +0 -6
- /data/{release-please-config.json → .release-please-config.json} +0 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
require 'git/commands/diff'
|
|
5
|
+
require 'git/commands/merge/start'
|
|
6
|
+
require 'git/commands/merge_base'
|
|
7
|
+
require 'git/commands/revert/start'
|
|
8
|
+
require 'git/commands/show'
|
|
9
|
+
require 'git/repository/shared_private'
|
|
10
|
+
|
|
11
|
+
module Git
|
|
12
|
+
class Repository
|
|
13
|
+
# Facade methods for merge operations: merging branches into the current branch,
|
|
14
|
+
# and finding common ancestors between commits
|
|
15
|
+
#
|
|
16
|
+
# Included by {Git::Repository}.
|
|
17
|
+
#
|
|
18
|
+
# @api public
|
|
19
|
+
#
|
|
20
|
+
module Merging
|
|
21
|
+
# Option keys accepted by {#merge}
|
|
22
|
+
#
|
|
23
|
+
# Derived from the 4.x option map for `Git::Lib#merge`.
|
|
24
|
+
MERGE_ALLOWED_OPTS = %i[no_commit no_ff m message].freeze
|
|
25
|
+
private_constant :MERGE_ALLOWED_OPTS
|
|
26
|
+
|
|
27
|
+
# Option keys accepted by {#merge_base}
|
|
28
|
+
#
|
|
29
|
+
# Derived from the 4.x option map for `Git::Lib#merge_base`.
|
|
30
|
+
MERGE_BASE_ALLOWED_OPTS = %i[octopus independent fork_point all].freeze
|
|
31
|
+
private_constant :MERGE_BASE_ALLOWED_OPTS
|
|
32
|
+
|
|
33
|
+
# Merge one or more branches into the current branch
|
|
34
|
+
#
|
|
35
|
+
# The merge commit message may be given by the message positional argument, the
|
|
36
|
+
# `:message` option, or the `:m` option; if more than one is provided, the
|
|
37
|
+
# precedence is positional argument > `:message` > `:m`.
|
|
38
|
+
#
|
|
39
|
+
# @example Merge a single branch
|
|
40
|
+
# repo.merge('feature')
|
|
41
|
+
#
|
|
42
|
+
# @example Merge a branch with a no-fast-forward commit message
|
|
43
|
+
# repo.merge('feature', 'Merge feature into main', no_ff: true)
|
|
44
|
+
#
|
|
45
|
+
# @example Octopus merge of multiple branches
|
|
46
|
+
# repo.merge(%w[feature-a feature-b])
|
|
47
|
+
#
|
|
48
|
+
# @example Merge without committing
|
|
49
|
+
# repo.merge('feature', nil, no_commit: true)
|
|
50
|
+
#
|
|
51
|
+
# @param branch [String, Array<String>, #to_s] the branch or branches to merge
|
|
52
|
+
# into the current branch
|
|
53
|
+
#
|
|
54
|
+
# When an Array is given, an octopus merge is performed; a {Git::Branch}
|
|
55
|
+
# object is coerced to a String via `#to_s`.
|
|
56
|
+
#
|
|
57
|
+
# @param message [String, nil] optional commit message for the merge commit
|
|
58
|
+
#
|
|
59
|
+
# Translated to the `-m` flag internally. For fast-forward merges git ignores
|
|
60
|
+
# this value; use `no_ff: true` to ensure a merge commit is created and the
|
|
61
|
+
# message is recorded.
|
|
62
|
+
#
|
|
63
|
+
# @param opts [Hash] additional options forwarded to `git merge`
|
|
64
|
+
#
|
|
65
|
+
# @option opts [Boolean, nil] :no_commit (nil) stop before creating the merge commit
|
|
66
|
+
# (`--no-commit`)
|
|
67
|
+
#
|
|
68
|
+
# @option opts [Boolean, nil] :no_ff (nil) create a merge commit even when
|
|
69
|
+
# fast-forward is possible (`--no-ff`)
|
|
70
|
+
#
|
|
71
|
+
# @option opts [String] :message (nil) commit message
|
|
72
|
+
#
|
|
73
|
+
# Prefer the `:m` option instead of this one. Translated to the `-m` flag.
|
|
74
|
+
# Identical to the positional `message` argument and the `:m` option.
|
|
75
|
+
#
|
|
76
|
+
# @option opts [String] :m (nil) commit message (`-m` flag)
|
|
77
|
+
#
|
|
78
|
+
# @return [String] git's stdout from the merge command
|
|
79
|
+
#
|
|
80
|
+
# @raise [ArgumentError] when unsupported options are provided
|
|
81
|
+
#
|
|
82
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
83
|
+
#
|
|
84
|
+
def merge(branch, message = nil, opts = {})
|
|
85
|
+
SharedPrivate.assert_valid_opts!(MERGE_ALLOWED_OPTS, **opts)
|
|
86
|
+
|
|
87
|
+
# Dup so callers who reuse the same opts hash are not affected
|
|
88
|
+
opts = opts.dup
|
|
89
|
+
|
|
90
|
+
# Merge positional message into opts so the rest of the logic is uniform
|
|
91
|
+
opts[:message] = message if message
|
|
92
|
+
|
|
93
|
+
# git merge uses -m, not --message; translate the key
|
|
94
|
+
opts[:m] = opts.delete(:message) if opts.key?(:message)
|
|
95
|
+
|
|
96
|
+
branches = Array(branch).map(&:to_s)
|
|
97
|
+
Git::Commands::Merge::Start.new(@execution_context).call(*branches, no_edit: true, **opts).stdout
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Find common ancestor commit(s) for use in a merge
|
|
101
|
+
#
|
|
102
|
+
# @example Find the common ancestor of two branches
|
|
103
|
+
# repo.merge_base('main', 'feature') #=> ["abc123def456..."]
|
|
104
|
+
#
|
|
105
|
+
# @example Find all common ancestors of two branches
|
|
106
|
+
# repo.merge_base('branch-a', 'branch-b', all: true)
|
|
107
|
+
#
|
|
108
|
+
# @example Find the fork point of a branch (consults the reflog)
|
|
109
|
+
# repo.merge_base('main', 'feature', fork_point: true)
|
|
110
|
+
#
|
|
111
|
+
# @example Find independent commits not reachable from each other
|
|
112
|
+
# repo.merge_base('abc1234', 'main', 'feature', independent: true)
|
|
113
|
+
#
|
|
114
|
+
# @overload merge_base(*commits, options = {})
|
|
115
|
+
#
|
|
116
|
+
# @param commits [Array<String>] two or more commit SHAs, branch names,
|
|
117
|
+
# or refs to find the common ancestor(s) of
|
|
118
|
+
#
|
|
119
|
+
# @param options [Hash] merge-base options
|
|
120
|
+
#
|
|
121
|
+
# @option options [Boolean, nil] :octopus (nil) compute the best common
|
|
122
|
+
# ancestor for an n-way merge (intersection of all merge bases)
|
|
123
|
+
#
|
|
124
|
+
# @option options [Boolean, nil] :independent (nil) list commits not
|
|
125
|
+
# reachable from any other; useful for finding minimal merge points
|
|
126
|
+
#
|
|
127
|
+
# @option options [Boolean, nil] :fork_point (nil) find the fork point
|
|
128
|
+
# where a branch diverged from another, consulting the reflog
|
|
129
|
+
#
|
|
130
|
+
# @option options [Boolean, nil] :all (nil) output all merge bases instead
|
|
131
|
+
# of just the first when multiple equally good bases exist
|
|
132
|
+
#
|
|
133
|
+
# @return [Array<String>] commit SHAs of the common ancestor(s); empty
|
|
134
|
+
# when no common ancestor exists or `--fork-point` finds none
|
|
135
|
+
#
|
|
136
|
+
# @raise [ArgumentError] when unsupported options are provided
|
|
137
|
+
#
|
|
138
|
+
# @raise [Git::FailedError] when `git merge-base` exits outside the
|
|
139
|
+
# allowed range (exit code > 1)
|
|
140
|
+
#
|
|
141
|
+
def merge_base(*args)
|
|
142
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
|
143
|
+
SharedPrivate.assert_valid_opts!(MERGE_BASE_ALLOWED_OPTS, **opts)
|
|
144
|
+
result = Git::Commands::MergeBase.new(@execution_context).call(*args, **opts)
|
|
145
|
+
result.stdout.lines.map(&:strip).reject(&:empty?)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Return the paths of files with unresolved merge conflicts
|
|
149
|
+
#
|
|
150
|
+
# @example List conflicting files after a failed merge
|
|
151
|
+
# paths = repo.unmerged
|
|
152
|
+
# # => ["config/settings.rb", "lib/git/base.rb"]
|
|
153
|
+
# paths.each { |path| puts "Conflict in #{path}" }
|
|
154
|
+
#
|
|
155
|
+
# @return [Array<String>] repository-relative paths of files with unresolved
|
|
156
|
+
# merge conflicts; empty array when the working tree has no conflicts
|
|
157
|
+
#
|
|
158
|
+
# @raise [Git::FailedError] if git exits outside the allowed range (exit code > 2)
|
|
159
|
+
#
|
|
160
|
+
# @see #each_conflict
|
|
161
|
+
#
|
|
162
|
+
def unmerged
|
|
163
|
+
Private.unmerged_paths(@execution_context)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Iterate over files with merge conflicts, yielding conflict details for each
|
|
167
|
+
#
|
|
168
|
+
# For each unmerged file, the staged content for both sides of the conflict
|
|
169
|
+
# (stage 2 "ours" and stage 3 "theirs") is written to temporary files whose
|
|
170
|
+
# paths are yielded alongside the file path. The temporary files are deleted
|
|
171
|
+
# automatically when the block returns.
|
|
172
|
+
#
|
|
173
|
+
# @example Inspect conflicting files
|
|
174
|
+
# repo.each_conflict do |file, your_version, their_version|
|
|
175
|
+
# puts "Conflict in #{file}"
|
|
176
|
+
# puts "Your version:"
|
|
177
|
+
# puts File.read(your_version)
|
|
178
|
+
# puts "Their version:"
|
|
179
|
+
# puts File.read(their_version)
|
|
180
|
+
# end
|
|
181
|
+
#
|
|
182
|
+
# @return [Array<String>] the list of unmerged file paths
|
|
183
|
+
#
|
|
184
|
+
# @raise [Git::FailedError] when `git diff --cached` exits outside the
|
|
185
|
+
# allowed range (exit code > 2)
|
|
186
|
+
#
|
|
187
|
+
# @yield [file, your_version, their_version] passes conflict details for
|
|
188
|
+
# each unmerged file
|
|
189
|
+
#
|
|
190
|
+
# @yieldparam file [String] path to the conflicting file, relative to the
|
|
191
|
+
# working tree
|
|
192
|
+
#
|
|
193
|
+
# @yieldparam your_version [String] path to a temporary file containing the
|
|
194
|
+
# stage-2 (ours) content for the conflicting file
|
|
195
|
+
#
|
|
196
|
+
# @yieldparam their_version [String] path to a temporary file containing the
|
|
197
|
+
# stage-3 (theirs) content for the conflicting file
|
|
198
|
+
#
|
|
199
|
+
# @yieldreturn [void]
|
|
200
|
+
#
|
|
201
|
+
def each_conflict
|
|
202
|
+
Private.unmerged_paths(@execution_context).each do |file_path|
|
|
203
|
+
Private.write_staged_file(@execution_context, file_path, 2) do |your_file|
|
|
204
|
+
Private.write_staged_file(@execution_context, file_path, 3) do |their_file|
|
|
205
|
+
yield(file_path, your_file.path, their_file.path)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Iterate over files with merge conflicts, yielding conflict details for each
|
|
212
|
+
#
|
|
213
|
+
# For each unmerged file, the staged content for both sides of the conflict
|
|
214
|
+
# (stage 2 "ours" and stage 3 "theirs") is written to temporary files whose
|
|
215
|
+
# paths are yielded alongside the file path. The temporary files are deleted
|
|
216
|
+
# automatically when the block returns.
|
|
217
|
+
#
|
|
218
|
+
# @example Inspect conflicting files
|
|
219
|
+
# repo.conflicts do |file, your_version, their_version|
|
|
220
|
+
# puts "Conflict in #{file}"
|
|
221
|
+
# puts File.read(your_version)
|
|
222
|
+
# puts File.read(their_version)
|
|
223
|
+
# end
|
|
224
|
+
#
|
|
225
|
+
# @return [Array<String>] the list of unmerged file paths
|
|
226
|
+
#
|
|
227
|
+
# @raise [Git::FailedError] when `git diff --cached` exits outside the
|
|
228
|
+
# allowed range (exit code > 2)
|
|
229
|
+
#
|
|
230
|
+
# @yield [file, your_version, their_version] passes conflict details for
|
|
231
|
+
# each unmerged file
|
|
232
|
+
#
|
|
233
|
+
# @yieldparam file [String] path to the conflicting file, relative to the
|
|
234
|
+
# working tree
|
|
235
|
+
#
|
|
236
|
+
# @yieldparam your_version [String] path to a temporary file containing the
|
|
237
|
+
# stage-2 (ours) content for the conflicting file
|
|
238
|
+
#
|
|
239
|
+
# @yieldparam their_version [String] path to a temporary file containing the
|
|
240
|
+
# stage-3 (theirs) content for the conflicting file
|
|
241
|
+
#
|
|
242
|
+
# @yieldreturn [void]
|
|
243
|
+
#
|
|
244
|
+
# @deprecated Use {#each_conflict} instead
|
|
245
|
+
#
|
|
246
|
+
def conflicts(&)
|
|
247
|
+
Git::Deprecation.warn(
|
|
248
|
+
'Git::Repository#conflicts is deprecated and will be removed in a future version. ' \
|
|
249
|
+
'Use Git::Repository#each_conflict instead.'
|
|
250
|
+
)
|
|
251
|
+
each_conflict(&)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Option keys accepted by {#revert}
|
|
255
|
+
#
|
|
256
|
+
# Derived from the 4.x option map for `Git::Lib#revert`.
|
|
257
|
+
REVERT_ALLOWED_OPTS = %i[no_edit].freeze
|
|
258
|
+
private_constant :REVERT_ALLOWED_OPTS
|
|
259
|
+
|
|
260
|
+
# Revert one or more existing commits by creating new commits that undo
|
|
261
|
+
# the changes those commits introduced
|
|
262
|
+
#
|
|
263
|
+
# The working tree must be clean before calling this method. By default
|
|
264
|
+
# the editor is suppressed (`--no-edit`) so the commit message is taken
|
|
265
|
+
# from git's default revert message without prompting.
|
|
266
|
+
#
|
|
267
|
+
# @example Revert the most recent commit
|
|
268
|
+
# repo.revert('HEAD')
|
|
269
|
+
#
|
|
270
|
+
# @example Revert a specific commit by SHA
|
|
271
|
+
# repo.revert('abc1234')
|
|
272
|
+
#
|
|
273
|
+
# @example Revert a range of commits
|
|
274
|
+
# repo.revert('HEAD~3..HEAD~1')
|
|
275
|
+
#
|
|
276
|
+
# @example Revert without suppressing the editor
|
|
277
|
+
# repo.revert('HEAD', no_edit: false)
|
|
278
|
+
#
|
|
279
|
+
# @param commitish [String, nil] the commit, ref, or rev range to revert;
|
|
280
|
+
# see `gitrevisions(7)` for accepted forms; defaults to `'HEAD'` when
|
|
281
|
+
# `nil`
|
|
282
|
+
#
|
|
283
|
+
# @param opts [Hash] additional options forwarded to `git revert`
|
|
284
|
+
#
|
|
285
|
+
# @option opts [Boolean, nil] :no_edit (true) suppress the commit-message
|
|
286
|
+
# editor (`--no-edit`); pass `false` to open the editor
|
|
287
|
+
#
|
|
288
|
+
# @return [String] git's stdout from the revert command
|
|
289
|
+
#
|
|
290
|
+
# @raise [ArgumentError] when unsupported options are provided
|
|
291
|
+
#
|
|
292
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
293
|
+
#
|
|
294
|
+
def revert(commitish = nil, opts = {})
|
|
295
|
+
commitish = 'HEAD' if commitish.nil?
|
|
296
|
+
SharedPrivate.assert_valid_opts!(REVERT_ALLOWED_OPTS, **opts)
|
|
297
|
+
opts = { no_edit: true }.merge(opts)
|
|
298
|
+
Git::Commands::Revert::Start.new(@execution_context).call(commitish, **opts).stdout
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Private helpers local to {Git::Repository::Merging}
|
|
302
|
+
#
|
|
303
|
+
# @api private
|
|
304
|
+
module Private
|
|
305
|
+
# Tempfile name prefixes for staged content, keyed by git stage index
|
|
306
|
+
STAGE_PREFIXES = { 2 => 'YOUR-', 3 => 'THEIR-' }.freeze
|
|
307
|
+
|
|
308
|
+
module_function
|
|
309
|
+
|
|
310
|
+
# Returns the list of file paths with unresolved merge conflicts
|
|
311
|
+
#
|
|
312
|
+
# @param execution_context [Git::ExecutionContext] the execution context
|
|
313
|
+
# used to run git commands
|
|
314
|
+
#
|
|
315
|
+
# @return [Array<String>] unmerged file paths
|
|
316
|
+
#
|
|
317
|
+
# @api private
|
|
318
|
+
#
|
|
319
|
+
def unmerged_paths(execution_context)
|
|
320
|
+
result = Git::Commands::Diff.new(execution_context).call(cached: true)
|
|
321
|
+
result.stdout.split("\n").filter_map do |line|
|
|
322
|
+
::Regexp.last_match(1) if line =~ /^\* Unmerged path (.*)/
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Creates a Tempfile with the staged content for `file_path` at `stage`
|
|
327
|
+
# and yields the open IO object to the block
|
|
328
|
+
#
|
|
329
|
+
# @param execution_context [Git::ExecutionContext] the execution context
|
|
330
|
+
# used to run git commands
|
|
331
|
+
#
|
|
332
|
+
# @param file_path [String] repository-relative path to the conflicting file
|
|
333
|
+
#
|
|
334
|
+
# @param stage [Integer] git stage index (2 = ours, 3 = theirs)
|
|
335
|
+
#
|
|
336
|
+
# @yield [f] yields the open Tempfile containing the staged content
|
|
337
|
+
#
|
|
338
|
+
# @yieldparam f [Tempfile] open IO object for the staged content
|
|
339
|
+
#
|
|
340
|
+
# @yieldreturn [void]
|
|
341
|
+
#
|
|
342
|
+
# @return [void]
|
|
343
|
+
#
|
|
344
|
+
# @api private
|
|
345
|
+
#
|
|
346
|
+
def write_staged_file(execution_context, file_path, stage)
|
|
347
|
+
Tempfile.create([STAGE_PREFIXES[stage], File.basename(file_path)]) do |f|
|
|
348
|
+
Git::Commands::Show.new(execution_context).call(":#{stage}:#{file_path}", out: f)
|
|
349
|
+
f.flush
|
|
350
|
+
yield f
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
private_constant :Private
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|