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,258 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
# Immutable value object for the status of one path in the index and working tree
|
|
5
|
+
#
|
|
6
|
+
# Each member holds one field of the entry `git status --porcelain=v2` reports
|
|
7
|
+
# for the path. `index_status` and `worktree_status` are the `X` and `Y`
|
|
8
|
+
# characters of that entry: `.` unmodified, `M` modified, `T` type changed, `A`
|
|
9
|
+
# added, `D` deleted, `R` renamed, `C` copied, or `U` unmerged. Untracked
|
|
10
|
+
# entries carry `?` in both and ignored entries carry `!` in both, mirroring
|
|
11
|
+
# the `??` and `!!` codes of the short status format.
|
|
12
|
+
#
|
|
13
|
+
# The mode and SHA members are `nil` for untracked and ignored entries. For
|
|
14
|
+
# unmerged entries the per-stage modes and SHAs live in `unmerged_stages` and
|
|
15
|
+
# `mode_head`, `mode_index`, `sha_head`, and `sha_index` are `nil`.
|
|
16
|
+
# `original_path` and `rename_score` are set only for rename and copy entries.
|
|
17
|
+
#
|
|
18
|
+
# The predicates follow these rules: `added?` when `index_status` is `A`,
|
|
19
|
+
# `deleted?` when either status is `D`, `changed?` when either status is `M`
|
|
20
|
+
# or `T`, `renamed?` when either status is `R`, `untracked?` and `ignored?`
|
|
21
|
+
# from the `?` and `!` codes, and `unmerged?` when `unmerged_stages` is set.
|
|
22
|
+
#
|
|
23
|
+
# Every String member is a frozen copy of the value given, and
|
|
24
|
+
# `unmerged_stages` is a deeply frozen copy, so an entry cannot be changed
|
|
25
|
+
# through a member the caller still references.
|
|
26
|
+
#
|
|
27
|
+
# @example Inspect the status of one path
|
|
28
|
+
# file = repo.status_info['lib/foo.rb']
|
|
29
|
+
# file.index_status #=> "M"
|
|
30
|
+
# file.worktree_status #=> "."
|
|
31
|
+
# file.changed? #=> true
|
|
32
|
+
# file.sha_index #=> "2bdf67abb163a4ffb2d7f3f0880c9fe5068ce782"
|
|
33
|
+
#
|
|
34
|
+
# @example Read the original path of a rename
|
|
35
|
+
# file = repo.status_info['lib/new_name.rb']
|
|
36
|
+
# file.renamed? #=> true
|
|
37
|
+
# file.original_path #=> "lib/old_name.rb"
|
|
38
|
+
# file.rename_score #=> 100
|
|
39
|
+
#
|
|
40
|
+
# @example Read the stages of a merge conflict
|
|
41
|
+
# file = repo.status_info['lib/conflict.rb']
|
|
42
|
+
# file.unmerged? #=> true
|
|
43
|
+
# file.unmerged_stages[2] #=> { mode: "100644", sha: "ba2906d0666c..." }
|
|
44
|
+
#
|
|
45
|
+
# @see Git::StatusInfo
|
|
46
|
+
#
|
|
47
|
+
# @see Git::Repository#status_info
|
|
48
|
+
#
|
|
49
|
+
# @see https://git-scm.com/docs/git-status#_porcelain_format_version_2
|
|
50
|
+
#
|
|
51
|
+
# @api public
|
|
52
|
+
#
|
|
53
|
+
# @!attribute [r] path
|
|
54
|
+
#
|
|
55
|
+
# @return [String] the repository-relative path
|
|
56
|
+
#
|
|
57
|
+
# @!attribute [r] index_status
|
|
58
|
+
#
|
|
59
|
+
# @return [String] the `X` status character (HEAD versus index), `?` for
|
|
60
|
+
# untracked and `!` for ignored entries
|
|
61
|
+
#
|
|
62
|
+
# @!attribute [r] worktree_status
|
|
63
|
+
#
|
|
64
|
+
# @return [String] the `Y` status character (index versus working tree), `?`
|
|
65
|
+
# for untracked and `!` for ignored entries
|
|
66
|
+
#
|
|
67
|
+
# @!attribute [r] submodule
|
|
68
|
+
#
|
|
69
|
+
# @return [String, nil] the four-character submodule state (`N...` for a
|
|
70
|
+
# regular file), or `nil` for untracked and ignored entries
|
|
71
|
+
#
|
|
72
|
+
# @!attribute [r] mode_head
|
|
73
|
+
#
|
|
74
|
+
# @return [String, nil] the octal file mode in HEAD (`000000` when the path
|
|
75
|
+
# is not in HEAD), or `nil` for untracked, ignored, and unmerged entries
|
|
76
|
+
#
|
|
77
|
+
# @!attribute [r] mode_index
|
|
78
|
+
#
|
|
79
|
+
# @return [String, nil] the octal file mode in the index (`000000` when the
|
|
80
|
+
# path is not in the index), or `nil` for untracked, ignored, and unmerged
|
|
81
|
+
# entries
|
|
82
|
+
#
|
|
83
|
+
# @!attribute [r] mode_worktree
|
|
84
|
+
#
|
|
85
|
+
# @return [String, nil] the octal file mode in the working tree (`000000`
|
|
86
|
+
# when the path is not in the working tree), or `nil` for untracked and
|
|
87
|
+
# ignored entries
|
|
88
|
+
#
|
|
89
|
+
# @!attribute [r] sha_head
|
|
90
|
+
#
|
|
91
|
+
# @return [String, nil] the object name of the blob in HEAD (all zeros when
|
|
92
|
+
# the path is not in HEAD), or `nil` for untracked, ignored, and unmerged
|
|
93
|
+
# entries
|
|
94
|
+
#
|
|
95
|
+
# @!attribute [r] sha_index
|
|
96
|
+
#
|
|
97
|
+
# @return [String, nil] the object name of the blob in the index (all zeros
|
|
98
|
+
# when the path is not in the index), or `nil` for untracked, ignored, and
|
|
99
|
+
# unmerged entries
|
|
100
|
+
#
|
|
101
|
+
# @!attribute [r] original_path
|
|
102
|
+
#
|
|
103
|
+
# @return [String, nil] the path the entry was renamed or copied from, or
|
|
104
|
+
# `nil` for every other entry
|
|
105
|
+
#
|
|
106
|
+
# @!attribute [r] rename_score
|
|
107
|
+
#
|
|
108
|
+
# @return [Integer, nil] the similarity score of a rename or copy entry, or
|
|
109
|
+
# `nil` for every other entry
|
|
110
|
+
#
|
|
111
|
+
# @!attribute [r] unmerged_stages
|
|
112
|
+
#
|
|
113
|
+
# @return [Hash{Integer => Hash{Symbol => String}}, nil] the mode and SHA of
|
|
114
|
+
# each conflict stage keyed by stage number (1 for the merge base, 2 for
|
|
115
|
+
# "ours", 3 for "theirs"), as frozen `\\{ mode:, sha: }` hashes, or `nil`
|
|
116
|
+
# for every other entry
|
|
117
|
+
#
|
|
118
|
+
StatusFileInfo = Data.define(
|
|
119
|
+
:path,
|
|
120
|
+
:index_status,
|
|
121
|
+
:worktree_status,
|
|
122
|
+
:submodule,
|
|
123
|
+
:mode_head,
|
|
124
|
+
:mode_index,
|
|
125
|
+
:mode_worktree,
|
|
126
|
+
:sha_head,
|
|
127
|
+
:sha_index,
|
|
128
|
+
:original_path,
|
|
129
|
+
:rename_score,
|
|
130
|
+
:unmerged_stages
|
|
131
|
+
) do
|
|
132
|
+
# Creates a file status value object holding frozen copies of its members
|
|
133
|
+
#
|
|
134
|
+
# String members are duplicated and frozen, and `unmerged_stages` is
|
|
135
|
+
# duplicated and frozen down to its mode and SHA strings, so neither this
|
|
136
|
+
# value nor a {Git::StatusInfo} holding it can be changed through a member
|
|
137
|
+
# the caller still references.
|
|
138
|
+
#
|
|
139
|
+
# @example Build an entry from parsed fields
|
|
140
|
+
# Git::StatusFileInfo.new(path: 'lib/foo.rb', index_status: 'M', worktree_status: '.', ...)
|
|
141
|
+
#
|
|
142
|
+
# @param members [Hash{Symbol => Object}] one value per member; every
|
|
143
|
+
# member is required
|
|
144
|
+
#
|
|
145
|
+
# @option members [String] :path the repository-relative path
|
|
146
|
+
#
|
|
147
|
+
# @option members [String] :index_status the `X` status character
|
|
148
|
+
#
|
|
149
|
+
# @option members [String] :worktree_status the `Y` status character
|
|
150
|
+
#
|
|
151
|
+
# @option members [String, nil] :submodule the four-character submodule state
|
|
152
|
+
#
|
|
153
|
+
# @option members [String, nil] :mode_head the octal file mode in HEAD
|
|
154
|
+
#
|
|
155
|
+
# @option members [String, nil] :mode_index the octal file mode in the index
|
|
156
|
+
#
|
|
157
|
+
# @option members [String, nil] :mode_worktree the octal file mode in the working tree
|
|
158
|
+
#
|
|
159
|
+
# @option members [String, nil] :sha_head the object name of the blob in HEAD
|
|
160
|
+
#
|
|
161
|
+
# @option members [String, nil] :sha_index the object name of the blob in the index
|
|
162
|
+
#
|
|
163
|
+
# @option members [String, nil] :original_path the path a rename or copy came from
|
|
164
|
+
#
|
|
165
|
+
# @option members [Integer, nil] :rename_score the similarity score of a rename or copy
|
|
166
|
+
#
|
|
167
|
+
# @option members [Hash{Integer => Hash{Symbol => String}}, nil] :unmerged_stages
|
|
168
|
+
# the mode and SHA of each conflict stage keyed by stage number
|
|
169
|
+
#
|
|
170
|
+
def initialize(**members)
|
|
171
|
+
super(**members.transform_values { |value| deep_frozen(value) })
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Returns `true` when the path is not tracked by git
|
|
175
|
+
#
|
|
176
|
+
# @example Check an untracked path
|
|
177
|
+
# repo.status_info['new.rb'].untracked? #=> true
|
|
178
|
+
#
|
|
179
|
+
# @return [Boolean] `true` when both status characters are `?`
|
|
180
|
+
#
|
|
181
|
+
def untracked? = index_status == '?' && worktree_status == '?'
|
|
182
|
+
|
|
183
|
+
# Returns `true` when the path is ignored
|
|
184
|
+
#
|
|
185
|
+
# Ignored entries are reported only when `git status` runs with `--ignored`.
|
|
186
|
+
# {Git::Repository#status_info} does not pass that option, so this is
|
|
187
|
+
# `false` for every entry it returns.
|
|
188
|
+
#
|
|
189
|
+
# @example Check an ignored entry
|
|
190
|
+
# file = Git::Parsers::Status.parse("! tmp/debug.log\0").first
|
|
191
|
+
# file.ignored? #=> true
|
|
192
|
+
#
|
|
193
|
+
# @return [Boolean] `true` when both status characters are `!`
|
|
194
|
+
#
|
|
195
|
+
def ignored? = index_status == '!' && worktree_status == '!'
|
|
196
|
+
|
|
197
|
+
# Returns `true` when the path has merge conflicts
|
|
198
|
+
#
|
|
199
|
+
# @example Check a conflicted path
|
|
200
|
+
# repo.status_info['lib/conflict.rb'].unmerged? #=> true
|
|
201
|
+
#
|
|
202
|
+
# @return [Boolean] `true` when `unmerged_stages` is set
|
|
203
|
+
#
|
|
204
|
+
def unmerged? = !unmerged_stages.nil?
|
|
205
|
+
|
|
206
|
+
# Returns `true` when the path was renamed in the index or working tree
|
|
207
|
+
#
|
|
208
|
+
# @example Check a renamed path
|
|
209
|
+
# repo.status_info['lib/new_name.rb'].renamed? #=> true
|
|
210
|
+
#
|
|
211
|
+
# @return [Boolean] `true` when either status character is `R`
|
|
212
|
+
#
|
|
213
|
+
def renamed? = index_status == 'R' || worktree_status == 'R'
|
|
214
|
+
|
|
215
|
+
# Returns `true` when the path was added to the index and is not in HEAD
|
|
216
|
+
#
|
|
217
|
+
# @example Check a newly staged path
|
|
218
|
+
# repo.status_info['lib/new.rb'].added? #=> true
|
|
219
|
+
#
|
|
220
|
+
# @return [Boolean] `true` when `index_status` is `A`
|
|
221
|
+
#
|
|
222
|
+
def added? = index_status == 'A'
|
|
223
|
+
|
|
224
|
+
# Returns `true` when the path was deleted from the index or working tree
|
|
225
|
+
#
|
|
226
|
+
# @example Check a deleted path
|
|
227
|
+
# repo.status_info['lib/old.rb'].deleted? #=> true
|
|
228
|
+
#
|
|
229
|
+
# @return [Boolean] `true` when either status character is `D`
|
|
230
|
+
#
|
|
231
|
+
def deleted? = index_status == 'D' || worktree_status == 'D'
|
|
232
|
+
|
|
233
|
+
# Returns `true` when the path's content or type changed in the index or working tree
|
|
234
|
+
#
|
|
235
|
+
# @example Check a modified path
|
|
236
|
+
# repo.status_info['lib/foo.rb'].changed? #=> true
|
|
237
|
+
#
|
|
238
|
+
# @return [Boolean] `true` when either status character is `M` or `T`
|
|
239
|
+
#
|
|
240
|
+
def changed? = [index_status, worktree_status].intersect?(%w[M T])
|
|
241
|
+
|
|
242
|
+
private
|
|
243
|
+
|
|
244
|
+
# Returns a frozen copy of `value`, freezing the contents of a Hash recursively
|
|
245
|
+
#
|
|
246
|
+
# @param value [Object] a member value
|
|
247
|
+
#
|
|
248
|
+
# @return [Object] a frozen copy of a String or Hash; any other value as given
|
|
249
|
+
#
|
|
250
|
+
def deep_frozen(value)
|
|
251
|
+
case value
|
|
252
|
+
when String then value.dup.freeze
|
|
253
|
+
when Hash then value.to_h { |key, item| [key, deep_frozen(item)] }.freeze
|
|
254
|
+
else value
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/status_file_info'
|
|
4
|
+
|
|
5
|
+
module Git
|
|
6
|
+
# Immutable value object for the status of a repository's index and working tree
|
|
7
|
+
#
|
|
8
|
+
# Holds one {Git::StatusFileInfo} per path that `git status` reports, in the
|
|
9
|
+
# order git listed them, together with the repository's `core.ignoreCase`
|
|
10
|
+
# setting. The derived readers (`changed`, `added`, `deleted`, `untracked`,
|
|
11
|
+
# `unmerged`) return the matching files keyed by path and are computed on each
|
|
12
|
+
# call. The path predicates (`changed?`, `added?`, `deleted?`, `untracked?`)
|
|
13
|
+
# compare paths case-insensitively when `ignore_case` is `true`.
|
|
14
|
+
#
|
|
15
|
+
# @example Inspect repository status
|
|
16
|
+
# status = repo.status_info
|
|
17
|
+
# status.changed.each_key { |path| puts "Modified: #{path}" }
|
|
18
|
+
# status.added.each_key { |path| puts "Added: #{path}" }
|
|
19
|
+
# status.deleted.each_key { |path| puts "Deleted: #{path}" }
|
|
20
|
+
# status.untracked.each_key { |path| puts "Untracked: #{path}" }
|
|
21
|
+
#
|
|
22
|
+
# @example Check one path
|
|
23
|
+
# status = repo.status_info
|
|
24
|
+
# status.changed?('lib/foo.rb') #=> true
|
|
25
|
+
# status['lib/foo.rb'].worktree_status #=> "M"
|
|
26
|
+
#
|
|
27
|
+
# @see Git::StatusFileInfo
|
|
28
|
+
#
|
|
29
|
+
# @see Git::Repository#status_info
|
|
30
|
+
#
|
|
31
|
+
# @api public
|
|
32
|
+
#
|
|
33
|
+
# @!attribute [r] files
|
|
34
|
+
#
|
|
35
|
+
# @return [Array<Git::StatusFileInfo>] every reported path in git's output
|
|
36
|
+
# order; the array is frozen
|
|
37
|
+
#
|
|
38
|
+
# @!attribute [r] ignore_case
|
|
39
|
+
#
|
|
40
|
+
# @return [Boolean] `true` when the repository's `core.ignoreCase` is true,
|
|
41
|
+
# making the path predicates compare paths case-insensitively
|
|
42
|
+
#
|
|
43
|
+
StatusInfo = Data.define(:files, :ignore_case) do
|
|
44
|
+
# Creates a status value object holding a frozen copy of the given files
|
|
45
|
+
#
|
|
46
|
+
# @example Build a status from parsed files
|
|
47
|
+
# Git::StatusInfo.new(files: files, ignore_case: false)
|
|
48
|
+
#
|
|
49
|
+
# @param files [Array<Git::StatusFileInfo>] the reported paths in git's
|
|
50
|
+
# output order
|
|
51
|
+
#
|
|
52
|
+
# @param ignore_case [Boolean] whether path predicates ignore case
|
|
53
|
+
#
|
|
54
|
+
def initialize(files:, ignore_case:)
|
|
55
|
+
super(files: files.dup.freeze, ignore_case: ignore_case)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Returns the files modified or type-changed in the index or working tree
|
|
59
|
+
#
|
|
60
|
+
# @example List modified paths
|
|
61
|
+
# repo.status_info.changed.keys #=> ["lib/foo.rb"]
|
|
62
|
+
#
|
|
63
|
+
# @return [Hash{String => Git::StatusFileInfo}] changed files keyed by path
|
|
64
|
+
#
|
|
65
|
+
def changed = files_by_path(&:changed?)
|
|
66
|
+
|
|
67
|
+
# Returns the files added to the index that are not in HEAD
|
|
68
|
+
#
|
|
69
|
+
# @example List added paths
|
|
70
|
+
# repo.status_info.added.keys #=> ["lib/new.rb"]
|
|
71
|
+
#
|
|
72
|
+
# @return [Hash{String => Git::StatusFileInfo}] added files keyed by path
|
|
73
|
+
#
|
|
74
|
+
def added = files_by_path(&:added?)
|
|
75
|
+
|
|
76
|
+
# Returns the files deleted from the index or working tree
|
|
77
|
+
#
|
|
78
|
+
# @example List deleted paths
|
|
79
|
+
# repo.status_info.deleted.keys #=> ["lib/old.rb"]
|
|
80
|
+
#
|
|
81
|
+
# @return [Hash{String => Git::StatusFileInfo}] deleted files keyed by path
|
|
82
|
+
#
|
|
83
|
+
def deleted = files_by_path(&:deleted?)
|
|
84
|
+
|
|
85
|
+
# Returns the files in the working tree that git does not track
|
|
86
|
+
#
|
|
87
|
+
# @example List untracked paths
|
|
88
|
+
# repo.status_info.untracked.keys #=> ["notes.txt"]
|
|
89
|
+
#
|
|
90
|
+
# @return [Hash{String => Git::StatusFileInfo}] untracked files keyed by path
|
|
91
|
+
#
|
|
92
|
+
def untracked = files_by_path(&:untracked?)
|
|
93
|
+
|
|
94
|
+
# Returns the files with merge conflicts
|
|
95
|
+
#
|
|
96
|
+
# @example List conflicted paths
|
|
97
|
+
# repo.status_info.unmerged.keys #=> ["lib/conflict.rb"]
|
|
98
|
+
#
|
|
99
|
+
# @return [Hash{String => Git::StatusFileInfo}] unmerged files keyed by path
|
|
100
|
+
#
|
|
101
|
+
def unmerged = files_by_path(&:unmerged?)
|
|
102
|
+
|
|
103
|
+
# Returns `true` if `path` is modified in the index or working tree
|
|
104
|
+
#
|
|
105
|
+
# @example Check a path
|
|
106
|
+
# repo.status_info.changed?('lib/foo.rb') #=> true
|
|
107
|
+
#
|
|
108
|
+
# @param path [String] the repository-relative path to check
|
|
109
|
+
#
|
|
110
|
+
# @return [Boolean] `true` when the path is in {#changed}
|
|
111
|
+
#
|
|
112
|
+
def changed?(path) = path_in?(changed, path)
|
|
113
|
+
|
|
114
|
+
# Returns `true` if `path` was added to the index
|
|
115
|
+
#
|
|
116
|
+
# @example Check a path
|
|
117
|
+
# repo.status_info.added?('lib/new.rb') #=> true
|
|
118
|
+
#
|
|
119
|
+
# @param path [String] the repository-relative path to check
|
|
120
|
+
#
|
|
121
|
+
# @return [Boolean] `true` when the path is in {#added}
|
|
122
|
+
#
|
|
123
|
+
def added?(path) = path_in?(added, path)
|
|
124
|
+
|
|
125
|
+
# Returns `true` if `path` was deleted from the index or working tree
|
|
126
|
+
#
|
|
127
|
+
# @example Check a path
|
|
128
|
+
# repo.status_info.deleted?('lib/old.rb') #=> true
|
|
129
|
+
#
|
|
130
|
+
# @param path [String] the repository-relative path to check
|
|
131
|
+
#
|
|
132
|
+
# @return [Boolean] `true` when the path is in {#deleted}
|
|
133
|
+
#
|
|
134
|
+
def deleted?(path) = path_in?(deleted, path)
|
|
135
|
+
|
|
136
|
+
# Returns `true` if `path` is not tracked by git
|
|
137
|
+
#
|
|
138
|
+
# @example Check a path
|
|
139
|
+
# repo.status_info.untracked?('notes.txt') #=> true
|
|
140
|
+
#
|
|
141
|
+
# @param path [String] the repository-relative path to check
|
|
142
|
+
#
|
|
143
|
+
# @return [Boolean] `true` when the path is in {#untracked}
|
|
144
|
+
#
|
|
145
|
+
def untracked?(path) = path_in?(untracked, path)
|
|
146
|
+
|
|
147
|
+
# Returns the {Git::StatusFileInfo} for the given path
|
|
148
|
+
#
|
|
149
|
+
# The path is matched exactly, regardless of `ignore_case`.
|
|
150
|
+
#
|
|
151
|
+
# @example Look up a path
|
|
152
|
+
# repo.status_info['lib/foo.rb'] #=> #<data Git::StatusFileInfo path="lib/foo.rb", ...>
|
|
153
|
+
# repo.status_info['clean.rb'] #=> nil
|
|
154
|
+
#
|
|
155
|
+
# @param path [String] the repository-relative path
|
|
156
|
+
#
|
|
157
|
+
# @return [Git::StatusFileInfo, nil] the file, or `nil` when git did not report it
|
|
158
|
+
#
|
|
159
|
+
def [](path) = files.find { |file| file.path == path }
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
# Returns the files for which the block is truthy, keyed by path
|
|
164
|
+
#
|
|
165
|
+
# @return [Hash{String => Git::StatusFileInfo}] the selected files keyed by path
|
|
166
|
+
#
|
|
167
|
+
# @yield [file] each {Git::StatusFileInfo} in `files`
|
|
168
|
+
#
|
|
169
|
+
# @yieldparam file [Git::StatusFileInfo] one reported path
|
|
170
|
+
#
|
|
171
|
+
# @yieldreturn [Boolean] truthy to include the file
|
|
172
|
+
#
|
|
173
|
+
def files_by_path(&) = files.select(&).to_h { |file| [file.path, file] }
|
|
174
|
+
|
|
175
|
+
# Returns `true` when `path` is a key of `collection`, honoring `ignore_case`
|
|
176
|
+
#
|
|
177
|
+
# @param collection [Hash{String => Git::StatusFileInfo}] files keyed by path
|
|
178
|
+
#
|
|
179
|
+
# @param path [String] the repository-relative path to look for
|
|
180
|
+
#
|
|
181
|
+
# @return [Boolean] `true` when the path is present
|
|
182
|
+
#
|
|
183
|
+
def path_in?(collection, path)
|
|
184
|
+
return collection.key?(path) unless ignore_case
|
|
185
|
+
|
|
186
|
+
collection.each_key.any? { |key| key.casecmp?(path) }
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
# Represents a tag that failed to be deleted
|
|
5
|
+
#
|
|
6
|
+
# This is an immutable data object returned as part of {Git::TagDeleteResult}
|
|
7
|
+
# when one or more tags could not be deleted.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# failure = Git::TagDeleteFailure.new(
|
|
11
|
+
# name: 'nonexistent',
|
|
12
|
+
# error_message: "tag 'nonexistent' not found."
|
|
13
|
+
# )
|
|
14
|
+
# failure.name #=> 'nonexistent'
|
|
15
|
+
# failure.error_message #=> "tag 'nonexistent' not found."
|
|
16
|
+
#
|
|
17
|
+
# @see Git::TagDeleteResult
|
|
18
|
+
#
|
|
19
|
+
# @see Git::Commands::Tag::Delete
|
|
20
|
+
#
|
|
21
|
+
# @api public
|
|
22
|
+
#
|
|
23
|
+
# @!attribute [r] name
|
|
24
|
+
# The name of the tag that failed to be deleted
|
|
25
|
+
#
|
|
26
|
+
# @return [String]
|
|
27
|
+
#
|
|
28
|
+
# @!attribute [r] error_message
|
|
29
|
+
# The error message from git explaining why the tag could not be deleted
|
|
30
|
+
#
|
|
31
|
+
# @return [String]
|
|
32
|
+
#
|
|
33
|
+
TagDeleteFailure = Data.define(:name, :error_message)
|
|
34
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/tag_info'
|
|
4
|
+
require 'git/tag_delete_failure'
|
|
5
|
+
|
|
6
|
+
module Git
|
|
7
|
+
# Represents the result of a tag delete operation
|
|
8
|
+
#
|
|
9
|
+
# This is an immutable data object returned by {Git::Commands::Tag::Delete#call}.
|
|
10
|
+
# It contains information about which tags were successfully deleted and which
|
|
11
|
+
# failed to be deleted, along with the reason for each failure.
|
|
12
|
+
#
|
|
13
|
+
# Git's `git tag -d` command uses "best effort" semantics - it deletes as many
|
|
14
|
+
# tags as possible and reports errors for those that couldn't be deleted. This
|
|
15
|
+
# result object reflects that behavior, allowing callers to inspect both
|
|
16
|
+
# successes and failures.
|
|
17
|
+
#
|
|
18
|
+
# @example Successful deletion of all tags
|
|
19
|
+
# result = tag_delete.call('v1.0.0', 'v2.0.0')
|
|
20
|
+
# result.success? #=> true
|
|
21
|
+
# result.deleted.map(&:name) #=> ['v1.0.0', 'v2.0.0']
|
|
22
|
+
# result.not_deleted #=> []
|
|
23
|
+
#
|
|
24
|
+
# @example Partial failure (some tags deleted, some not found)
|
|
25
|
+
# result = tag_delete.call('v1.0.0', 'nonexistent', 'v2.0.0')
|
|
26
|
+
# result.success? #=> false
|
|
27
|
+
# result.deleted.map(&:name) #=> ['v1.0.0', 'v2.0.0']
|
|
28
|
+
# result.not_deleted.first.name #=> 'nonexistent'
|
|
29
|
+
# result.not_deleted.first.error_message #=> "tag 'nonexistent' not found."
|
|
30
|
+
#
|
|
31
|
+
# @see Git::TagInfo
|
|
32
|
+
#
|
|
33
|
+
# @see Git::TagDeleteFailure
|
|
34
|
+
#
|
|
35
|
+
# @see Git::Commands::Tag::Delete
|
|
36
|
+
#
|
|
37
|
+
# @api public
|
|
38
|
+
#
|
|
39
|
+
# @!attribute [r] deleted
|
|
40
|
+
# Tags that were successfully deleted
|
|
41
|
+
#
|
|
42
|
+
# @return [Array<Git::TagInfo>]
|
|
43
|
+
#
|
|
44
|
+
# @!attribute [r] not_deleted
|
|
45
|
+
# Tags that could not be deleted, with the reason for each failure
|
|
46
|
+
#
|
|
47
|
+
# @return [Array<Git::TagDeleteFailure>]
|
|
48
|
+
#
|
|
49
|
+
TagDeleteResult = Data.define(:deleted, :not_deleted) do
|
|
50
|
+
# Returns true if all requested tags were successfully deleted
|
|
51
|
+
#
|
|
52
|
+
# @example Check if the delete operation succeeded
|
|
53
|
+
# result = tag_delete.call('v1.0.0')
|
|
54
|
+
# if result.success?
|
|
55
|
+
# puts "All tags deleted successfully"
|
|
56
|
+
# else
|
|
57
|
+
# puts "Some tags could not be deleted:"
|
|
58
|
+
# result.not_deleted.each { |f| puts " #{f.name}: #{f.error_message}" }
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
# @return [Boolean] true if no tags failed to delete, false otherwise
|
|
62
|
+
def success?
|
|
63
|
+
not_deleted.empty?
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
data/lib/git/tag_info.rb
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
require 'git/author_info'
|
|
6
|
+
|
|
7
|
+
module Git
|
|
8
|
+
# Value object representing tag metadata from git tag output
|
|
9
|
+
#
|
|
10
|
+
# This is a lightweight, immutable data structure returned by tag listing
|
|
11
|
+
# commands. It contains only the data parsed from git output without any
|
|
12
|
+
# repository context or operations.
|
|
13
|
+
#
|
|
14
|
+
# The tagger identity is a nested {Git::AuthorInfo}. Its `date` is a `Time`
|
|
15
|
+
# parsed from git's strict ISO 8601 output, not an ISO 8601 string.
|
|
16
|
+
#
|
|
17
|
+
# @example Annotated tag
|
|
18
|
+
# info = Git::TagInfo.new(
|
|
19
|
+
# name: 'v1.0.0',
|
|
20
|
+
# oid: 'abc123def456', # tag object's ID
|
|
21
|
+
# target_oid: 'def456abc789', # commit it points to
|
|
22
|
+
# objecttype: 'tag',
|
|
23
|
+
# tagger: Git::AuthorInfo.new(
|
|
24
|
+
# name: 'John Doe',
|
|
25
|
+
# email: 'john@example.com',
|
|
26
|
+
# date: Time.iso8601('2024-01-15T10:30:00-08:00')
|
|
27
|
+
# ),
|
|
28
|
+
# message: 'Release version 1.0.0'
|
|
29
|
+
# )
|
|
30
|
+
# info.annotated? #=> true
|
|
31
|
+
# info.tagger.name #=> 'John Doe'
|
|
32
|
+
# info.tagger.date #=> 2024-01-15 10:30:00 -0800
|
|
33
|
+
#
|
|
34
|
+
# @example Lightweight tag
|
|
35
|
+
# info = Git::TagInfo.new(
|
|
36
|
+
# name: 'v1.0.0',
|
|
37
|
+
# oid: nil, # no tag object exists
|
|
38
|
+
# target_oid: 'def456abc789', # commit ID
|
|
39
|
+
# objecttype: 'commit',
|
|
40
|
+
# tagger: nil,
|
|
41
|
+
# message: nil
|
|
42
|
+
# )
|
|
43
|
+
# info.lightweight? #=> true
|
|
44
|
+
# info.tagger #=> nil
|
|
45
|
+
#
|
|
46
|
+
# @see Git::Repository::ObjectOperations#tag_list for the repository method
|
|
47
|
+
# that returns these
|
|
48
|
+
#
|
|
49
|
+
# @see Git::Commands::Tag::List for the command that produces these
|
|
50
|
+
#
|
|
51
|
+
# @see Git::AuthorInfo for the nested tagger identity
|
|
52
|
+
#
|
|
53
|
+
# @api public
|
|
54
|
+
#
|
|
55
|
+
# @!attribute [r] name
|
|
56
|
+
# @return [String] the tag name (e.g., 'v1.0.0')
|
|
57
|
+
#
|
|
58
|
+
# @!attribute [r] oid
|
|
59
|
+
# The object ID of the tag object itself.
|
|
60
|
+
#
|
|
61
|
+
# For annotated tags, this is the tag object's ID. For lightweight tags,
|
|
62
|
+
# this is nil because lightweight tags are not objects in the git database.
|
|
63
|
+
#
|
|
64
|
+
# @return [String, nil] the tag object's ID, or nil for lightweight tags
|
|
65
|
+
#
|
|
66
|
+
# @!attribute [r] target_oid
|
|
67
|
+
# The object ID of the commit this tag ultimately points to.
|
|
68
|
+
#
|
|
69
|
+
# For both annotated and lightweight tags, this is the commit ID that the
|
|
70
|
+
# tag resolves to (i.e., the dereferenced target).
|
|
71
|
+
#
|
|
72
|
+
# @return [String] the commit ID this tag points to
|
|
73
|
+
#
|
|
74
|
+
# @!attribute [r] objecttype
|
|
75
|
+
# @return [String] 'tag' for annotated tags, 'commit' for lightweight tags
|
|
76
|
+
#
|
|
77
|
+
# @!attribute [r] tagger
|
|
78
|
+
# The identity of the person who created the tag object.
|
|
79
|
+
#
|
|
80
|
+
# Lightweight tags have no tag object and therefore no tagger. The nested
|
|
81
|
+
# `email` has no angle brackets and the nested `date` is a `Time`.
|
|
82
|
+
#
|
|
83
|
+
# @return [Git::AuthorInfo, nil] the tagger, or nil for lightweight tags
|
|
84
|
+
#
|
|
85
|
+
# @!attribute [r] message
|
|
86
|
+
# @return [String, nil] the tag message, or nil for lightweight tags
|
|
87
|
+
#
|
|
88
|
+
TagInfo = Data.define(:name, :oid, :target_oid, :objecttype, :tagger, :message) do
|
|
89
|
+
# @return [Boolean] true if this is an annotated tag (oid is present)
|
|
90
|
+
def annotated?
|
|
91
|
+
!oid.nil?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @return [Boolean] true if this is a lightweight tag (oid is nil)
|
|
95
|
+
def lightweight?
|
|
96
|
+
oid.nil?
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|