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
data/lib/git/object.rb
CHANGED
|
@@ -24,24 +24,55 @@ module Git
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def sha
|
|
27
|
-
@sha ||=
|
|
27
|
+
@sha ||= object_repository.rev_parse(@objectish)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def size
|
|
31
|
-
@size ||=
|
|
31
|
+
@size ||= object_repository.cat_file_size(@objectish)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
34
|
+
# Returns the raw content of this git object or streams it into a temporary file
|
|
35
|
+
#
|
|
36
|
+
# Without a block, the full content is buffered in memory and cached, then
|
|
37
|
+
# returned as a `String`. With a block, git output is streamed directly to a
|
|
38
|
+
# temporary file on disk — suitable for large objects.
|
|
39
|
+
#
|
|
40
|
+
# @api public
|
|
41
|
+
#
|
|
42
|
+
# @overload contents
|
|
43
|
+
# Returns the cached content as a string.
|
|
44
|
+
#
|
|
45
|
+
# @return [String] the raw content of the object, cached after first call
|
|
46
|
+
#
|
|
47
|
+
# @raise [Git::FailedError] if the object does not exist or the command fails
|
|
48
|
+
#
|
|
49
|
+
# @example Get the contents of a blob
|
|
50
|
+
# git.object('HEAD:README.md').contents # => "This is a README file\n"
|
|
51
|
+
#
|
|
52
|
+
# @overload contents(&block)
|
|
53
|
+
# Streams the content to a temporary file and yields it.
|
|
54
|
+
#
|
|
55
|
+
# Git output is written directly to a file without buffering in
|
|
56
|
+
# memory. Use this form for large blobs to avoid memory pressure.
|
|
57
|
+
#
|
|
58
|
+
# @yield [file] the temporary file, positioned at the start of the content
|
|
59
|
+
#
|
|
60
|
+
# @yieldparam file [File] readable `IO` object positioned at the beginning
|
|
61
|
+
#
|
|
62
|
+
# @yieldreturn [Object] the value to return from this method
|
|
63
|
+
#
|
|
64
|
+
# @return [Object] the value returned by the block
|
|
65
|
+
#
|
|
66
|
+
# @raise [Git::FailedError] if the object does not exist or the command fails
|
|
67
|
+
#
|
|
68
|
+
# @example Read a large blob without loading it into memory
|
|
69
|
+
# git.object('HEAD:large_file.bin').contents { |f| upload(f) }
|
|
38
70
|
#
|
|
39
|
-
# Use this for large files so that they are not held in memory.
|
|
40
71
|
def contents(&)
|
|
41
72
|
if block_given?
|
|
42
|
-
|
|
73
|
+
object_repository.cat_file_contents(@objectish, &)
|
|
43
74
|
else
|
|
44
|
-
@contents ||=
|
|
75
|
+
@contents ||= object_repository.cat_file_contents(@objectish)
|
|
45
76
|
end
|
|
46
77
|
end
|
|
47
78
|
|
|
@@ -54,8 +85,7 @@ module Git
|
|
|
54
85
|
end
|
|
55
86
|
|
|
56
87
|
def grep(string, path_limiter = nil, opts = {})
|
|
57
|
-
|
|
58
|
-
@base.lib.grep(string, opts)
|
|
88
|
+
object_repository.grep(string, path_limiter, opts.merge(object: sha))
|
|
59
89
|
end
|
|
60
90
|
|
|
61
91
|
def diff(objectish)
|
|
@@ -66,9 +96,23 @@ module Git
|
|
|
66
96
|
Git::Log.new(@base, count).object(@objectish)
|
|
67
97
|
end
|
|
68
98
|
|
|
69
|
-
#
|
|
99
|
+
# Creates an archive of this object and writes it to a file
|
|
100
|
+
#
|
|
101
|
+
# @api public
|
|
102
|
+
#
|
|
103
|
+
# @param file [String, nil] destination file path; a temp file is created if `nil`
|
|
104
|
+
#
|
|
105
|
+
# @param opts [Hash] archive options (see {Git::Repository#archive})
|
|
106
|
+
#
|
|
107
|
+
# @return [String] the path to the written archive file
|
|
108
|
+
#
|
|
109
|
+
# @raise [Git::FailedError] if `git archive` fails
|
|
110
|
+
#
|
|
111
|
+
# @example Archive a tree to a zip file
|
|
112
|
+
# git.object('v1.0').archive('/tmp/release.zip', format: 'zip')
|
|
113
|
+
#
|
|
70
114
|
def archive(file = nil, opts = {})
|
|
71
|
-
|
|
115
|
+
object_repository.archive(@objectish, file, opts)
|
|
72
116
|
end
|
|
73
117
|
|
|
74
118
|
def tree? = false
|
|
@@ -78,6 +122,14 @@ module Git
|
|
|
78
122
|
def commit? = false
|
|
79
123
|
|
|
80
124
|
def tag? = false
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
# @return [Git::Repository]
|
|
129
|
+
#
|
|
130
|
+
def object_repository
|
|
131
|
+
@base
|
|
132
|
+
end
|
|
81
133
|
end
|
|
82
134
|
|
|
83
135
|
# A Git blob object
|
|
@@ -117,11 +169,11 @@ module Git
|
|
|
117
169
|
alias subdirectories trees
|
|
118
170
|
|
|
119
171
|
def full_tree
|
|
120
|
-
|
|
172
|
+
object_repository.full_tree(@objectish)
|
|
121
173
|
end
|
|
122
174
|
|
|
123
175
|
def depth
|
|
124
|
-
|
|
176
|
+
object_repository.tree_depth(@objectish)
|
|
125
177
|
end
|
|
126
178
|
|
|
127
179
|
def tree?
|
|
@@ -135,7 +187,7 @@ module Git
|
|
|
135
187
|
@trees = {}
|
|
136
188
|
@blobs = {}
|
|
137
189
|
|
|
138
|
-
data =
|
|
190
|
+
data = object_repository.ls_tree(@objectish)
|
|
139
191
|
|
|
140
192
|
data['tree'].each do |key, tree|
|
|
141
193
|
@trees[key] = Git::Object::Tree.new(@base, tree[:sha], tree[:mode])
|
|
@@ -169,7 +221,7 @@ module Git
|
|
|
169
221
|
end
|
|
170
222
|
|
|
171
223
|
def name
|
|
172
|
-
|
|
224
|
+
object_repository.name_rev(sha)
|
|
173
225
|
end
|
|
174
226
|
|
|
175
227
|
def gtree
|
|
@@ -239,7 +291,7 @@ module Git
|
|
|
239
291
|
def check_commit
|
|
240
292
|
return if @tree
|
|
241
293
|
|
|
242
|
-
data =
|
|
294
|
+
data = object_repository.cat_file_commit(@objectish)
|
|
243
295
|
from_data(data)
|
|
244
296
|
end
|
|
245
297
|
end
|
|
@@ -257,18 +309,23 @@ module Git
|
|
|
257
309
|
attr_accessor :name
|
|
258
310
|
|
|
259
311
|
# @overload initialize(base, name)
|
|
260
|
-
#
|
|
261
|
-
# @param
|
|
312
|
+
#
|
|
313
|
+
# @param base [Git::Repository] the git repository
|
|
314
|
+
#
|
|
315
|
+
# @param name [String] the name of the tag
|
|
262
316
|
#
|
|
263
317
|
# @overload initialize(base, sha, name)
|
|
264
|
-
#
|
|
265
|
-
# @param
|
|
266
|
-
#
|
|
318
|
+
#
|
|
319
|
+
# @param base [Git::Repository] the git repository
|
|
320
|
+
#
|
|
321
|
+
# @param sha [String] the SHA of the tag object
|
|
322
|
+
#
|
|
323
|
+
# @param name [String] the name of the tag
|
|
267
324
|
#
|
|
268
325
|
def initialize(base, sha, name = nil)
|
|
269
326
|
if name.nil?
|
|
270
327
|
name = sha
|
|
271
|
-
sha = base.
|
|
328
|
+
sha = base.tag_sha(name)
|
|
272
329
|
raise Git::UnexpectedResultError, "Tag '#{name}' does not exist." if sha == ''
|
|
273
330
|
end
|
|
274
331
|
|
|
@@ -280,7 +337,7 @@ module Git
|
|
|
280
337
|
end
|
|
281
338
|
|
|
282
339
|
def annotated?
|
|
283
|
-
@annotated = @annotated.nil? ? (
|
|
340
|
+
@annotated = @annotated.nil? ? (object_repository.cat_file_type(name) == 'tag') : @annotated
|
|
284
341
|
end
|
|
285
342
|
|
|
286
343
|
def message
|
|
@@ -303,7 +360,7 @@ module Git
|
|
|
303
360
|
return if @loaded
|
|
304
361
|
|
|
305
362
|
if annotated?
|
|
306
|
-
tdata =
|
|
363
|
+
tdata = object_repository.cat_file_tag(@name)
|
|
307
364
|
@message = tdata['message'].chomp
|
|
308
365
|
@tagger = Git::Author.new(tdata['tagger'])
|
|
309
366
|
else
|
|
@@ -319,7 +376,7 @@ module Git
|
|
|
319
376
|
def self.new(base, objectish, type = nil, is_tag = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
320
377
|
return new_tag(base, objectish) if is_tag
|
|
321
378
|
|
|
322
|
-
type ||= base.
|
|
379
|
+
type ||= object_repository_for(base).cat_file_type(objectish)
|
|
323
380
|
# TODO: why not handle tag case here too?
|
|
324
381
|
klass =
|
|
325
382
|
case type
|
|
@@ -334,5 +391,11 @@ module Git
|
|
|
334
391
|
Git::Deprecation.warn('Git::Object.new with is_tag argument is deprecated. Use Git::Object::Tag.new instead.')
|
|
335
392
|
Git::Object::Tag.new(base, objectish)
|
|
336
393
|
end
|
|
394
|
+
|
|
395
|
+
# @return [Git::Repository]
|
|
396
|
+
#
|
|
397
|
+
private_class_method def self.object_repository_for(base)
|
|
398
|
+
base
|
|
399
|
+
end
|
|
337
400
|
end
|
|
338
401
|
end
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/branch_info'
|
|
4
|
+
require 'git/branch_delete_result'
|
|
5
|
+
require 'git/branch_delete_failure'
|
|
6
|
+
|
|
7
|
+
module Git
|
|
8
|
+
module Parsers
|
|
9
|
+
# Parser for git branch command output
|
|
10
|
+
#
|
|
11
|
+
# Handles parsing of `git branch --list` and `git branch --delete` output
|
|
12
|
+
# into structured data objects.
|
|
13
|
+
#
|
|
14
|
+
# ## Design Note: Namespace Organization
|
|
15
|
+
#
|
|
16
|
+
# This parser creates and returns {Git::BranchInfo} and {Git::BranchDeleteResult}
|
|
17
|
+
# objects, which live at the top-level `Git::` namespace rather than within
|
|
18
|
+
# `Git::Parsers::`. This is intentional:
|
|
19
|
+
#
|
|
20
|
+
# - **Parsers are infrastructure** - marked `@api private`, users shouldn't
|
|
21
|
+
# interact with them directly
|
|
22
|
+
# - **Info/Result classes are public API** - returned by commands and used
|
|
23
|
+
# throughout the codebase
|
|
24
|
+
# - **Info classes are domain entities** - represent core git concepts
|
|
25
|
+
# (branches as data)
|
|
26
|
+
# - **Result classes are operation outcomes** - represent command results,
|
|
27
|
+
# not parsing details
|
|
28
|
+
#
|
|
29
|
+
# Keeping Info/Result classes at `Git::` improves discoverability and correctly
|
|
30
|
+
# reflects their role as public types rather than parser internals.
|
|
31
|
+
#
|
|
32
|
+
# @api private
|
|
33
|
+
#
|
|
34
|
+
module Branch
|
|
35
|
+
# Format string for git branch --format
|
|
36
|
+
#
|
|
37
|
+
# Fields (pipe-delimited):
|
|
38
|
+
# 1. refname - full ref name (e.g., refs/heads/main, refs/remotes/origin/main)
|
|
39
|
+
# 2. objectname - full SHA of the commit the branch points to
|
|
40
|
+
# 3. HEAD - '*' if current branch, empty otherwise
|
|
41
|
+
# 4. worktreepath - path if checked out in another worktree, empty otherwise
|
|
42
|
+
# 5. symref - target ref if symbolic reference, empty otherwise
|
|
43
|
+
# 6. upstream - full upstream ref (e.g., refs/remotes/origin/main), empty if none
|
|
44
|
+
#
|
|
45
|
+
FORMAT_STRING = '%(refname)|%(objectname)|%(HEAD)|%(worktreepath)|%(symref)|%(upstream)'
|
|
46
|
+
|
|
47
|
+
# Delimiter used in format output
|
|
48
|
+
FIELD_DELIMITER = '|'
|
|
49
|
+
|
|
50
|
+
# Regex to parse successful deletion lines from stdout
|
|
51
|
+
# Matches: Deleted branch branchname (was abc123).
|
|
52
|
+
# Matches: Deleted remote-tracking branch origin/branchname (was abc123).
|
|
53
|
+
# Uses non-greedy match to capture branch names containing spaces
|
|
54
|
+
DELETED_BRANCH_REGEX = /^Deleted (?:remote-tracking )?branch (.+?) \(was/
|
|
55
|
+
|
|
56
|
+
# Regex to parse error messages from stderr
|
|
57
|
+
# Matches: error: branch 'branchname' not found.
|
|
58
|
+
ERROR_BRANCH_REGEX = /^error: branch '([^']+)'(.*)$/
|
|
59
|
+
|
|
60
|
+
module_function
|
|
61
|
+
|
|
62
|
+
# Parse git branch --list output into BranchInfo objects
|
|
63
|
+
#
|
|
64
|
+
# @example
|
|
65
|
+
# Git::Parsers::Branch.parse_list("refs/heads/main|abc1234|*|||\nrefs/heads/feature|def5678||||\n")
|
|
66
|
+
# # => [#<data Git::BranchInfo refname="main", ...>, #<data Git::BranchInfo refname="feature", ...>]
|
|
67
|
+
#
|
|
68
|
+
# @param stdout [String] output from git branch --list --format=...
|
|
69
|
+
#
|
|
70
|
+
# @return [Array<Git::BranchInfo>] parsed branch information
|
|
71
|
+
#
|
|
72
|
+
def parse_list(stdout)
|
|
73
|
+
stdout.split("\n").filter_map { |line| parse_branch_line(line) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Parse a single formatted branch line
|
|
77
|
+
#
|
|
78
|
+
# @param line [String] the line to parse (pipe-delimited fields)
|
|
79
|
+
# @return [Git::BranchInfo, nil] branch info object, or nil if line should be skipped
|
|
80
|
+
#
|
|
81
|
+
def parse_branch_line(line)
|
|
82
|
+
fields = line.split(FIELD_DELIMITER, 6)
|
|
83
|
+
|
|
84
|
+
return nil if non_branch_entry?(fields[0])
|
|
85
|
+
|
|
86
|
+
build_branch_info(fields)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Build a BranchInfo from parsed fields
|
|
90
|
+
#
|
|
91
|
+
# @param fields [Array<String>] the parsed fields: [refname, objectname, head, worktreepath, symref, upstream]
|
|
92
|
+
# @return [Git::BranchInfo] the branch info object
|
|
93
|
+
#
|
|
94
|
+
def build_branch_info(fields)
|
|
95
|
+
raw_refname, objectname, head, worktreepath, symref, upstream = fields
|
|
96
|
+
current = head == '*'
|
|
97
|
+
|
|
98
|
+
Git::BranchInfo.new(
|
|
99
|
+
refname: normalize_refname(raw_refname),
|
|
100
|
+
target_oid: presence(objectname),
|
|
101
|
+
current: current,
|
|
102
|
+
worktree: in_other_worktree?(worktreepath, current),
|
|
103
|
+
symref: presence(symref),
|
|
104
|
+
upstream: build_upstream_info(upstream)
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Check if the refname represents a detached HEAD state or non-branch entry
|
|
109
|
+
#
|
|
110
|
+
# Git outputs special entries for detached HEAD and non-branch states:
|
|
111
|
+
# - "(HEAD detached at <ref>)" when in detached HEAD state
|
|
112
|
+
# - "(not a branch)" for non-branch entries
|
|
113
|
+
#
|
|
114
|
+
# @param refname [String] the refname to check
|
|
115
|
+
# @return [Boolean] true if this is a non-branch entry
|
|
116
|
+
#
|
|
117
|
+
def non_branch_entry?(refname)
|
|
118
|
+
refname.match?(/^\(HEAD detached/) || refname.match?(/^\(not a branch\)/)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Normalize a full refname to the expected format
|
|
122
|
+
#
|
|
123
|
+
# Converts:
|
|
124
|
+
# - refs/heads/main -> main
|
|
125
|
+
# - refs/remotes/origin/main -> remotes/origin/main
|
|
126
|
+
#
|
|
127
|
+
# @param refname [String] the full refname from git
|
|
128
|
+
# @return [String] normalized refname
|
|
129
|
+
#
|
|
130
|
+
def normalize_refname(refname)
|
|
131
|
+
refname.sub(%r{^refs/heads/}, '').sub(%r{^refs/}, '')
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Check if the branch is checked out in another worktree
|
|
135
|
+
#
|
|
136
|
+
# worktree is true when the branch is checked out in ANOTHER worktree
|
|
137
|
+
# (worktreepath is non-empty AND it's not the current branch)
|
|
138
|
+
#
|
|
139
|
+
# @param worktreepath [String, nil] the worktree path from git output
|
|
140
|
+
# @param current [Boolean] whether this is the current branch
|
|
141
|
+
# @return [Boolean] true if checked out in another worktree
|
|
142
|
+
#
|
|
143
|
+
def in_other_worktree?(worktreepath, current)
|
|
144
|
+
has_worktree = !worktreepath.nil? && !worktreepath.empty?
|
|
145
|
+
has_worktree && !current
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Build upstream BranchInfo from upstream refname
|
|
149
|
+
#
|
|
150
|
+
# @param upstream_ref [String, nil] the upstream ref (e.g., 'refs/remotes/origin/main')
|
|
151
|
+
# @return [Git::BranchInfo, nil] upstream branch info or nil
|
|
152
|
+
#
|
|
153
|
+
def build_upstream_info(upstream_ref)
|
|
154
|
+
return nil if upstream_ref.nil? || upstream_ref.empty?
|
|
155
|
+
|
|
156
|
+
Git::BranchInfo.new(
|
|
157
|
+
refname: normalize_refname(upstream_ref),
|
|
158
|
+
target_oid: nil, # We don't have upstream's OID from this format
|
|
159
|
+
current: false,
|
|
160
|
+
worktree: false,
|
|
161
|
+
symref: nil,
|
|
162
|
+
upstream: nil # Upstream branches don't have their own upstream in this context
|
|
163
|
+
)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Return value if non-empty, nil otherwise
|
|
167
|
+
#
|
|
168
|
+
# @param value [String, nil] the value to check
|
|
169
|
+
# @return [String, nil] the value or nil
|
|
170
|
+
#
|
|
171
|
+
def presence(value)
|
|
172
|
+
value.nil? || value.empty? ? nil : value
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Parse deleted branch names from stdout
|
|
176
|
+
#
|
|
177
|
+
# @example
|
|
178
|
+
# BranchParser.parse_deleted_branches("Deleted branch feature (was abc123).\n")
|
|
179
|
+
# # => ["feature"]
|
|
180
|
+
#
|
|
181
|
+
# @param stdout [String] command stdout
|
|
182
|
+
# @return [Array<String>] names of successfully deleted branches
|
|
183
|
+
#
|
|
184
|
+
def parse_deleted_branches(stdout)
|
|
185
|
+
stdout.scan(DELETED_BRANCH_REGEX).flatten
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Parse error messages from stderr into a map
|
|
189
|
+
#
|
|
190
|
+
# @example
|
|
191
|
+
# BranchParser.parse_error_messages("error: branch 'missing' not found.\n")
|
|
192
|
+
# # => {"missing" => "error: branch 'missing' not found."}
|
|
193
|
+
#
|
|
194
|
+
# @param stderr [String] command stderr
|
|
195
|
+
# @return [Hash<String, String>] map of branch name to error message
|
|
196
|
+
#
|
|
197
|
+
def parse_error_messages(stderr)
|
|
198
|
+
stderr.each_line.with_object({}) do |line, hash|
|
|
199
|
+
match = line.match(ERROR_BRANCH_REGEX)
|
|
200
|
+
hash[match[1]] = line.strip if match
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Build the BranchDeleteResult from parsed data
|
|
205
|
+
#
|
|
206
|
+
# @param requested_names [Array<String>] originally requested branch names
|
|
207
|
+
# @param existing_branches [Hash<String, Git::BranchInfo>] branches that existed before delete
|
|
208
|
+
# @param deleted_names [Array<String>] names confirmed deleted in stdout
|
|
209
|
+
# @param error_map [Hash<String, String>] map of branch name to error message
|
|
210
|
+
# @return [Git::BranchDeleteResult] the result object
|
|
211
|
+
#
|
|
212
|
+
def build_delete_result(requested_names, existing_branches, deleted_names, error_map)
|
|
213
|
+
deleted = deleted_names.filter_map { |name| existing_branches[name] }
|
|
214
|
+
|
|
215
|
+
not_deleted = (requested_names - deleted_names).map do |name|
|
|
216
|
+
error_message = error_map[name] || "branch '#{name}' could not be deleted"
|
|
217
|
+
Git::BranchDeleteFailure.new(name: name, error_message: error_message)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
Git::BranchDeleteResult.new(deleted: deleted, not_deleted: not_deleted)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
module Parsers
|
|
5
|
+
# Parser for `git cat-file` commit and tag output
|
|
6
|
+
#
|
|
7
|
+
# Provides class methods that transform raw `git cat-file` output lines into
|
|
8
|
+
# structured Hash objects consumed by the `Git::Repository::ObjectOperations`
|
|
9
|
+
# facade.
|
|
10
|
+
#
|
|
11
|
+
# @api private
|
|
12
|
+
#
|
|
13
|
+
module CatFile
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# Matches a single `git cat-file` header line
|
|
17
|
+
#
|
|
18
|
+
# @api private
|
|
19
|
+
#
|
|
20
|
+
CAT_FILE_HEADER_LINE = /\A(?<key>\w+) (?<value>.*)\z/
|
|
21
|
+
|
|
22
|
+
# Parse `git cat-file commit` output into a structured Hash
|
|
23
|
+
#
|
|
24
|
+
# @param lines [Array<String>] mutable cat-file output lines, consumed
|
|
25
|
+
# in place during header parsing
|
|
26
|
+
#
|
|
27
|
+
# @param sha [String] the object name passed by the caller
|
|
28
|
+
#
|
|
29
|
+
# @return [Hash] commit data hash with string keys
|
|
30
|
+
#
|
|
31
|
+
# @api private
|
|
32
|
+
#
|
|
33
|
+
def parse_commit(lines, sha)
|
|
34
|
+
headers = parse_commit_headers(lines)
|
|
35
|
+
message = "#{lines.join("\n")}\n"
|
|
36
|
+
{ 'sha' => sha, 'message' => message }.merge(headers)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Parse `git cat-file tag` output into a structured Hash
|
|
40
|
+
#
|
|
41
|
+
# @param lines [Array<String>] mutable cat-file output lines, consumed
|
|
42
|
+
# in place during header parsing; remaining lines become the message
|
|
43
|
+
#
|
|
44
|
+
# @param name [String] the tag name passed by the caller
|
|
45
|
+
#
|
|
46
|
+
# @return [Hash] tag data hash with string keys
|
|
47
|
+
#
|
|
48
|
+
# @api private
|
|
49
|
+
#
|
|
50
|
+
def parse_tag(lines, name)
|
|
51
|
+
hsh = { 'name' => name }
|
|
52
|
+
each_header(lines) { |key, value| hsh[key] = value }
|
|
53
|
+
hsh['message'] = "#{lines.join("\n")}\n"
|
|
54
|
+
hsh
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Extracts and returns commit headers from the front of `lines`
|
|
58
|
+
#
|
|
59
|
+
# Mutates `lines` in place, consuming header lines and the blank
|
|
60
|
+
# separator line. After the call `lines` contains only message lines.
|
|
61
|
+
#
|
|
62
|
+
# @param lines [Array<String>] mutable cat-file output lines
|
|
63
|
+
#
|
|
64
|
+
# @return [Hash] parsed header key/value pairs; `parent` is always
|
|
65
|
+
# an Array
|
|
66
|
+
#
|
|
67
|
+
# @api private
|
|
68
|
+
#
|
|
69
|
+
def parse_commit_headers(lines)
|
|
70
|
+
headers = { 'parent' => [] }
|
|
71
|
+
each_header(lines) do |key, value|
|
|
72
|
+
if key == 'parent'
|
|
73
|
+
headers['parent'] << value
|
|
74
|
+
else
|
|
75
|
+
headers[key] = value
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
headers
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Yields parsed header key/value pairs from `git cat-file` output lines
|
|
82
|
+
#
|
|
83
|
+
# Consumes header lines from the front of `lines` until a blank line is
|
|
84
|
+
# encountered. Continuation lines that begin with a space are folded
|
|
85
|
+
# into the previous header value using newline separators.
|
|
86
|
+
#
|
|
87
|
+
# @param lines [Array<String>] mutable output lines from a cat-file response
|
|
88
|
+
#
|
|
89
|
+
# @yield [key, value] each parsed header pair
|
|
90
|
+
#
|
|
91
|
+
# @yieldparam key [String] header field name
|
|
92
|
+
#
|
|
93
|
+
# @yieldparam value [String] unfolded header value text
|
|
94
|
+
#
|
|
95
|
+
# @yieldreturn [void]
|
|
96
|
+
#
|
|
97
|
+
# @return [void]
|
|
98
|
+
#
|
|
99
|
+
# @api private
|
|
100
|
+
#
|
|
101
|
+
def each_header(lines)
|
|
102
|
+
while (line = lines.shift) && (match = CAT_FILE_HEADER_LINE.match(line))
|
|
103
|
+
key = match[:key]
|
|
104
|
+
value_lines = [match[:value]]
|
|
105
|
+
value_lines << lines.shift.lstrip while lines.first&.start_with?(' ')
|
|
106
|
+
yield key, value_lines.join("\n")
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/config_entry_info'
|
|
4
|
+
|
|
5
|
+
module Git
|
|
6
|
+
module Parsers
|
|
7
|
+
# Parser for `git config` output
|
|
8
|
+
#
|
|
9
|
+
# Each public method corresponds to a different `git config` sub-command
|
|
10
|
+
# variant and handles the specific output format that variant produces.
|
|
11
|
+
# Most variants are called with `--show-scope --show-origin --null`;
|
|
12
|
+
# `parse_urlmatch` handles the `--get-urlmatch` format where `--show-origin`
|
|
13
|
+
# is unsupported and therefore absent.
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
16
|
+
#
|
|
17
|
+
module ConfigEntry
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# Parse `git config --get --show-scope --show-origin --null` output
|
|
21
|
+
#
|
|
22
|
+
# Output format (per entry): `scope\0origin\0value\0`
|
|
23
|
+
#
|
|
24
|
+
# The key name is absent from `--get` output and must be supplied by the
|
|
25
|
+
# caller.
|
|
26
|
+
#
|
|
27
|
+
# @param key [String] the config key name that was queried
|
|
28
|
+
#
|
|
29
|
+
# @param output [String] raw stdout from the command
|
|
30
|
+
#
|
|
31
|
+
# @return [Git::ConfigEntryInfo, nil] the parsed entry, or `nil` when not found
|
|
32
|
+
#
|
|
33
|
+
def parse_get(key, output)
|
|
34
|
+
return nil if output.empty?
|
|
35
|
+
|
|
36
|
+
scope, origin, value = output.split("\0", -1)
|
|
37
|
+
Git::ConfigEntryInfo.new(scope: scope, origin: origin, key: key, value: value)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Parse `git config --get-all --show-scope --show-origin --null` output
|
|
41
|
+
#
|
|
42
|
+
# Output format (per entry): `scope\0origin\0value\0`
|
|
43
|
+
#
|
|
44
|
+
# The key name is absent from `--get-all` output and must be supplied by
|
|
45
|
+
# the caller. Multiple entries appear back-to-back in the same string.
|
|
46
|
+
#
|
|
47
|
+
# @param key [String] the config key name that was queried
|
|
48
|
+
#
|
|
49
|
+
# @param output [String] raw stdout from the command
|
|
50
|
+
#
|
|
51
|
+
# @return [Array<Git::ConfigEntryInfo>] the parsed entries
|
|
52
|
+
#
|
|
53
|
+
def parse_get_all(key, output)
|
|
54
|
+
return [] if output.empty?
|
|
55
|
+
|
|
56
|
+
tokens = output.split("\0", -1)
|
|
57
|
+
tokens.pop if tokens.last == ''
|
|
58
|
+
tokens.each_slice(3).map do |scope, origin, value|
|
|
59
|
+
Git::ConfigEntryInfo.new(scope: scope, origin: origin, key: key, value: value)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Parse `git config --list --show-scope --show-origin --null` output
|
|
64
|
+
#
|
|
65
|
+
# Also handles `--get-regexp` output, which shares the same format.
|
|
66
|
+
#
|
|
67
|
+
# Output format (per entry): `scope\0origin\0key\nvalue\0`
|
|
68
|
+
#
|
|
69
|
+
# Multiple entries appear back-to-back in the same string.
|
|
70
|
+
#
|
|
71
|
+
# @param output [String] raw stdout from the command
|
|
72
|
+
#
|
|
73
|
+
# @return [Array<Git::ConfigEntryInfo>] the parsed entries
|
|
74
|
+
#
|
|
75
|
+
def parse_list(output)
|
|
76
|
+
return [] if output.empty?
|
|
77
|
+
|
|
78
|
+
tokens = output.split("\0", -1)
|
|
79
|
+
tokens.pop if tokens.last == ''
|
|
80
|
+
tokens.each_slice(3).map do |scope, origin, key_value|
|
|
81
|
+
key, value = key_value.split("\n", 2)
|
|
82
|
+
Git::ConfigEntryInfo.new(scope: scope, origin: origin, key: key, value: value || '')
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Parse `git config --get-urlmatch --show-scope --null` output
|
|
87
|
+
#
|
|
88
|
+
# Handles the two-field-per-entry format produced by `--get-urlmatch` when
|
|
89
|
+
# `--show-scope` is used but `--show-origin` is not (git does not support
|
|
90
|
+
# `--show-origin` with `--get-urlmatch`).
|
|
91
|
+
#
|
|
92
|
+
# Output format (per entry): `scope\0key\nvalue\0`
|
|
93
|
+
#
|
|
94
|
+
# @param output [String] raw stdout from the command
|
|
95
|
+
#
|
|
96
|
+
# @return [Array<Git::ConfigEntryInfo>] the parsed entries; `origin` is `nil` for each
|
|
97
|
+
#
|
|
98
|
+
def parse_urlmatch(output)
|
|
99
|
+
return [] if output.empty?
|
|
100
|
+
|
|
101
|
+
tokens = output.split("\0", -1)
|
|
102
|
+
tokens.pop if tokens.last == ''
|
|
103
|
+
tokens.each_slice(2).map do |scope, key_value|
|
|
104
|
+
key, value = key_value.split("\n", 2)
|
|
105
|
+
Git::ConfigEntryInfo.new(scope: scope, origin: nil, key: key, value: value || '')
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|