git 1.19.1 → 5.5.0
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/.yardopts +5 -1
- data/AI_POLICY.md +24 -0
- data/CHANGELOG.md +689 -0
- data/CODE_OF_CONDUCT.md +25 -0
- data/CONTRIBUTING.md +1175 -97
- data/GOVERNANCE.md +106 -0
- data/LICENSE +1 -1
- data/MAINTAINERS.md +17 -4
- data/README.md +476 -320
- data/UPGRADING.md +1138 -0
- data/git.gemspec +124 -36
- data/lib/git/author.rb +39 -7
- data/lib/git/author_info.rb +66 -0
- data/lib/git/branch.rb +615 -65
- data/lib/git/branch_delete_failure.rb +34 -0
- data/lib/git/branch_delete_result.rb +66 -0
- data/lib/git/branch_info.rb +237 -0
- data/lib/git/branches.rb +167 -44
- data/lib/git/command_line/base.rb +247 -0
- data/lib/git/command_line/capturing.rb +308 -0
- data/lib/git/command_line/result.rb +88 -0
- data/lib/git/command_line/streaming.rb +236 -0
- data/lib/git/command_line.rb +52 -0
- data/lib/git/commands/add.rb +139 -0
- data/lib/git/commands/am/abort.rb +43 -0
- data/lib/git/commands/am/apply.rb +263 -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 +49 -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 +242 -0
- data/lib/git/commands/archive/list_formats.rb +46 -0
- data/lib/git/commands/archive.rb +145 -0
- data/lib/git/commands/arguments.rb +4521 -0
- data/lib/git/commands/base.rb +502 -0
- data/lib/git/commands/branch/copy.rb +102 -0
- data/lib/git/commands/branch/create.rb +177 -0
- data/lib/git/commands/branch/delete.rb +88 -0
- data/lib/git/commands/branch/list.rb +178 -0
- data/lib/git/commands/branch/move.rb +102 -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 +53 -0
- data/lib/git/commands/branch.rb +34 -0
- data/lib/git/commands/cat_file/batch.rb +385 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +271 -0
- data/lib/git/commands/cat_file.rb +49 -0
- data/lib/git/commands/checkout/branch.rb +153 -0
- data/lib/git/commands/checkout/files.rb +116 -0
- data/lib/git/commands/checkout.rb +38 -0
- data/lib/git/commands/checkout_index.rb +106 -0
- data/lib/git/commands/clean.rb +102 -0
- data/lib/git/commands/clone.rb +241 -0
- data/lib/git/commands/commit.rb +273 -0
- data/lib/git/commands/commit_tree.rb +101 -0
- data/lib/git/commands/config_option_syntax/add.rb +86 -0
- data/lib/git/commands/config_option_syntax/get.rb +121 -0
- data/lib/git/commands/config_option_syntax/get_all.rb +118 -0
- data/lib/git/commands/config_option_syntax/get_color.rb +95 -0
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +96 -0
- data/lib/git/commands/config_option_syntax/get_regexp.rb +119 -0
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +111 -0
- data/lib/git/commands/config_option_syntax/list.rb +111 -0
- data/lib/git/commands/config_option_syntax/remove_section.rb +79 -0
- data/lib/git/commands/config_option_syntax/rename_section.rb +83 -0
- data/lib/git/commands/config_option_syntax/replace_all.rb +109 -0
- data/lib/git/commands/config_option_syntax/set.rb +119 -0
- data/lib/git/commands/config_option_syntax/unset.rb +92 -0
- data/lib/git/commands/config_option_syntax/unset_all.rb +94 -0
- data/lib/git/commands/config_option_syntax.rb +56 -0
- data/lib/git/commands/describe.rb +156 -0
- data/lib/git/commands/diff.rb +657 -0
- data/lib/git/commands/diff_files.rb +519 -0
- data/lib/git/commands/diff_index.rb +499 -0
- data/lib/git/commands/fetch.rb +354 -0
- data/lib/git/commands/fsck.rb +138 -0
- data/lib/git/commands/gc.rb +134 -0
- data/lib/git/commands/grep.rb +339 -0
- data/lib/git/commands/init.rb +101 -0
- data/lib/git/commands/log.rb +634 -0
- data/lib/git/commands/ls_files.rb +195 -0
- data/lib/git/commands/ls_remote.rb +161 -0
- data/lib/git/commands/ls_tree.rb +135 -0
- data/lib/git/commands/maintenance/register.rb +77 -0
- data/lib/git/commands/maintenance/run.rb +109 -0
- data/lib/git/commands/maintenance/start.rb +71 -0
- data/lib/git/commands/maintenance/stop.rb +60 -0
- data/lib/git/commands/maintenance/unregister.rb +84 -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 +250 -0
- data/lib/git/commands/merge.rb +28 -0
- data/lib/git/commands/merge_base.rb +91 -0
- data/lib/git/commands/mv.rb +82 -0
- data/lib/git/commands/name_rev.rb +119 -0
- data/lib/git/commands/pull.rb +382 -0
- data/lib/git/commands/push.rb +251 -0
- data/lib/git/commands/read_tree.rb +154 -0
- data/lib/git/commands/remote/add.rb +96 -0
- data/lib/git/commands/remote/get_url.rb +68 -0
- data/lib/git/commands/remote/list.rb +56 -0
- data/lib/git/commands/remote/prune.rb +63 -0
- data/lib/git/commands/remote/remove.rb +52 -0
- data/lib/git/commands/remote/rename.rb +76 -0
- data/lib/git/commands/remote/set_branches.rb +70 -0
- data/lib/git/commands/remote/set_head.rb +89 -0
- data/lib/git/commands/remote/set_url.rb +78 -0
- data/lib/git/commands/remote/set_url_add.rb +70 -0
- data/lib/git/commands/remote/set_url_delete.rb +71 -0
- data/lib/git/commands/remote/show.rb +77 -0
- data/lib/git/commands/remote/update.rb +79 -0
- data/lib/git/commands/remote.rb +42 -0
- data/lib/git/commands/repack.rb +281 -0
- data/lib/git/commands/reset.rb +154 -0
- data/lib/git/commands/rev_parse.rb +304 -0
- data/lib/git/commands/revert/abort.rb +45 -0
- data/lib/git/commands/revert/continue.rb +62 -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 +158 -0
- data/lib/git/commands/revert.rb +29 -0
- data/lib/git/commands/rm.rb +113 -0
- data/lib/git/commands/show.rb +632 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +119 -0
- data/lib/git/commands/show_ref/exists.rb +80 -0
- data/lib/git/commands/show_ref/list.rb +149 -0
- data/lib/git/commands/show_ref/verify.rb +122 -0
- data/lib/git/commands/show_ref.rb +42 -0
- data/lib/git/commands/stash/apply.rb +81 -0
- data/lib/git/commands/stash/branch.rb +67 -0
- data/lib/git/commands/stash/clear.rb +43 -0
- data/lib/git/commands/stash/create.rb +60 -0
- data/lib/git/commands/stash/drop.rb +73 -0
- data/lib/git/commands/stash/list.rb +43 -0
- data/lib/git/commands/stash/pop.rb +87 -0
- data/lib/git/commands/stash/push.rb +112 -0
- data/lib/git/commands/stash/show.rb +158 -0
- data/lib/git/commands/stash/store.rb +72 -0
- data/lib/git/commands/stash.rb +38 -0
- data/lib/git/commands/status.rb +174 -0
- data/lib/git/commands/symbolic_ref/delete.rb +72 -0
- data/lib/git/commands/symbolic_ref/read.rb +99 -0
- data/lib/git/commands/symbolic_ref/update.rb +79 -0
- data/lib/git/commands/symbolic_ref.rb +38 -0
- data/lib/git/commands/tag/create.rb +142 -0
- data/lib/git/commands/tag/delete.rb +57 -0
- data/lib/git/commands/tag/list.rb +146 -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 +145 -0
- data/lib/git/commands/update_ref/delete.rb +90 -0
- data/lib/git/commands/update_ref/update.rb +103 -0
- data/lib/git/commands/update_ref.rb +42 -0
- data/lib/git/commands/version.rb +60 -0
- data/lib/git/commands/worktree/add.rb +139 -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 +88 -0
- data/lib/git/config.rb +72 -5
- data/lib/git/config_entry_info.rb +106 -0
- data/lib/git/configuring.rb +795 -0
- data/lib/git/detached_head_info.rb +57 -0
- data/lib/git/diff.rb +437 -86
- data/lib/git/diff_file_numstat_info.rb +31 -0
- data/lib/git/diff_file_patch_info.rb +136 -0
- data/lib/git/diff_file_raw_info.rb +129 -0
- data/lib/git/diff_info.rb +162 -0
- data/lib/git/diff_path_status.rb +107 -0
- data/lib/git/diff_result.rb +34 -0
- data/lib/git/diff_stats.rb +111 -0
- data/lib/git/dirstat_info.rb +102 -0
- data/lib/git/encoding_utils.rb +32 -1
- data/lib/git/errors.rb +285 -0
- data/lib/git/escaped_path.rb +57 -5
- data/lib/git/execution_context/global.rb +31 -0
- data/lib/git/execution_context/repository.rb +151 -0
- data/lib/git/execution_context.rb +559 -0
- data/lib/git/factories.rb +813 -0
- data/lib/git/file_ref.rb +77 -0
- data/lib/git/fsck_object.rb +56 -0
- data/lib/git/fsck_result.rb +132 -0
- data/lib/git/log.rb +306 -90
- data/lib/git/object.rb +563 -141
- data/lib/git/parsers/branch.rb +240 -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 +792 -0
- data/lib/git/parsers/fsck.rb +144 -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/remote.rb +162 -0
- data/lib/git/parsers/stash.rb +292 -0
- data/lib/git/parsers/status.rb +251 -0
- data/lib/git/parsers/tag.rb +341 -0
- data/lib/git/parsers/worktree.rb +185 -0
- data/lib/git/path_resolver.rb +206 -0
- data/lib/git/remote.rb +165 -12
- data/lib/git/remote_info.rb +203 -0
- data/lib/git/repository/branching.rb +964 -0
- data/lib/git/repository/committing.rb +246 -0
- data/lib/git/repository/context_helpers.rb +293 -0
- data/lib/git/repository/diffing.rb +785 -0
- data/lib/git/repository/inspecting.rb +252 -0
- data/lib/git/repository/logging.rb +410 -0
- data/lib/git/repository/maintenance.rb +65 -0
- data/lib/git/repository/merging.rb +451 -0
- data/lib/git/repository/object_operations.rb +1551 -0
- data/lib/git/repository/remote_operations.rb +984 -0
- data/lib/git/repository/shared_private.rb +120 -0
- data/lib/git/repository/staging.rb +587 -0
- data/lib/git/repository/stashing.rb +623 -0
- data/lib/git/repository/status_operations.rb +249 -0
- data/lib/git/repository/worktree_operations.rb +339 -0
- data/lib/git/repository.rb +484 -2
- data/lib/git/stash.rb +109 -12
- data/lib/git/stash_info.rb +102 -0
- data/lib/git/stashes.rb +169 -26
- data/lib/git/status.rb +308 -122
- data/lib/git/status_file_info.rb +258 -0
- data/lib/git/status_info.rb +189 -0
- data/lib/git/tag_delete_failure.rb +34 -0
- data/lib/git/tag_delete_result.rb +66 -0
- data/lib/git/tag_info.rb +99 -0
- data/lib/git/url.rb +15 -8
- data/lib/git/version.rb +113 -2
- data/lib/git/version_constraint.rb +85 -0
- data/lib/git/worktree.rb +150 -8
- data/lib/git/worktree_info.rb +128 -0
- data/lib/git/worktrees.rb +118 -13
- data/lib/git.rb +632 -234
- metadata +369 -54
- data/.github/stale.yml +0 -25
- data/.github/workflows/continuous_integration.yml +0 -49
- data/.gitignore +0 -10
- data/Dockerfile.changelog-rs +0 -12
- data/Gemfile +0 -5
- data/ISSUE_TEMPLATE.md +0 -15
- data/PULL_REQUEST_TEMPLATE.md +0 -9
- data/RELEASING.md +0 -70
- data/Rakefile +0 -60
- data/lib/git/base/factory.rb +0 -99
- data/lib/git/base.rb +0 -711
- data/lib/git/command_line_result.rb +0 -86
- data/lib/git/failed_error.rb +0 -53
- data/lib/git/git_execute_error.rb +0 -7
- data/lib/git/index.rb +0 -5
- data/lib/git/lib.rb +0 -1328
- data/lib/git/path.rb +0 -31
- data/lib/git/signaled_error.rb +0 -50
- data/lib/git/working_directory.rb +0 -4
|
@@ -0,0 +1,984 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/commands/config_option_syntax'
|
|
4
|
+
require 'git/commands/fetch'
|
|
5
|
+
require 'git/commands/ls_remote'
|
|
6
|
+
require 'git/commands/pull'
|
|
7
|
+
require 'git/commands/push'
|
|
8
|
+
require 'git/commands/remote'
|
|
9
|
+
require 'git/parsers/ls_remote'
|
|
10
|
+
require 'git/parsers/remote'
|
|
11
|
+
require 'git/remote'
|
|
12
|
+
|
|
13
|
+
require 'git/repository/shared_private'
|
|
14
|
+
|
|
15
|
+
module Git
|
|
16
|
+
class Repository
|
|
17
|
+
# Mixin that adds remote operation facade methods to {Git::Repository}
|
|
18
|
+
#
|
|
19
|
+
# Included by {Git::Repository}.
|
|
20
|
+
#
|
|
21
|
+
# @api private
|
|
22
|
+
#
|
|
23
|
+
module RemoteOperations # rubocop:disable Metrics/ModuleLength
|
|
24
|
+
# Key normalizations for {#fetch} options
|
|
25
|
+
#
|
|
26
|
+
# Maps dash-style option keys (which the 4.x `Git::Lib#fetch` accepted)
|
|
27
|
+
# to their canonical underscore-style equivalents.
|
|
28
|
+
#
|
|
29
|
+
# @return [Hash{Symbol => Symbol}]
|
|
30
|
+
#
|
|
31
|
+
# @api private
|
|
32
|
+
#
|
|
33
|
+
FETCH_KEY_NORMALIZATIONS = { 'update-head-ok': :update_head_ok, 'prune-tags': :prune_tags }.freeze
|
|
34
|
+
private_constant :FETCH_KEY_NORMALIZATIONS
|
|
35
|
+
|
|
36
|
+
# Option keys accepted by {#fetch}
|
|
37
|
+
#
|
|
38
|
+
# Derived from the 4.x `FETCH_OPTION_MAP` in `Git::Lib`.
|
|
39
|
+
#
|
|
40
|
+
# @return [Array<Symbol>]
|
|
41
|
+
#
|
|
42
|
+
# @api private
|
|
43
|
+
#
|
|
44
|
+
FETCH_ALLOWED_OPTS = %i[all tags t prune p prune_tags P force f update_head_ok u unshallow depth ref].freeze
|
|
45
|
+
private_constant :FETCH_ALLOWED_OPTS
|
|
46
|
+
|
|
47
|
+
# Download objects and refs from a remote repository
|
|
48
|
+
#
|
|
49
|
+
# Fetches branches and/or tags from one or more other repositories, along
|
|
50
|
+
# with the objects necessary to complete their histories. The local
|
|
51
|
+
# tracking references are updated but the working directory is not
|
|
52
|
+
# modified.
|
|
53
|
+
#
|
|
54
|
+
# @example Fetch from the default remote
|
|
55
|
+
# repo.fetch
|
|
56
|
+
#
|
|
57
|
+
# @example Fetch from a named remote
|
|
58
|
+
# repo.fetch('upstream')
|
|
59
|
+
#
|
|
60
|
+
# @example Fetch all remotes at once
|
|
61
|
+
# repo.fetch(all: true)
|
|
62
|
+
#
|
|
63
|
+
# @example Fetch and prune deleted remote branches
|
|
64
|
+
# repo.fetch('origin', prune: true)
|
|
65
|
+
#
|
|
66
|
+
# @example Fetch a specific refspec
|
|
67
|
+
# repo.fetch('origin', ref: 'refs/heads/main:refs/remotes/origin/main')
|
|
68
|
+
#
|
|
69
|
+
# @example Fetch multiple refspecs
|
|
70
|
+
# repo.fetch('origin', ref: ['refs/heads/main', 'refs/heads/develop'])
|
|
71
|
+
#
|
|
72
|
+
# @example Fetch and include all tags
|
|
73
|
+
# repo.fetch('origin', tags: true)
|
|
74
|
+
#
|
|
75
|
+
# @param remote [String, Hash, nil] the remote name or URL to fetch from
|
|
76
|
+
#
|
|
77
|
+
# When a Hash is given it is treated as `opts` and `remote` defaults to
|
|
78
|
+
# `nil` (which omits the remote positional argument and lets git use the
|
|
79
|
+
# configured default).
|
|
80
|
+
#
|
|
81
|
+
# @param opts [Hash] options for the fetch command
|
|
82
|
+
#
|
|
83
|
+
# @option opts [Boolean, nil] :all (nil) fetch from all configured remotes
|
|
84
|
+
# (`--all`)
|
|
85
|
+
#
|
|
86
|
+
# @option opts [Boolean, nil] :tags (nil) fetch all tags from the remote
|
|
87
|
+
# (`--tags`)
|
|
88
|
+
#
|
|
89
|
+
# Alias: `:t`
|
|
90
|
+
#
|
|
91
|
+
# @option opts [Boolean, nil] :prune (nil) remove remote-tracking references
|
|
92
|
+
# that no longer exist on the remote (`--prune`)
|
|
93
|
+
#
|
|
94
|
+
# Alias: `:p`
|
|
95
|
+
#
|
|
96
|
+
# @option opts [Boolean, nil] :prune_tags (nil) remove local tags that no
|
|
97
|
+
# longer exist on the remote (`--prune-tags`)
|
|
98
|
+
#
|
|
99
|
+
# Alias: `:P`. The legacy dash-style key `:'prune-tags'` is also accepted
|
|
100
|
+
# and normalized automatically.
|
|
101
|
+
#
|
|
102
|
+
# @option opts [Boolean, nil] :force (nil) override the fast-forward check
|
|
103
|
+
# when using explicit refspecs (`--force`)
|
|
104
|
+
#
|
|
105
|
+
# Alias: `:f`
|
|
106
|
+
#
|
|
107
|
+
# @option opts [Boolean, nil] :update_head_ok (nil) allow `git fetch` to
|
|
108
|
+
# update the branch pointed to by `HEAD` (`--update-head-ok`)
|
|
109
|
+
#
|
|
110
|
+
# Alias: `:u`. The legacy dash-style key `:'update-head-ok'` is also
|
|
111
|
+
# accepted and normalized automatically.
|
|
112
|
+
#
|
|
113
|
+
# @option opts [Boolean, nil] :unshallow (nil) convert a shallow clone into a
|
|
114
|
+
# full repository (`--unshallow`)
|
|
115
|
+
#
|
|
116
|
+
# @option opts [String, Integer] :depth (nil) limit history to N commits from
|
|
117
|
+
# each branch tip (`--depth=N`)
|
|
118
|
+
#
|
|
119
|
+
# @option opts [String, Array<String>] :ref (nil) one or more refspecs to
|
|
120
|
+
# fetch; forwarded as positional arguments after the remote name. An explicit
|
|
121
|
+
# `remote` is required when `:ref` is given.
|
|
122
|
+
#
|
|
123
|
+
# @return [String] the merged stdout from the fetch command
|
|
124
|
+
#
|
|
125
|
+
# @raise [ArgumentError] when unsupported option keys are provided or `:ref`
|
|
126
|
+
# is supplied without an explicit remote
|
|
127
|
+
#
|
|
128
|
+
# @raise [Git::FailedError] when git exits with a non-zero status
|
|
129
|
+
#
|
|
130
|
+
def fetch(remote = 'origin', opts = {})
|
|
131
|
+
remote, opts = Private.resolve_fetch_target(remote, opts)
|
|
132
|
+
|
|
133
|
+
opts = Private.normalize_fetch_keys(opts)
|
|
134
|
+
SharedPrivate.assert_valid_opts!(FETCH_ALLOWED_OPTS, **opts)
|
|
135
|
+
|
|
136
|
+
opts = opts.dup
|
|
137
|
+
refspecs = Array(opts.delete(:ref)).compact
|
|
138
|
+
positionals = [*([remote] if remote), *refspecs]
|
|
139
|
+
|
|
140
|
+
Git::Commands::Fetch.new(@execution_context).call(*positionals, **opts, merge: true).stdout
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Option keys accepted by {#pull}
|
|
144
|
+
#
|
|
145
|
+
# Derived from the 4.x `PULL_OPTION_MAP` in `Git::Lib`.
|
|
146
|
+
#
|
|
147
|
+
# @return [Array<Symbol>]
|
|
148
|
+
#
|
|
149
|
+
# @api private
|
|
150
|
+
#
|
|
151
|
+
PULL_ALLOWED_OPTS = %i[allow_unrelated_histories].freeze
|
|
152
|
+
private_constant :PULL_ALLOWED_OPTS
|
|
153
|
+
|
|
154
|
+
# Incorporate changes from a remote repository into the current branch
|
|
155
|
+
#
|
|
156
|
+
# Fetches from the given remote and merges into the current branch. In its
|
|
157
|
+
# default mode, `git pull` is shorthand for `git fetch` followed by
|
|
158
|
+
# `git merge FETCH_HEAD`. The merge editor is suppressed (`--no-edit`) and
|
|
159
|
+
# progress output is silenced (`--no-progress`) by default.
|
|
160
|
+
#
|
|
161
|
+
# @example Pull from the default remote and branch
|
|
162
|
+
# repo.pull
|
|
163
|
+
#
|
|
164
|
+
# @example Pull from a named remote
|
|
165
|
+
# repo.pull('upstream')
|
|
166
|
+
#
|
|
167
|
+
# @example Pull a specific branch from a remote
|
|
168
|
+
# repo.pull('origin', 'main')
|
|
169
|
+
#
|
|
170
|
+
# @example Pull allowing unrelated histories
|
|
171
|
+
# repo.pull('origin', 'main', allow_unrelated_histories: true)
|
|
172
|
+
#
|
|
173
|
+
# @param remote [String, nil] the remote name or URL to pull from
|
|
174
|
+
#
|
|
175
|
+
# When nil, git uses the tracking remote for the current branch.
|
|
176
|
+
#
|
|
177
|
+
# @param branch [String, nil] the remote branch name to pull
|
|
178
|
+
#
|
|
179
|
+
# When nil, git uses the tracking branch for the current branch.
|
|
180
|
+
# A branch may not be specified without also specifying a remote.
|
|
181
|
+
#
|
|
182
|
+
# @param opts [Hash] options for the pull command
|
|
183
|
+
#
|
|
184
|
+
# @option opts [Boolean, nil] :allow_unrelated_histories (nil) allow merging
|
|
185
|
+
# histories that do not share a common ancestor
|
|
186
|
+
# (`--allow-unrelated-histories`)
|
|
187
|
+
#
|
|
188
|
+
# @return [String] the stdout from the pull command
|
|
189
|
+
#
|
|
190
|
+
# @raise [ArgumentError] when a branch is given without a remote, or when
|
|
191
|
+
# unsupported option keys are provided
|
|
192
|
+
#
|
|
193
|
+
# @raise [Git::FailedError] when git exits with a non-zero status
|
|
194
|
+
#
|
|
195
|
+
def pull(remote = nil, branch = nil, opts = {})
|
|
196
|
+
raise ArgumentError, 'You must specify a remote if a branch is specified' if remote.nil? && !branch.nil?
|
|
197
|
+
|
|
198
|
+
SharedPrivate.assert_valid_opts!(PULL_ALLOWED_OPTS, **opts)
|
|
199
|
+
positional_args = [remote, branch].compact
|
|
200
|
+
Git::Commands::Pull
|
|
201
|
+
.new(@execution_context)
|
|
202
|
+
.call(*positional_args, no_edit: true, no_progress: true, **opts)
|
|
203
|
+
.stdout
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Option keys accepted by {#push}
|
|
207
|
+
#
|
|
208
|
+
# Derived from the 4.x `PUSH_OPTION_MAP` in `Git::Lib`.
|
|
209
|
+
#
|
|
210
|
+
# @return [Array<Symbol>]
|
|
211
|
+
#
|
|
212
|
+
# @api private
|
|
213
|
+
#
|
|
214
|
+
PUSH_ALLOWED_OPTS = %i[mirror delete force f push_option all tags].freeze
|
|
215
|
+
private_constant :PUSH_ALLOWED_OPTS
|
|
216
|
+
|
|
217
|
+
# Push refs to a remote repository
|
|
218
|
+
#
|
|
219
|
+
# @example Push using the current branch's default remote and push configuration
|
|
220
|
+
# repo.push
|
|
221
|
+
#
|
|
222
|
+
# @example Push to a named remote
|
|
223
|
+
# repo.push('origin')
|
|
224
|
+
#
|
|
225
|
+
# @example Force-push the current branch to a named remote
|
|
226
|
+
# repo.push('origin', force: true)
|
|
227
|
+
#
|
|
228
|
+
# @example Push a specific branch to a named remote
|
|
229
|
+
# repo.push('origin', 'main')
|
|
230
|
+
#
|
|
231
|
+
# @example Push a branch and all tags to a named remote
|
|
232
|
+
# repo.push('origin', 'main', tags: true)
|
|
233
|
+
#
|
|
234
|
+
# @example Push all branches to a named remote
|
|
235
|
+
# repo.push('origin', all: true)
|
|
236
|
+
#
|
|
237
|
+
# @example Mirror all refs to a named remote
|
|
238
|
+
# repo.push('origin', mirror: true)
|
|
239
|
+
#
|
|
240
|
+
# @param remote [String, Hash, nil] the remote name or URL to push to
|
|
241
|
+
#
|
|
242
|
+
# When a Hash is given it is treated as `opts` and `remote` defaults to
|
|
243
|
+
# `nil` so git uses the configured default push target.
|
|
244
|
+
#
|
|
245
|
+
# @param branch [String, Hash, nil] the branch name or refspec to push
|
|
246
|
+
#
|
|
247
|
+
# When a Hash is given it is treated as `opts` and `branch` defaults to
|
|
248
|
+
# `nil`. A branch may not be specified without also specifying a remote.
|
|
249
|
+
#
|
|
250
|
+
# @param opts [Hash, Boolean, nil] options for the push command
|
|
251
|
+
#
|
|
252
|
+
# For backward compatibility, a Boolean is interpreted as
|
|
253
|
+
# `tags: <Boolean>`.
|
|
254
|
+
#
|
|
255
|
+
# @option opts [Boolean, nil] :all (nil) push all branches (`--all`)
|
|
256
|
+
#
|
|
257
|
+
# @option opts [Boolean, nil] :mirror (nil) push all refs under `refs/` to
|
|
258
|
+
# the remote (`--mirror`)
|
|
259
|
+
#
|
|
260
|
+
# @option opts [Boolean, nil] :tags (nil) push all refs under `refs/tags/`
|
|
261
|
+
# in a second `git push` invocation (`--tags`)
|
|
262
|
+
#
|
|
263
|
+
# When `:mirror` is also given, the tags push is suppressed because
|
|
264
|
+
# `--mirror` already includes tags.
|
|
265
|
+
#
|
|
266
|
+
# @option opts [Boolean, nil] :force (nil) force updates, overriding the
|
|
267
|
+
# fast-forward check (`--force`)
|
|
268
|
+
#
|
|
269
|
+
# Alias: `:f`
|
|
270
|
+
#
|
|
271
|
+
# @option opts [Boolean, nil] :delete (nil) delete the named refs from the
|
|
272
|
+
# remote (`--delete`)
|
|
273
|
+
#
|
|
274
|
+
# @option opts [String, Array<String>] :push_option (nil) one or more
|
|
275
|
+
# server-side push option values (`--push-option=<value>`, repeatable)
|
|
276
|
+
#
|
|
277
|
+
# @return [String] the stdout from the push command
|
|
278
|
+
#
|
|
279
|
+
# @raise [ArgumentError] when `branch` is given without `remote`
|
|
280
|
+
#
|
|
281
|
+
# @raise [ArgumentError] when unsupported option keys are provided
|
|
282
|
+
#
|
|
283
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
284
|
+
#
|
|
285
|
+
def push(remote = nil, branch = nil, opts = nil)
|
|
286
|
+
remote, branch, opts = Private.normalize_push_args(remote, branch, opts)
|
|
287
|
+
SharedPrivate.assert_valid_opts!(PUSH_ALLOWED_OPTS, **opts)
|
|
288
|
+
raise ArgumentError, 'remote is required if branch is specified' if !remote && branch
|
|
289
|
+
|
|
290
|
+
first_result = Private.push_refs(@execution_context, remote, branch, opts)
|
|
291
|
+
return first_result.stdout unless Private.push_tags_separately?(opts)
|
|
292
|
+
|
|
293
|
+
Private.push_tags(@execution_context, remote, opts).stdout
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Option keys accepted by {#remote_add}
|
|
297
|
+
#
|
|
298
|
+
# Derived from the 4.x `REMOTE_ADD_OPTION_MAP` in `Git::Lib`.
|
|
299
|
+
REMOTE_ADD_ALLOWED_OPTS = %i[fetch track].freeze
|
|
300
|
+
private_constant :REMOTE_ADD_ALLOWED_OPTS
|
|
301
|
+
|
|
302
|
+
# Register a new remote in the local repository
|
|
303
|
+
#
|
|
304
|
+
# Associates `name` with `url` and optionally fetches immediately or
|
|
305
|
+
# configures which branches are tracked.
|
|
306
|
+
#
|
|
307
|
+
# @example Add a remote
|
|
308
|
+
# repo.remote_add('upstream', 'https://github.com/user/repo.git')
|
|
309
|
+
#
|
|
310
|
+
# @example Add a remote and fetch immediately
|
|
311
|
+
# repo.remote_add('upstream', 'https://github.com/user/repo.git', fetch: true)
|
|
312
|
+
#
|
|
313
|
+
# @example Add a remote tracking a specific branch
|
|
314
|
+
# repo.remote_add('upstream', 'https://github.com/user/repo.git', track: 'main')
|
|
315
|
+
#
|
|
316
|
+
# @param name [String] the name for the new remote
|
|
317
|
+
#
|
|
318
|
+
# @param url [String, Git::Repository] the URL of the remote repository
|
|
319
|
+
#
|
|
320
|
+
# A {Git::Repository} instance is accepted for local references and converted
|
|
321
|
+
# to `url.repo.to_s`.
|
|
322
|
+
#
|
|
323
|
+
# @param opts [Hash] options for adding the remote
|
|
324
|
+
#
|
|
325
|
+
# @option opts [Boolean, nil] :fetch (nil) fetch from the remote immediately
|
|
326
|
+
# after adding it (`-f`)
|
|
327
|
+
#
|
|
328
|
+
# The deprecated alias `:with_fetch` is accepted and normalized
|
|
329
|
+
# automatically.
|
|
330
|
+
#
|
|
331
|
+
# @option opts [String, nil] :track (nil) track only the given branch during
|
|
332
|
+
# fetch (`-t`)
|
|
333
|
+
#
|
|
334
|
+
# @return [void]
|
|
335
|
+
#
|
|
336
|
+
# @raise [ArgumentError] when unsupported option keys are provided
|
|
337
|
+
#
|
|
338
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
339
|
+
#
|
|
340
|
+
def remote_add(name, url, opts = {})
|
|
341
|
+
url = url.repo.to_s if url.is_a?(Git::Repository)
|
|
342
|
+
opts = Private.normalize_add_remote_keys(opts)
|
|
343
|
+
SharedPrivate.assert_valid_opts!(REMOTE_ADD_ALLOWED_OPTS, **opts)
|
|
344
|
+
Git::Commands::Remote::Add.new(@execution_context).call(name, url, **opts)
|
|
345
|
+
|
|
346
|
+
nil
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# @param name [String] the name for the new remote
|
|
350
|
+
#
|
|
351
|
+
# @param url [String, Git::Repository] the URL of the remote repository
|
|
352
|
+
#
|
|
353
|
+
# A {Git::Repository} instance is accepted for local references and converted
|
|
354
|
+
# to `url.repo.to_s`.
|
|
355
|
+
#
|
|
356
|
+
# @param opts [Hash] options for adding the remote
|
|
357
|
+
#
|
|
358
|
+
# @option opts [Boolean, nil] :fetch (nil) fetch from the remote immediately
|
|
359
|
+
# after adding it (`-f`)
|
|
360
|
+
#
|
|
361
|
+
# The deprecated alias `:with_fetch` is accepted and normalized
|
|
362
|
+
# automatically.
|
|
363
|
+
#
|
|
364
|
+
# @option opts [String, nil] :track (nil) track only the given branch during
|
|
365
|
+
# fetch (`-t`)
|
|
366
|
+
#
|
|
367
|
+
# @return [Git::Remote] the newly added remote
|
|
368
|
+
#
|
|
369
|
+
# @raise [ArgumentError] when unsupported option keys are provided
|
|
370
|
+
#
|
|
371
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
372
|
+
#
|
|
373
|
+
# @deprecated Use {#remote_add} instead
|
|
374
|
+
#
|
|
375
|
+
def add_remote(name, url, opts = {})
|
|
376
|
+
Git::Deprecation.warn(
|
|
377
|
+
'Git::Repository#add_remote is deprecated and will be removed in v6.0.0. ' \
|
|
378
|
+
'Use Git::Repository#remote_add instead.'
|
|
379
|
+
)
|
|
380
|
+
remote_add(name, url, opts)
|
|
381
|
+
Git::Remote.new(self, name)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Removes a remote from this repository
|
|
385
|
+
#
|
|
386
|
+
# Deletes the remote named `name` along with its associated configuration,
|
|
387
|
+
# tracking references, and remote-tracking branches.
|
|
388
|
+
#
|
|
389
|
+
# @example Remove a remote named 'upstream'
|
|
390
|
+
# repo.remote_remove('upstream')
|
|
391
|
+
#
|
|
392
|
+
# @param name [String] the name of the remote to remove
|
|
393
|
+
#
|
|
394
|
+
# @return [Git::CommandLine::Result] the result of calling `git remote remove`
|
|
395
|
+
#
|
|
396
|
+
# @raise [Git::FailedError] when git exits with a non-zero status
|
|
397
|
+
#
|
|
398
|
+
def remote_remove(name)
|
|
399
|
+
Git::Commands::Remote::Remove.new(@execution_context).call(name)
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# @param name [String] the name of the remote to remove
|
|
403
|
+
#
|
|
404
|
+
# @return [Git::CommandLine::Result] the result of calling `git remote remove`
|
|
405
|
+
#
|
|
406
|
+
# @raise [Git::FailedError] when git exits with a non-zero status
|
|
407
|
+
#
|
|
408
|
+
# @deprecated Use {#remote_remove} instead
|
|
409
|
+
#
|
|
410
|
+
def remove_remote(name)
|
|
411
|
+
Git::Deprecation.warn(
|
|
412
|
+
'Git::Repository#remove_remote is deprecated and will be removed in v6.0.0. ' \
|
|
413
|
+
'Use Git::Repository#remote_remove instead.'
|
|
414
|
+
)
|
|
415
|
+
remote_remove(name)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Sets the URL for an existing remote
|
|
419
|
+
#
|
|
420
|
+
# Replaces the fetch URL configured for the remote named `name`.
|
|
421
|
+
#
|
|
422
|
+
# @example Set the URL for a remote
|
|
423
|
+
# repo.remote_set_url('origin', 'https://github.com/user/repo.git')
|
|
424
|
+
#
|
|
425
|
+
# @example Set the URL from a local repository reference
|
|
426
|
+
# source = Git.open('/path/to/source')
|
|
427
|
+
# repo.remote_set_url('origin', source)
|
|
428
|
+
#
|
|
429
|
+
# @param name [String] the name of the remote to update
|
|
430
|
+
#
|
|
431
|
+
# @param url [String, Git::Repository] the new URL for the remote
|
|
432
|
+
#
|
|
433
|
+
# A {Git::Repository} instance is accepted for local references and converted
|
|
434
|
+
# to `url.repo.to_s`.
|
|
435
|
+
#
|
|
436
|
+
# @return [void]
|
|
437
|
+
#
|
|
438
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
439
|
+
#
|
|
440
|
+
def remote_set_url(name, url)
|
|
441
|
+
url = url.repo.to_s if url.is_a?(Git::Repository)
|
|
442
|
+
Git::Commands::Remote::SetUrl.new(@execution_context).call(name, url)
|
|
443
|
+
|
|
444
|
+
nil
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
# @param name [String] the name of the remote to update
|
|
448
|
+
#
|
|
449
|
+
# @param url [String, Git::Repository] the new URL for the remote
|
|
450
|
+
#
|
|
451
|
+
# A {Git::Repository} instance is accepted for local references and converted
|
|
452
|
+
# to `url.repo.to_s`.
|
|
453
|
+
#
|
|
454
|
+
# @return [Git::Remote] the updated remote
|
|
455
|
+
#
|
|
456
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
457
|
+
#
|
|
458
|
+
# @deprecated Use {#remote_set_url} instead
|
|
459
|
+
#
|
|
460
|
+
def set_remote_url(name, url)
|
|
461
|
+
Git::Deprecation.warn(
|
|
462
|
+
'Git::Repository#set_remote_url is deprecated and will be removed in v6.0.0. ' \
|
|
463
|
+
'Use Git::Repository#remote_set_url instead.'
|
|
464
|
+
)
|
|
465
|
+
remote_set_url(name, url)
|
|
466
|
+
Git::Remote.new(self, name)
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
# Configures which branches are fetched for a remote
|
|
470
|
+
#
|
|
471
|
+
# Uses `git remote set-branches` to set or append fetch refspecs. When the
|
|
472
|
+
# `add:` option is `false`, the `--add` flag is not passed to the git
|
|
473
|
+
# command and the tracked branch list is replaced.
|
|
474
|
+
#
|
|
475
|
+
# @example Replace fetched branches with a single glob pattern
|
|
476
|
+
# repo.remote_set_branches('origin', 'feature/*')
|
|
477
|
+
#
|
|
478
|
+
# @example Append a glob pattern to existing fetched branches
|
|
479
|
+
# repo.remote_set_branches('origin', 'release/*', add: true)
|
|
480
|
+
#
|
|
481
|
+
# @example Configure multiple explicit branches
|
|
482
|
+
# repo.remote_set_branches('origin', 'main', 'development', 'hotfix')
|
|
483
|
+
#
|
|
484
|
+
# @param name [String] the remote name (for example, `"origin"`)
|
|
485
|
+
#
|
|
486
|
+
# @param branches [Array<String>] branch names or globs (for example, `'*'`)
|
|
487
|
+
#
|
|
488
|
+
# @param add [Boolean] when `true`, append to existing refspecs instead of
|
|
489
|
+
# replacing them
|
|
490
|
+
#
|
|
491
|
+
# @return [void]
|
|
492
|
+
#
|
|
493
|
+
# @raise [ArgumentError] when no branches are provided
|
|
494
|
+
#
|
|
495
|
+
# @raise [Git::FailedError] when git exits with a non-zero status
|
|
496
|
+
#
|
|
497
|
+
def remote_set_branches(name, *branches, add: false)
|
|
498
|
+
branch_list = branches.flatten
|
|
499
|
+
raise ArgumentError, 'branches are required' if branch_list.empty?
|
|
500
|
+
|
|
501
|
+
Git::Commands::Remote::SetBranches.new(@execution_context).call(name, *branch_list, add: add)
|
|
502
|
+
|
|
503
|
+
nil
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
# Return the git configuration entries for a named remote
|
|
507
|
+
#
|
|
508
|
+
# Reads `git config --list` and returns all entries whose keys begin with
|
|
509
|
+
# `remote.<name>.`, with the `remote.<name>.` prefix stripped. This
|
|
510
|
+
# typically yields at least `"url"` and `"fetch"` for a configured remote.
|
|
511
|
+
#
|
|
512
|
+
# @example Retrieve the config for the 'origin' remote
|
|
513
|
+
# repo.config_remote('origin')
|
|
514
|
+
# #=> {
|
|
515
|
+
# # 'url' => 'https://github.com/user/repo.git',
|
|
516
|
+
# # 'fetch' => '+refs/heads/*:refs/remotes/origin/*'
|
|
517
|
+
# # }
|
|
518
|
+
#
|
|
519
|
+
# @param name [String] the name of the remote (e.g. `"origin"`)
|
|
520
|
+
#
|
|
521
|
+
# @return [Hash{String => String}] configuration entries for the remote,
|
|
522
|
+
# keyed without the `remote.<name>.` prefix
|
|
523
|
+
#
|
|
524
|
+
# Returns an empty hash when no entries are found.
|
|
525
|
+
#
|
|
526
|
+
# @raise [Git::FailedError] when git exits with a non-zero status
|
|
527
|
+
#
|
|
528
|
+
# @deprecated Use `remote_list.find { |r| r.name == name }` for the fields
|
|
529
|
+
# {Git::RemoteInfo} models, or filter {Git::Configuring#config_list} on
|
|
530
|
+
# the `remote.<name>.` key prefix to keep every entry
|
|
531
|
+
#
|
|
532
|
+
# {#remote_list} returns a {Git::RemoteInfo} per remote. Its `url` and
|
|
533
|
+
# `fetch` members hold every configured value as `Array<String>`,
|
|
534
|
+
# whereas this method returns a flat hash in which a repeated `url` or
|
|
535
|
+
# `fetch` key overwrites the earlier value.
|
|
536
|
+
#
|
|
537
|
+
# {Git::RemoteInfo} models only the remote variables git defines and
|
|
538
|
+
# drops any other `remote.<name>.*` entry, whereas this method returns
|
|
539
|
+
# every entry. Callers that read custom keys should filter
|
|
540
|
+
# {Git::Configuring#config_list} instead, which returns the same hash
|
|
541
|
+
# (shown here for the `origin` remote):
|
|
542
|
+
#
|
|
543
|
+
# prefix = 'remote.origin.'
|
|
544
|
+
# repo.config_list
|
|
545
|
+
# .select { |entry| entry.key.start_with?(prefix) }
|
|
546
|
+
# .to_h { |entry| [entry.key.delete_prefix(prefix), entry.value] }
|
|
547
|
+
#
|
|
548
|
+
# @see #remote_list
|
|
549
|
+
#
|
|
550
|
+
# @see Git::Configuring#config_list
|
|
551
|
+
#
|
|
552
|
+
def config_remote(name)
|
|
553
|
+
Git::Deprecation.warn(
|
|
554
|
+
'Git::Repository#config_remote is deprecated and will be removed in v6.0.0. ' \
|
|
555
|
+
'Use Git::Repository#remote_list.find { |r| r.name == name } for the fields ' \
|
|
556
|
+
'Git::RemoteInfo models, or filter Git::Repository#config_list on the ' \
|
|
557
|
+
'"remote.<name>." key prefix to keep every entry.'
|
|
558
|
+
)
|
|
559
|
+
prefix = "remote.#{name}."
|
|
560
|
+
Private.config_list(@execution_context).each_with_object({}) do |(key, value), hsh|
|
|
561
|
+
hsh[key.delete_prefix(prefix)] = value if key.start_with?(prefix)
|
|
562
|
+
end
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
# List all configured remotes as {Git::RemoteInfo} objects
|
|
566
|
+
#
|
|
567
|
+
# Reads the repository configuration via {Git::Configuring#config_list} and
|
|
568
|
+
# returns one {Git::RemoteInfo} per configured remote, preserving the order
|
|
569
|
+
# in which remotes appear in the config. Multi-value fields (`:url`,
|
|
570
|
+
# `:push_url`, `:fetch`, `:push`) are always `Array<String>` (never `nil`).
|
|
571
|
+
#
|
|
572
|
+
# @example List all remotes
|
|
573
|
+
# repo.remote_list
|
|
574
|
+
# # => [#<data Git::RemoteInfo name="origin" ...>,
|
|
575
|
+
# # #<data Git::RemoteInfo name="upstream" ...>]
|
|
576
|
+
#
|
|
577
|
+
# @example Get fetch URLs for all remotes
|
|
578
|
+
# repo.remote_list.map { |r| [r.name, r.url] }.to_h
|
|
579
|
+
#
|
|
580
|
+
# @return [Array<Git::RemoteInfo>] one entry per configured remote
|
|
581
|
+
#
|
|
582
|
+
# Returns an empty array when no remotes are configured.
|
|
583
|
+
#
|
|
584
|
+
# @raise [ArgumentError] if a `remote.*` config entry carries an
|
|
585
|
+
# unrecognized boolean value (e.g. `remote.origin.prune=maybe`)
|
|
586
|
+
#
|
|
587
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
588
|
+
#
|
|
589
|
+
def remote_list
|
|
590
|
+
Git::Parsers::Remote.parse_list(config_list)
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
# Returns a {Git::Remote} object for the named remote
|
|
594
|
+
#
|
|
595
|
+
# @example Get the default 'origin' remote
|
|
596
|
+
# repo.remote #=> #<Git::Remote 'origin'>
|
|
597
|
+
#
|
|
598
|
+
# @example Get a named remote
|
|
599
|
+
# repo.remote('upstream') #=> #<Git::Remote 'upstream'>
|
|
600
|
+
#
|
|
601
|
+
# @param name [String] the remote name (defaults to `'origin'`)
|
|
602
|
+
#
|
|
603
|
+
# @return [Git::Remote] the remote object
|
|
604
|
+
#
|
|
605
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
606
|
+
#
|
|
607
|
+
# @deprecated Use `remote_list.find { |r| r.name == name }` instead
|
|
608
|
+
#
|
|
609
|
+
# {#remote_list} returns immutable {Git::RemoteInfo} value objects
|
|
610
|
+
# rather than {Git::Remote}. Call the corresponding {Git::Repository}
|
|
611
|
+
# method (e.g. {#fetch}, {#remote_remove}) for operations on a remote.
|
|
612
|
+
#
|
|
613
|
+
# @see #remote_list
|
|
614
|
+
#
|
|
615
|
+
def remote(name = 'origin')
|
|
616
|
+
Git::Deprecation.warn(
|
|
617
|
+
'Git::Repository#remote is deprecated and will be removed in v6.0.0. ' \
|
|
618
|
+
'Use Git::Repository#remote_list.find { |r| r.name == name } instead.'
|
|
619
|
+
)
|
|
620
|
+
Git::Remote.new(self, name)
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
# Returns all configured remotes as {Git::Remote} objects
|
|
624
|
+
#
|
|
625
|
+
# @example List all remotes
|
|
626
|
+
# repo.remotes #=> [#<Git::Remote 'origin'>, #<Git::Remote 'upstream'>]
|
|
627
|
+
#
|
|
628
|
+
# @return [Array<Git::Remote>] one {Git::Remote} for each configured remote
|
|
629
|
+
#
|
|
630
|
+
# Returns an empty array when no remotes are configured.
|
|
631
|
+
#
|
|
632
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
633
|
+
#
|
|
634
|
+
# @deprecated Use {#remote_list} instead
|
|
635
|
+
#
|
|
636
|
+
# {#remote_list} returns `Array<Git::RemoteInfo>` (immutable value
|
|
637
|
+
# objects) rather than `Array<Git::Remote>`. Call the corresponding
|
|
638
|
+
# {Git::Repository} method (e.g. {#fetch}, {#remote_remove}) for
|
|
639
|
+
# operations on a remote. Each {Git::Remote} this method constructs
|
|
640
|
+
# emits its own deprecation warning, so a call produces one warning
|
|
641
|
+
# for this method plus one per remote returned.
|
|
642
|
+
#
|
|
643
|
+
# @see #remote_list
|
|
644
|
+
#
|
|
645
|
+
def remotes
|
|
646
|
+
Git::Deprecation.warn(
|
|
647
|
+
'Git::Repository#remotes is deprecated and will be removed in v6.0.0. ' \
|
|
648
|
+
'Use Git::Repository#remote_list instead.'
|
|
649
|
+
)
|
|
650
|
+
result = Git::Commands::Remote::List.new(@execution_context).call
|
|
651
|
+
result.stdout.split("\n").map { |name| Git::Remote.new(self, name) }
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
# Returns the names of all configured remotes
|
|
655
|
+
#
|
|
656
|
+
# Lists remote names by running `git remote`. This is a lightweight
|
|
657
|
+
# alternative to {#remote_list} when only names are needed — in
|
|
658
|
+
# particular, it returns the raw name (e.g. `"team/upstream"`) preserving
|
|
659
|
+
# any slashes in the remote name.
|
|
660
|
+
#
|
|
661
|
+
# @example Get all remote names
|
|
662
|
+
# repo.remote_names #=> ["origin", "upstream"]
|
|
663
|
+
#
|
|
664
|
+
# @example With a slash-containing remote name
|
|
665
|
+
# repo.remote_names #=> ["origin", "team/upstream"]
|
|
666
|
+
#
|
|
667
|
+
# @return [Array<String>] the configured remote names
|
|
668
|
+
#
|
|
669
|
+
# Returns an empty array when no remotes are configured.
|
|
670
|
+
#
|
|
671
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
672
|
+
#
|
|
673
|
+
# @api public
|
|
674
|
+
#
|
|
675
|
+
def remote_names
|
|
676
|
+
Git::Commands::Remote::List.new(@execution_context).call.stdout.split("\n")
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
# Option keys accepted by {#ls_remote}
|
|
680
|
+
#
|
|
681
|
+
# @return [Array<Symbol>]
|
|
682
|
+
#
|
|
683
|
+
# @api private
|
|
684
|
+
#
|
|
685
|
+
LS_REMOTE_ALLOWED_OPTS = %i[
|
|
686
|
+
branches b heads h tags t refs upload_pack quiet q exit_code sort server_option o timeout
|
|
687
|
+
].freeze
|
|
688
|
+
private_constant :LS_REMOTE_ALLOWED_OPTS
|
|
689
|
+
|
|
690
|
+
# List references available in a remote repository
|
|
691
|
+
#
|
|
692
|
+
# Queries a remote for its available refs and returns a structured Hash
|
|
693
|
+
# mapping ref types to name/sha pairs. The remote is contacted but no local
|
|
694
|
+
# objects are created or updated.
|
|
695
|
+
#
|
|
696
|
+
# @example List all refs from the local repository
|
|
697
|
+
# repo.ls_remote
|
|
698
|
+
# # => {"head"=>{ref: "HEAD", sha: "abc123"},
|
|
699
|
+
# # "branches"=>{"main"=>{ref: "refs/heads/main", sha: "abc123"}}}
|
|
700
|
+
#
|
|
701
|
+
# @example List all refs from a named remote
|
|
702
|
+
# repo.ls_remote('origin')
|
|
703
|
+
# # => {"head"=>..., "branches"=>..., "tags"=>...}
|
|
704
|
+
#
|
|
705
|
+
# @example List only tags from a named remote
|
|
706
|
+
# repo.ls_remote('origin', tags: true)
|
|
707
|
+
# # => {"tags"=>{"v1.0"=>{ref: "refs/tags/v1.0", sha: "def456"}}}
|
|
708
|
+
#
|
|
709
|
+
# @param location [String, nil] the remote name or URL to query; defaults to
|
|
710
|
+
# `'.'` (the local repository) when nil
|
|
711
|
+
#
|
|
712
|
+
# @param opts [Hash] options for the ls-remote command
|
|
713
|
+
#
|
|
714
|
+
# @option opts [Boolean, nil] :branches (nil) limit output to refs under
|
|
715
|
+
# `refs/heads/`; alias: `:b`
|
|
716
|
+
#
|
|
717
|
+
# @option opts [Boolean, nil] :heads (nil) limit output to refs under
|
|
718
|
+
# `refs/heads/`; kept for backward compatibility; alias: `:h`
|
|
719
|
+
#
|
|
720
|
+
# @option opts [Boolean, nil] :tags (nil) limit output to refs under
|
|
721
|
+
# `refs/tags/`; alias: `:t`
|
|
722
|
+
#
|
|
723
|
+
# @option opts [Boolean, nil] :refs (nil) exclude peeled tags and pseudorefs
|
|
724
|
+
# like `HEAD` from the output
|
|
725
|
+
#
|
|
726
|
+
# @option opts [Numeric] :timeout (nil) execution timeout in seconds
|
|
727
|
+
#
|
|
728
|
+
# @return [Hash{String => Hash}] a Hash keyed by ref type (e.g. `"head"`,
|
|
729
|
+
# `"branches"`, `"tags"`; other git namespace segments may appear for
|
|
730
|
+
# non-standard refs); for named refs the value is a Hash keyed by ref name
|
|
731
|
+
# mapping to `{ ref: String, sha: String }`; for the `"head"` entry the value
|
|
732
|
+
# is `{ ref: String, sha: String }` directly
|
|
733
|
+
#
|
|
734
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
735
|
+
#
|
|
736
|
+
# @raise [Git::FailedError] if git exits outside the allowed range (exit code > 2)
|
|
737
|
+
#
|
|
738
|
+
def ls_remote(location = nil, opts = {})
|
|
739
|
+
SharedPrivate.assert_valid_opts!(LS_REMOTE_ALLOWED_OPTS, **opts)
|
|
740
|
+
repository = location || '.'
|
|
741
|
+
output_lines = Git::Commands::LsRemote.new(@execution_context).call(repository, **opts).stdout.split("\n")
|
|
742
|
+
Git::Parsers::LsRemote.parse_output(output_lines)
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
# Helpers private to the `RemoteOperations` topic module
|
|
746
|
+
#
|
|
747
|
+
# @api private
|
|
748
|
+
#
|
|
749
|
+
module Private
|
|
750
|
+
module_function
|
|
751
|
+
|
|
752
|
+
# Resolve the (remote, opts) pair for {#fetch}, supporting the hash-only form
|
|
753
|
+
#
|
|
754
|
+
# `fetch` may be called as `fetch(remote, opts)` or `fetch(opts)`. When a bare
|
|
755
|
+
# options hash is passed the remote is treated as nil. A `:ref` is only
|
|
756
|
+
# meaningful with an explicit remote, so requesting one without a remote (it
|
|
757
|
+
# would otherwise be silently promoted to the remote-name slot) is rejected.
|
|
758
|
+
#
|
|
759
|
+
# @param remote [String, Hash, nil] the remote name, or an options hash
|
|
760
|
+
#
|
|
761
|
+
# @param opts [Hash] the options hash when remote is given positionally
|
|
762
|
+
#
|
|
763
|
+
# @option opts [String, Array<String>, nil] :ref (nil) one or more refspecs
|
|
764
|
+
# forwarded after the remote name
|
|
765
|
+
#
|
|
766
|
+
# Requires an explicit `remote`.
|
|
767
|
+
#
|
|
768
|
+
# @return [Array(String, Hash), Array(nil, Hash)] the resolved remote and opts
|
|
769
|
+
#
|
|
770
|
+
# @raise [ArgumentError] when :ref is supplied without an explicit remote
|
|
771
|
+
#
|
|
772
|
+
# @api private
|
|
773
|
+
#
|
|
774
|
+
def resolve_fetch_target(remote, opts)
|
|
775
|
+
if remote.is_a?(Hash)
|
|
776
|
+
opts = remote
|
|
777
|
+
remote = nil
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
raise ArgumentError, ':ref requires an explicit remote' if remote.nil? && opts.key?(:ref)
|
|
781
|
+
|
|
782
|
+
[remote, opts]
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
# Normalize dash-style option keys to their underscore equivalents
|
|
786
|
+
#
|
|
787
|
+
# Converts any key in {FETCH_KEY_NORMALIZATIONS} from its dash-style symbol
|
|
788
|
+
# form (e.g., `:'update-head-ok'`) to the canonical underscore-style form
|
|
789
|
+
# (e.g., `:update_head_ok`). Unrecognized keys are returned unchanged.
|
|
790
|
+
#
|
|
791
|
+
# @param opts [Hash] the raw options hash passed by the caller
|
|
792
|
+
#
|
|
793
|
+
# @option opts [Object] :'prune-tags' a legacy dash-style fetch option value
|
|
794
|
+
#
|
|
795
|
+
# @option opts [Object] :'update-head-ok' a legacy dash-style fetch option
|
|
796
|
+
# value
|
|
797
|
+
#
|
|
798
|
+
# @return [Hash] a new hash with all applicable keys normalized
|
|
799
|
+
#
|
|
800
|
+
# @api private
|
|
801
|
+
#
|
|
802
|
+
def normalize_fetch_keys(opts)
|
|
803
|
+
opts.transform_keys do |k|
|
|
804
|
+
sym = k.is_a?(Symbol) ? k : k.to_sym
|
|
805
|
+
FETCH_KEY_NORMALIZATIONS.fetch(sym, sym)
|
|
806
|
+
end
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
# Normalize the flexible argument list accepted by {RemoteOperations#push}
|
|
810
|
+
#
|
|
811
|
+
# Handles three call forms:
|
|
812
|
+
# - `push(opts)` — Hash promoted from `remote` position
|
|
813
|
+
# - `push(remote, opts)` — Hash promoted from `branch` position
|
|
814
|
+
# - `push(remote, branch, true|false)` — Boolean `opts` converted to
|
|
815
|
+
# `{ tags: opts }` for backward compatibility
|
|
816
|
+
#
|
|
817
|
+
# @param remote [String, Hash, nil] remote name, URL, or opts hash
|
|
818
|
+
#
|
|
819
|
+
# @param branch [String, Hash, nil] branch/refspec, or opts hash
|
|
820
|
+
#
|
|
821
|
+
# @param opts [Hash, Boolean, nil] options hash or legacy Boolean shorthand
|
|
822
|
+
#
|
|
823
|
+
# @option opts [Boolean, nil] :all (nil) push all branches
|
|
824
|
+
#
|
|
825
|
+
# @option opts [Boolean, nil] :mirror (nil) mirror all refs
|
|
826
|
+
#
|
|
827
|
+
# @option opts [Boolean, nil] :tags (nil) push all tags
|
|
828
|
+
#
|
|
829
|
+
# @option opts [Boolean, nil] :delete (nil) delete refs on the remote
|
|
830
|
+
#
|
|
831
|
+
# @option opts [Boolean, nil] :force (nil) force updates
|
|
832
|
+
#
|
|
833
|
+
# @option opts [String, Array<String>] :push_option (nil) one or more
|
|
834
|
+
# push-option values
|
|
835
|
+
#
|
|
836
|
+
# @return [Array((String, nil), (String, nil), Hash)] normalized [remote, branch, opts]
|
|
837
|
+
#
|
|
838
|
+
# @api private
|
|
839
|
+
#
|
|
840
|
+
def normalize_push_args(remote, branch, opts)
|
|
841
|
+
if branch.is_a?(Hash)
|
|
842
|
+
opts = branch
|
|
843
|
+
branch = nil
|
|
844
|
+
elsif remote.is_a?(Hash)
|
|
845
|
+
opts = remote
|
|
846
|
+
remote = nil
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
opts ||= {}
|
|
850
|
+
|
|
851
|
+
# Backwards compatibility for `push(remote, branch, true)` to push tags
|
|
852
|
+
# without requiring the caller to use keyword arguments
|
|
853
|
+
|
|
854
|
+
opts = { tags: opts } if [true, false].include?(opts)
|
|
855
|
+
[remote, branch, opts]
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
# Issue the refs push (first push when `:tags` is given separately)
|
|
859
|
+
#
|
|
860
|
+
# Strips `:tags` from the options so that only refs — not tags — are pushed
|
|
861
|
+
# in this first call. Tags are pushed in a separate call when
|
|
862
|
+
# {push_tags_separately?} is true.
|
|
863
|
+
#
|
|
864
|
+
# @param execution_context [Git::ExecutionContext::Repository] the repository execution context
|
|
865
|
+
#
|
|
866
|
+
# @param remote [String, nil] remote name or URL
|
|
867
|
+
#
|
|
868
|
+
# @param branch [String, nil] branch or refspec
|
|
869
|
+
#
|
|
870
|
+
# @param opts [Hash] push options (`:tags` key will be stripped)
|
|
871
|
+
#
|
|
872
|
+
# @option opts [Boolean, nil] :all (nil) push all branches
|
|
873
|
+
#
|
|
874
|
+
# @option opts [Boolean, nil] :mirror (nil) mirror all refs
|
|
875
|
+
#
|
|
876
|
+
# @option opts [Boolean, nil] :delete (nil) delete refs on the remote
|
|
877
|
+
#
|
|
878
|
+
# @option opts [Boolean, nil] :force (nil) force updates
|
|
879
|
+
#
|
|
880
|
+
# @option opts [String, Array<String>] :push_option (nil) one or more
|
|
881
|
+
# push-option values
|
|
882
|
+
#
|
|
883
|
+
# @return [Git::CommandLine::Result]
|
|
884
|
+
#
|
|
885
|
+
# @api private
|
|
886
|
+
#
|
|
887
|
+
def push_refs(execution_context, remote, branch, opts)
|
|
888
|
+
positionals = [remote, branch].compact
|
|
889
|
+
Git::Commands::Push.new(execution_context).call(*positionals, **opts.except(:tags))
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
# Return true when tags must be pushed in a second separate invocation
|
|
893
|
+
#
|
|
894
|
+
# Tags are pushed separately when `:tags` is truthy AND `:mirror` is not set.
|
|
895
|
+
# When `:mirror` is set, the mirror push already includes all refs and tags,
|
|
896
|
+
# so a second tags-only call would be redundant.
|
|
897
|
+
#
|
|
898
|
+
# @param opts [Hash] the normalized push options
|
|
899
|
+
#
|
|
900
|
+
# @option opts [Boolean, nil] :tags (nil) request a separate tags push
|
|
901
|
+
#
|
|
902
|
+
# @option opts [Boolean, nil] :mirror (nil) indicates refs are mirrored and
|
|
903
|
+
# tags are already covered
|
|
904
|
+
#
|
|
905
|
+
# @return [Boolean]
|
|
906
|
+
#
|
|
907
|
+
# @api private
|
|
908
|
+
#
|
|
909
|
+
def push_tags_separately?(opts)
|
|
910
|
+
opts[:tags] && !opts[:mirror]
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
# Issue the tags push (second push when `:tags` is requested without `:mirror`)
|
|
914
|
+
#
|
|
915
|
+
# @param execution_context [Git::ExecutionContext::Repository] the repository execution context
|
|
916
|
+
#
|
|
917
|
+
# @param remote [String, nil] remote name or URL
|
|
918
|
+
#
|
|
919
|
+
# @param opts [Hash] push options (`:tags` key included to emit `--tags`)
|
|
920
|
+
#
|
|
921
|
+
# @option opts [Boolean, nil] :tags (nil) emit `--tags`
|
|
922
|
+
#
|
|
923
|
+
# @option opts [String, Array<String>] :push_option (nil) one or more
|
|
924
|
+
# push-option values
|
|
925
|
+
#
|
|
926
|
+
# @return [Git::CommandLine::Result]
|
|
927
|
+
#
|
|
928
|
+
# @api private
|
|
929
|
+
#
|
|
930
|
+
def push_tags(execution_context, remote, opts)
|
|
931
|
+
Git::Commands::Push.new(execution_context).call(*[remote].compact, **opts)
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
# Normalize deprecated option keys for {#remote_add} to their canonical equivalents
|
|
935
|
+
#
|
|
936
|
+
# Renames the deprecated `:with_fetch` key to `:fetch`, removing it from
|
|
937
|
+
# the copy. When both keys are present, `:with_fetch` takes precedence.
|
|
938
|
+
#
|
|
939
|
+
# @param opts [Hash] the raw options hash passed by the caller
|
|
940
|
+
#
|
|
941
|
+
# @option opts [Boolean, nil] :with_fetch (nil) deprecated alias for
|
|
942
|
+
# immediate fetch behavior
|
|
943
|
+
#
|
|
944
|
+
# @option opts [Boolean, nil] :fetch (nil) fetch from the remote after adding
|
|
945
|
+
#
|
|
946
|
+
# @option opts [String, nil] :track (nil) track the given branch during fetch
|
|
947
|
+
#
|
|
948
|
+
# @return [Hash] a new hash with all applicable keys normalized
|
|
949
|
+
#
|
|
950
|
+
# @api private
|
|
951
|
+
#
|
|
952
|
+
def normalize_add_remote_keys(opts)
|
|
953
|
+
normalized = opts.dup
|
|
954
|
+
normalized[:fetch] = normalized.delete(:with_fetch) if normalized.key?(:with_fetch)
|
|
955
|
+
normalized
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
# Retrieve all config entries as a flat hash
|
|
959
|
+
#
|
|
960
|
+
# Runs `git config --list` and parses each `key=value` line into a hash.
|
|
961
|
+
# When no value is present for a key, the value defaults to an empty string.
|
|
962
|
+
#
|
|
963
|
+
# @param execution_context [Git::ExecutionContext::Repository] the
|
|
964
|
+
# execution context for the repository
|
|
965
|
+
#
|
|
966
|
+
# @return [Hash{String => String}] all visible config entries, keyed by
|
|
967
|
+
# their full dotted key names
|
|
968
|
+
#
|
|
969
|
+
# For example, `"remote.origin.url"` is a valid key.
|
|
970
|
+
#
|
|
971
|
+
# @api private
|
|
972
|
+
#
|
|
973
|
+
def config_list(execution_context)
|
|
974
|
+
lines = Git::Commands::ConfigOptionSyntax::List.new(execution_context).call.stdout.split("\n")
|
|
975
|
+
lines.each_with_object({}) do |line, hsh|
|
|
976
|
+
key, value = line.split('=', 2)
|
|
977
|
+
hsh[key] = value || ''
|
|
978
|
+
end
|
|
979
|
+
end
|
|
980
|
+
end
|
|
981
|
+
private_constant :Private
|
|
982
|
+
end
|
|
983
|
+
end
|
|
984
|
+
end
|