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,246 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/commands/commit'
|
|
4
|
+
require 'git/commands/commit_tree'
|
|
5
|
+
require 'git/commands/write_tree'
|
|
6
|
+
require 'git/repository/shared_private'
|
|
7
|
+
|
|
8
|
+
module Git
|
|
9
|
+
class Repository
|
|
10
|
+
# Facade methods for committing operations: recording commits, manipulating
|
|
11
|
+
# tree objects, and building commit objects outside the working tree
|
|
12
|
+
#
|
|
13
|
+
# Included by {Git::Repository}.
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
16
|
+
#
|
|
17
|
+
module Committing
|
|
18
|
+
# Option keys accepted by {#commit}
|
|
19
|
+
COMMIT_ALLOWED_OPTS = %i[
|
|
20
|
+
all amend allow_empty allow_empty_message author date
|
|
21
|
+
gpg_sign no_gpg_sign no_verify
|
|
22
|
+
].freeze
|
|
23
|
+
private_constant :COMMIT_ALLOWED_OPTS
|
|
24
|
+
|
|
25
|
+
# Option keys accepted by {#commit_tree}
|
|
26
|
+
COMMIT_TREE_ALLOWED_OPTS = %i[parent p parents message m].freeze
|
|
27
|
+
private_constant :COMMIT_TREE_ALLOWED_OPTS
|
|
28
|
+
|
|
29
|
+
# Record staged changes as a new commit
|
|
30
|
+
#
|
|
31
|
+
# @example Commit with a message
|
|
32
|
+
# repo.commit('Add README')
|
|
33
|
+
#
|
|
34
|
+
# @example Amend the previous commit, reusing its message
|
|
35
|
+
# repo.commit(nil, amend: true)
|
|
36
|
+
#
|
|
37
|
+
# @example Stage all modified files and commit
|
|
38
|
+
# repo.commit('Cleanup', all: true)
|
|
39
|
+
#
|
|
40
|
+
# @param message [String, nil] the commit message; pass `nil` to omit
|
|
41
|
+
# (e.g. when using `:amend` to reuse the previous message)
|
|
42
|
+
#
|
|
43
|
+
# @param opts [Hash] options for the commit command
|
|
44
|
+
#
|
|
45
|
+
# @option opts [Boolean, nil] :all (nil) automatically stage modified and
|
|
46
|
+
# deleted files before committing
|
|
47
|
+
#
|
|
48
|
+
# @option opts [Boolean, nil] :amend (nil) replace the tip of the current
|
|
49
|
+
# branch with a new commit
|
|
50
|
+
#
|
|
51
|
+
# @option opts [Boolean, nil] :allow_empty (nil) allow committing with no
|
|
52
|
+
# changes
|
|
53
|
+
#
|
|
54
|
+
# @option opts [Boolean, nil] :allow_empty_message (nil) allow committing
|
|
55
|
+
# with an empty message
|
|
56
|
+
#
|
|
57
|
+
# @option opts [String] :author (nil) override the commit author in
|
|
58
|
+
# `A U Thor <author@example.com>` format
|
|
59
|
+
#
|
|
60
|
+
# @option opts [String] :date (nil) override the author date
|
|
61
|
+
#
|
|
62
|
+
# @option opts [Boolean, String, nil] :gpg_sign (nil) GPG-sign the commit
|
|
63
|
+
#
|
|
64
|
+
# @option opts [Boolean, nil] :no_gpg_sign (nil) disable GPG signing
|
|
65
|
+
#
|
|
66
|
+
# @option opts [Boolean, nil] :no_verify (nil) bypass the pre-commit and
|
|
67
|
+
# commit-msg hooks
|
|
68
|
+
#
|
|
69
|
+
# @return [String] git's stdout from the commit
|
|
70
|
+
#
|
|
71
|
+
# @raise [ArgumentError] when unsupported options are provided
|
|
72
|
+
#
|
|
73
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
74
|
+
#
|
|
75
|
+
def commit(message, opts = {})
|
|
76
|
+
opts = normalize_commit_options(opts)
|
|
77
|
+
SharedPrivate.assert_valid_opts!(COMMIT_ALLOWED_OPTS, **opts)
|
|
78
|
+
|
|
79
|
+
call_opts = { no_edit: true }
|
|
80
|
+
call_opts[:message] = message if message
|
|
81
|
+
|
|
82
|
+
Git::Commands::Commit.new(@execution_context).call(**call_opts, **opts).stdout
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Commit all modified tracked files without explicitly staging them first
|
|
86
|
+
#
|
|
87
|
+
# Equivalent to calling {#commit} with `all: true` merged into `opts`.
|
|
88
|
+
#
|
|
89
|
+
# @example Commit all changes with a message
|
|
90
|
+
# repo.commit_all('Update everything')
|
|
91
|
+
#
|
|
92
|
+
# @param message [String, nil] the commit message; pass `nil` to omit
|
|
93
|
+
# (e.g. when using `:amend` to reuse the previous message)
|
|
94
|
+
#
|
|
95
|
+
# @param opts [Hash] additional options forwarded to {#commit}
|
|
96
|
+
#
|
|
97
|
+
# @option opts [Boolean, nil] :all (nil) ignored because this method
|
|
98
|
+
# always commits with `all: true`
|
|
99
|
+
#
|
|
100
|
+
# @option opts [Boolean, nil] :amend (nil) replace the tip of the current
|
|
101
|
+
# branch with a new commit
|
|
102
|
+
#
|
|
103
|
+
# @option opts [Boolean, nil] :allow_empty (nil) allow committing with no
|
|
104
|
+
# changes
|
|
105
|
+
#
|
|
106
|
+
# @option opts [Boolean, nil] :allow_empty_message (nil) allow committing
|
|
107
|
+
# with an empty message
|
|
108
|
+
#
|
|
109
|
+
# @option opts [String] :author (nil) override the commit author in
|
|
110
|
+
# `A U Thor <author@example.com>` format
|
|
111
|
+
#
|
|
112
|
+
# @option opts [String] :date (nil) override the author date
|
|
113
|
+
#
|
|
114
|
+
# @option opts [Boolean, String, nil] :gpg_sign (nil) GPG-sign the commit
|
|
115
|
+
#
|
|
116
|
+
# @option opts [Boolean, nil] :no_gpg_sign (nil) disable GPG signing
|
|
117
|
+
#
|
|
118
|
+
# @option opts [Boolean, nil] :no_verify (nil) bypass the pre-commit and
|
|
119
|
+
# commit-msg hooks
|
|
120
|
+
#
|
|
121
|
+
# @return [String] git's stdout from the commit
|
|
122
|
+
#
|
|
123
|
+
# @raise [ArgumentError] when unsupported options are provided
|
|
124
|
+
#
|
|
125
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
126
|
+
#
|
|
127
|
+
def commit_all(message, opts = {})
|
|
128
|
+
commit(message, opts.merge(all: true))
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Create a commit object from a tree SHA without moving HEAD
|
|
132
|
+
#
|
|
133
|
+
# Unlike {#commit}, this does not read the index; it directly wraps
|
|
134
|
+
# `git commit-tree`.
|
|
135
|
+
#
|
|
136
|
+
# @example Commit a tree with a parent
|
|
137
|
+
# repo.commit_tree('deadbeef', message: 'snapshot', parent: 'HEAD')
|
|
138
|
+
#
|
|
139
|
+
# @param tree [String, nil] the tree SHA to commit; defaults to `nil`
|
|
140
|
+
#
|
|
141
|
+
# @param opts [Hash] options for the commit-tree command
|
|
142
|
+
#
|
|
143
|
+
# @option opts [String, Array<String>] :m (nil) the commit message
|
|
144
|
+
# paragraph(s) (short form)
|
|
145
|
+
#
|
|
146
|
+
# @option opts [String, Array<String>] :message (nil) the commit message
|
|
147
|
+
# paragraph(s) (normalized to `:m` before passing to the command)
|
|
148
|
+
#
|
|
149
|
+
# @option opts [String, Array<String>] :p (nil) parent commit SHA(s)
|
|
150
|
+
#
|
|
151
|
+
# @option opts [String] :parent (nil) a single parent commit SHA
|
|
152
|
+
# (normalized to `:p`)
|
|
153
|
+
#
|
|
154
|
+
# @option opts [Array<String>] :parents (nil) multiple parent commit
|
|
155
|
+
# SHAs (normalized to `:p`)
|
|
156
|
+
#
|
|
157
|
+
# @return [String] the SHA of the newly created commit object
|
|
158
|
+
#
|
|
159
|
+
# @raise [ArgumentError] when unsupported options are provided
|
|
160
|
+
#
|
|
161
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
162
|
+
#
|
|
163
|
+
def commit_tree(tree = nil, opts = {}) # rubocop:disable Metrics/AbcSize
|
|
164
|
+
SharedPrivate.assert_valid_opts!(COMMIT_TREE_ALLOWED_OPTS, **opts)
|
|
165
|
+
|
|
166
|
+
opts = opts.dup
|
|
167
|
+
opts[:p] = opts.delete(:parents) if opts.key?(:parents)
|
|
168
|
+
opts[:p] = opts.delete(:parent) if opts.key?(:parent)
|
|
169
|
+
opts[:m] = opts.delete(:message) if opts.key?(:message)
|
|
170
|
+
opts[:m] = "commit tree #{tree}" unless opts[:m]
|
|
171
|
+
|
|
172
|
+
Git::Commands::CommitTree.new(@execution_context).call(tree, **opts).stdout
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Write the current index to a tree object in the object store
|
|
176
|
+
#
|
|
177
|
+
# @example Get the tree SHA of the current index
|
|
178
|
+
# tree_sha = repo.write_tree
|
|
179
|
+
#
|
|
180
|
+
# @return [String] the SHA of the tree object written
|
|
181
|
+
#
|
|
182
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
183
|
+
#
|
|
184
|
+
def write_tree
|
|
185
|
+
Git::Commands::WriteTree.new(@execution_context).call.stdout
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Write the current index to a tree object and immediately commit it
|
|
189
|
+
#
|
|
190
|
+
# Combines {#write_tree} and {#commit_tree} in a single call.
|
|
191
|
+
#
|
|
192
|
+
# @example Commit the current index as a snapshot
|
|
193
|
+
# commit_sha = repo.write_and_commit_tree(message: 'snapshot')
|
|
194
|
+
#
|
|
195
|
+
# @param opts [Hash] options forwarded to {#commit_tree}
|
|
196
|
+
#
|
|
197
|
+
# @option opts [String, Array<String>] :m (nil) the commit message
|
|
198
|
+
# paragraph(s) (short form)
|
|
199
|
+
#
|
|
200
|
+
# @option opts [String, Array<String>] :message (nil) the commit message
|
|
201
|
+
# paragraph(s) (normalized to `:m` before passing to the command)
|
|
202
|
+
#
|
|
203
|
+
# @option opts [String, Array<String>] :p (nil) parent commit SHA(s)
|
|
204
|
+
#
|
|
205
|
+
# @option opts [String] :parent (nil) a single parent commit SHA
|
|
206
|
+
# (normalized to `:p`)
|
|
207
|
+
#
|
|
208
|
+
# @option opts [Array<String>] :parents (nil) multiple parent commit
|
|
209
|
+
# SHAs (normalized to `:p`)
|
|
210
|
+
#
|
|
211
|
+
# @return [String] the SHA of the newly created commit object
|
|
212
|
+
#
|
|
213
|
+
# @raise [ArgumentError] when unsupported options are provided
|
|
214
|
+
#
|
|
215
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
216
|
+
#
|
|
217
|
+
def write_and_commit_tree(opts = {})
|
|
218
|
+
commit_tree(write_tree, opts)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
private
|
|
222
|
+
|
|
223
|
+
# Normalizes deprecated commit options into their supported form
|
|
224
|
+
#
|
|
225
|
+
# @param opts [Hash] caller-provided commit options
|
|
226
|
+
#
|
|
227
|
+
# @option opts [Boolean, nil] :add_all (nil) deprecated alias for `:all`
|
|
228
|
+
#
|
|
229
|
+
# @return [Hash] options with deprecated aliases translated
|
|
230
|
+
#
|
|
231
|
+
# @api private
|
|
232
|
+
#
|
|
233
|
+
def normalize_commit_options(opts)
|
|
234
|
+
opts = opts.dup
|
|
235
|
+
return opts unless opts.key?(:add_all)
|
|
236
|
+
|
|
237
|
+
Git::Deprecation.warn(
|
|
238
|
+
'The :add_all option for #commit is deprecated and will be removed in v6.0.0. ' \
|
|
239
|
+
'Use :all instead.'
|
|
240
|
+
)
|
|
241
|
+
opts[:all] = opts.delete(:add_all)
|
|
242
|
+
opts
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require 'tmpdir'
|
|
6
|
+
require 'git/execution_context/repository'
|
|
7
|
+
|
|
8
|
+
module Git
|
|
9
|
+
class Repository
|
|
10
|
+
# Facade methods for block-based directory and index context helpers
|
|
11
|
+
#
|
|
12
|
+
# These helpers allow callers to temporarily change the working directory,
|
|
13
|
+
# the git index, or both, restoring the original state unconditionally when
|
|
14
|
+
# the block exits — even if the block raises an exception.
|
|
15
|
+
#
|
|
16
|
+
# Included by {Git::Repository}.
|
|
17
|
+
#
|
|
18
|
+
# @api private
|
|
19
|
+
#
|
|
20
|
+
module ContextHelpers
|
|
21
|
+
# Changes the current working directory to the repository working directory
|
|
22
|
+
# for the duration of the block
|
|
23
|
+
#
|
|
24
|
+
# @example Write a file inside the repository working directory
|
|
25
|
+
# repo.chdir do |dir|
|
|
26
|
+
# File.write('hello.txt', 'Hello, world!')
|
|
27
|
+
# repo.add('hello.txt')
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# @return [Object] the value returned by the block
|
|
31
|
+
#
|
|
32
|
+
# @raise [ArgumentError] if the repository has no working directory (bare
|
|
33
|
+
# repository)
|
|
34
|
+
#
|
|
35
|
+
# @yield [dir] the repository working directory
|
|
36
|
+
#
|
|
37
|
+
# @yieldparam dir [Pathname] the working directory path
|
|
38
|
+
#
|
|
39
|
+
# @yieldreturn [Object] returned as the method's return value
|
|
40
|
+
#
|
|
41
|
+
def chdir
|
|
42
|
+
raise ArgumentError, 'cannot chdir: repository has no working directory (bare repository)' if dir.nil?
|
|
43
|
+
|
|
44
|
+
Dir.chdir(dir.to_s) { yield dir }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Temporarily switches the git index to `new_index` for the duration of
|
|
48
|
+
# the block
|
|
49
|
+
#
|
|
50
|
+
# Rebuilds the repository execution context to point to the new index file,
|
|
51
|
+
# yields `self`, then unconditionally restores the original execution
|
|
52
|
+
# context — even if the block raises an exception.
|
|
53
|
+
#
|
|
54
|
+
# @example Read a tree into a custom index
|
|
55
|
+
# repo.with_index('/tmp/custom.index') do
|
|
56
|
+
# repo.read_tree('HEAD')
|
|
57
|
+
# end
|
|
58
|
+
#
|
|
59
|
+
# @param new_index [String, Pathname] path to the replacement index file
|
|
60
|
+
#
|
|
61
|
+
# @return [Object] the value returned by the block
|
|
62
|
+
#
|
|
63
|
+
# @yield [repo] the repository instance with the new index active
|
|
64
|
+
#
|
|
65
|
+
# @yieldparam repo [Git::Repository] `self`
|
|
66
|
+
#
|
|
67
|
+
# @yieldreturn [Object] returned as the method's return value
|
|
68
|
+
#
|
|
69
|
+
def with_index(new_index) # :yields: self
|
|
70
|
+
old_context = @execution_context
|
|
71
|
+
set_index(new_index, must_exist: false)
|
|
72
|
+
yield self
|
|
73
|
+
ensure
|
|
74
|
+
@execution_context = old_context
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Temporarily switches the git index to a new temporary file for the
|
|
78
|
+
# duration of the block, then removes the file
|
|
79
|
+
#
|
|
80
|
+
# The temporary index file does not exist until git creates it on first
|
|
81
|
+
# write. A unique temporary directory is created to hold the index path,
|
|
82
|
+
# avoiding the risk of presenting an empty file to git (which git would
|
|
83
|
+
# reject as a corrupt index). The directory — and any files inside it —
|
|
84
|
+
# are removed unconditionally after the block exits, even if the block
|
|
85
|
+
# raises an exception.
|
|
86
|
+
#
|
|
87
|
+
# @example Stage changes using a temporary index
|
|
88
|
+
# repo.with_temp_index do
|
|
89
|
+
# repo.read_tree('HEAD')
|
|
90
|
+
# repo.write_tree
|
|
91
|
+
# end
|
|
92
|
+
#
|
|
93
|
+
# @return [Object] the value returned by the block
|
|
94
|
+
#
|
|
95
|
+
# @yield [repo] the repository instance with the temporary index active
|
|
96
|
+
#
|
|
97
|
+
# @yieldparam repo [Git::Repository] `self`
|
|
98
|
+
#
|
|
99
|
+
# @yieldreturn [Object] returned as the method's return value
|
|
100
|
+
#
|
|
101
|
+
def with_temp_index(&) # :yields: self
|
|
102
|
+
# Use a unique temp directory so the index file path is collision-free
|
|
103
|
+
# and does not exist until git writes it. An existing empty file would
|
|
104
|
+
# be treated as a corrupt index by git.
|
|
105
|
+
temp_dir = Dir.mktmpdir('git-temp-index-')
|
|
106
|
+
begin
|
|
107
|
+
with_index(File.join(temp_dir, 'index'), &)
|
|
108
|
+
ensure
|
|
109
|
+
FileUtils.remove_entry(temp_dir, true)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Temporarily switches the git working directory to `work_dir` for the
|
|
114
|
+
# duration of the block
|
|
115
|
+
#
|
|
116
|
+
# Rebuilds the repository execution context to point to the new working
|
|
117
|
+
# directory, changes the process working directory via `Dir.chdir`, yields
|
|
118
|
+
# `self`, then unconditionally restores the original execution context —
|
|
119
|
+
# even if the block raises an exception.
|
|
120
|
+
#
|
|
121
|
+
# @example Commit changes from a different worktree path
|
|
122
|
+
# repo.with_working('/path/to/worktree') do
|
|
123
|
+
# repo.add('.')
|
|
124
|
+
# repo.commit('chore: automated update')
|
|
125
|
+
# end
|
|
126
|
+
#
|
|
127
|
+
# @param work_dir [String, Pathname] path to the replacement working
|
|
128
|
+
# directory
|
|
129
|
+
#
|
|
130
|
+
# @return [Object] the value returned by the block
|
|
131
|
+
#
|
|
132
|
+
# @raise [ArgumentError] if `work_dir` does not exist on disk
|
|
133
|
+
#
|
|
134
|
+
# @yield [repo] the repository instance with the new working directory
|
|
135
|
+
# active
|
|
136
|
+
#
|
|
137
|
+
# @yieldparam repo [Git::Repository] `self`
|
|
138
|
+
#
|
|
139
|
+
# @yieldreturn [Object] returned as the method's return value
|
|
140
|
+
#
|
|
141
|
+
def with_working(work_dir) # :yields: self
|
|
142
|
+
old_context = @execution_context
|
|
143
|
+
set_working(work_dir)
|
|
144
|
+
Dir.chdir(dir.to_s) { yield self }
|
|
145
|
+
ensure
|
|
146
|
+
@execution_context = old_context
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Temporarily switches the git working directory to a new temporary
|
|
150
|
+
# directory for the duration of the block, then removes the directory and
|
|
151
|
+
# its contents
|
|
152
|
+
#
|
|
153
|
+
# The temporary directory is removed unconditionally after the block
|
|
154
|
+
# exits, even if the block raises an exception.
|
|
155
|
+
#
|
|
156
|
+
# @example Write files in an isolated temporary working directory
|
|
157
|
+
# repo.with_temp_working do
|
|
158
|
+
# File.write('scratch.txt', 'temporary content')
|
|
159
|
+
# end
|
|
160
|
+
#
|
|
161
|
+
# @return [Object] the value returned by the block
|
|
162
|
+
#
|
|
163
|
+
# @yield [repo] the repository instance with the temporary working
|
|
164
|
+
# directory active
|
|
165
|
+
#
|
|
166
|
+
# @yieldparam repo [Git::Repository] `self`
|
|
167
|
+
#
|
|
168
|
+
# @yieldreturn [Object] returned as the method's return value
|
|
169
|
+
#
|
|
170
|
+
def with_temp_working(&block) # :yields: self
|
|
171
|
+
Dir.mktmpdir('temp-workdir') { |temp_dir| with_working(temp_dir, &block) }
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Sets the git index to `index_file` and rebuilds the execution context
|
|
175
|
+
#
|
|
176
|
+
# By default raises if `index_file` does not exist. Pass `must_exist:
|
|
177
|
+
# false` to skip the existence check (useful when the index will be
|
|
178
|
+
# created by git later).
|
|
179
|
+
#
|
|
180
|
+
# @example Set the index to a custom path
|
|
181
|
+
# repo.set_index('/path/to/custom.index')
|
|
182
|
+
#
|
|
183
|
+
# @param index_file [String, Pathname] path to the new index file
|
|
184
|
+
#
|
|
185
|
+
# @param check [Boolean, nil] deprecated positional argument — use
|
|
186
|
+
# `must_exist:` instead; emits a deprecation warning when non-`nil`
|
|
187
|
+
#
|
|
188
|
+
# @param must_exist [Boolean, nil] when `true` (the default), raises
|
|
189
|
+
# `ArgumentError` if `index_file` does not exist on disk
|
|
190
|
+
#
|
|
191
|
+
# @return [void]
|
|
192
|
+
#
|
|
193
|
+
# @raise [ArgumentError] if `must_exist: true` (the default) and
|
|
194
|
+
# `index_file` does not exist
|
|
195
|
+
#
|
|
196
|
+
def set_index(index_file, check = nil, must_exist: nil)
|
|
197
|
+
must_exist = context_helpers_deprecate_check_argument(check, must_exist)
|
|
198
|
+
new_path = context_helpers_validate_path(index_file, must_exist)
|
|
199
|
+
context_helpers_rebuild_context(git_index_file: new_path.to_s)
|
|
200
|
+
nil
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Sets the git working directory to `work_dir` and rebuilds the execution
|
|
204
|
+
# context
|
|
205
|
+
#
|
|
206
|
+
# By default raises if `work_dir` does not exist. Pass `must_exist:
|
|
207
|
+
# false` to skip the existence check.
|
|
208
|
+
#
|
|
209
|
+
# @example Set the working directory to a custom path
|
|
210
|
+
# repo.set_working('/path/to/working')
|
|
211
|
+
#
|
|
212
|
+
# @param work_dir [String, Pathname] path to the new working directory
|
|
213
|
+
#
|
|
214
|
+
# @param check [Boolean, nil] deprecated positional argument — use
|
|
215
|
+
# `must_exist:` instead; emits a deprecation warning when non-`nil`
|
|
216
|
+
#
|
|
217
|
+
# @param must_exist [Boolean, nil] when `true` (the default), raises
|
|
218
|
+
# `ArgumentError` if `work_dir` does not exist on disk
|
|
219
|
+
#
|
|
220
|
+
# @return [void]
|
|
221
|
+
#
|
|
222
|
+
# @raise [ArgumentError] if `must_exist: true` (the default) and
|
|
223
|
+
# `work_dir` does not exist
|
|
224
|
+
#
|
|
225
|
+
def set_working(work_dir, check = nil, must_exist: nil)
|
|
226
|
+
must_exist = context_helpers_deprecate_check_argument(check, must_exist)
|
|
227
|
+
new_path = context_helpers_validate_path(work_dir, must_exist)
|
|
228
|
+
context_helpers_rebuild_context(git_work_dir: new_path.to_s)
|
|
229
|
+
nil
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
private
|
|
233
|
+
|
|
234
|
+
# Resolves deprecated `check` argument semantics with `must_exist:`
|
|
235
|
+
#
|
|
236
|
+
# @param check [Boolean, nil] deprecated positional existence-check value
|
|
237
|
+
#
|
|
238
|
+
# @param must_exist [Boolean, nil] keyword existence-check override
|
|
239
|
+
#
|
|
240
|
+
# @return [Boolean] whether path existence must be enforced
|
|
241
|
+
#
|
|
242
|
+
def context_helpers_deprecate_check_argument(check, must_exist)
|
|
243
|
+
if !check.nil? && defined?(Git::Deprecation)
|
|
244
|
+
Git::Deprecation.warn(
|
|
245
|
+
'The "check" argument is deprecated and will be removed in v6.0.0. ' \
|
|
246
|
+
'Use "must_exist:" instead.'
|
|
247
|
+
)
|
|
248
|
+
end
|
|
249
|
+
# Preserve the original Git::Base semantics: when both the deprecated
|
|
250
|
+
# positional `check` and the new `must_exist:` keyword are given, OR
|
|
251
|
+
# them so the more restrictive value wins.
|
|
252
|
+
#
|
|
253
|
+
# NilClass#| is defined in Ruby: nil | false → false, nil | true → true.
|
|
254
|
+
# This means single-argument callers (check only, or must_exist: only)
|
|
255
|
+
# are handled correctly without any nil-special-casing.
|
|
256
|
+
return true if must_exist.nil? && check.nil?
|
|
257
|
+
|
|
258
|
+
must_exist | check
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Expands `path` and validates existence when required
|
|
262
|
+
#
|
|
263
|
+
# @param path [String, Pathname] path to normalize and validate
|
|
264
|
+
#
|
|
265
|
+
# @param must_exist [Boolean] whether the expanded path must already exist
|
|
266
|
+
#
|
|
267
|
+
# @return [Pathname] the expanded absolute path
|
|
268
|
+
#
|
|
269
|
+
# @raise [ArgumentError] if `must_exist` is `true` and the path does not exist
|
|
270
|
+
#
|
|
271
|
+
def context_helpers_validate_path(path, must_exist)
|
|
272
|
+
Pathname.new(File.expand_path(path.to_s)).tap do |expanded_path|
|
|
273
|
+
raise ArgumentError, "path does not exist: #{expanded_path}" if must_exist && !expanded_path.exist?
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Rebuilds the repository execution context with selected overrides
|
|
278
|
+
#
|
|
279
|
+
# @param overrides [Hash] execution-context attributes to override
|
|
280
|
+
#
|
|
281
|
+
# @option overrides [String, nil] :git_index_file replacement index file path
|
|
282
|
+
#
|
|
283
|
+
# @option overrides [String, nil] :git_work_dir replacement working directory
|
|
284
|
+
# path
|
|
285
|
+
#
|
|
286
|
+
# @return [void]
|
|
287
|
+
#
|
|
288
|
+
def context_helpers_rebuild_context(**overrides)
|
|
289
|
+
@execution_context = @execution_context.dup_with(**overrides)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|