git 5.1.0 → 5.3.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/CHANGELOG.md +78 -0
- data/CONTRIBUTING.md +202 -169
- data/LICENSE +1 -1
- data/README.md +192 -151
- data/UPGRADING.md +287 -1
- data/git.gemspec +35 -3
- data/lib/git/author.rb +11 -0
- data/lib/git/author_info.rb +66 -0
- data/lib/git/branch.rb +210 -15
- data/lib/git/branch_info.rb +1 -1
- data/lib/git/branches.rb +35 -7
- data/lib/git/command_line/base.rb +1 -2
- data/lib/git/commands/base.rb +1 -1
- data/lib/git/commands/cat_file/raw.rb +62 -7
- data/lib/git/object.rb +13 -7
- data/lib/git/parsers/stash.rb +50 -17
- data/lib/git/parsers/tag.rb +54 -8
- data/lib/git/remote.rb +37 -7
- data/lib/git/remote_info.rb +67 -10
- data/lib/git/repository/branching.rb +190 -6
- data/lib/git/repository/merging.rb +96 -2
- data/lib/git/repository/remote_operations.rb +57 -0
- data/lib/git/repository/shared_private.rb +67 -0
- data/lib/git/stash_info.rb +32 -34
- data/lib/git/tag_info.rb +21 -29
- data/lib/git/version.rb +1 -1
- data/lib/git.rb +1 -0
- metadata +6 -94
- data/.claude/commands/address-copilot-reviews.md +0 -14
- data/.claude/settings.json +0 -16
- data/.claude/skills +0 -1
- data/.commitlintrc.yml +0 -38
- data/.dockerignore +0 -27
- data/.github/copilot-instructions.md +0 -30
- data/.github/hooks/bin-setup-on-worktree.json +0 -11
- data/.github/hooks/run-bin-setup-once.sh +0 -20
- data/.github/issue_template.md +0 -15
- data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +0 -188
- data/.github/pull_request_template.md +0 -21
- data/.github/skills/breaking-change-analysis/SKILL.md +0 -99
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +0 -264
- data/.github/skills/command-implementation/REFERENCE.md +0 -994
- data/.github/skills/command-implementation/SKILL.md +0 -230
- data/.github/skills/command-test-conventions/SKILL.md +0 -664
- data/.github/skills/command-yard-documentation/SKILL.md +0 -434
- data/.github/skills/dependency-management/SKILL.md +0 -72
- data/.github/skills/development-workflow/SKILL.md +0 -512
- data/.github/skills/facade-implementation/REFERENCE.md +0 -837
- data/.github/skills/facade-implementation/SKILL.md +0 -269
- data/.github/skills/facade-test-conventions/SKILL.md +0 -391
- data/.github/skills/facade-yard-documentation/SKILL.md +0 -435
- data/.github/skills/make-skill-template/SKILL.md +0 -226
- data/.github/skills/pr-readiness-review/SKILL.md +0 -205
- data/.github/skills/project-context/SKILL.md +0 -306
- data/.github/skills/pull-request-review/SKILL.md +0 -168
- data/.github/skills/rebase/SKILL.md +0 -148
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +0 -131
- data/.github/skills/release-management/SKILL.md +0 -125
- data/.github/skills/resolve-feedback/SKILL.md +0 -288
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +0 -788
- data/.github/skills/review-arguments-dsl/SKILL.md +0 -214
- data/.github/skills/review-cross-command-consistency/SKILL.md +0 -139
- data/.github/skills/reviewing-skills/SKILL.md +0 -214
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +0 -685
- data/.github/skills/tdd-refactor-step/SKILL.md +0 -236
- data/.github/skills/test-debugging/SKILL.md +0 -161
- data/.github/skills/yard-documentation/SKILL.md +0 -981
- data/.github/skills/yard-documentation/element-rules.md +0 -162
- data/.github/skills-deprecated/README.md +0 -21
- data/.github/skills-deprecated/extract-command-from-lib/SKILL.md +0 -487
- data/.github/skills-deprecated/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +0 -22
- data/.github/skills-deprecated/extract-facade-from-base-lib/SKILL.md +0 -600
- data/.github/skills-deprecated/review-backward-compatibility/SKILL.md +0 -275
- data/.github/workflows/continuous_integration.yml +0 -358
- data/.github/workflows/enforce_conventional_commits.yml +0 -35
- data/.github/workflows/experimental_continuous_integration.yml +0 -59
- data/.github/workflows/release.yml +0 -52
- data/.github/workflows/warm_bundler_caches.yml +0 -82
- data/.gitignore +0 -30
- data/.husky/commit-msg +0 -1
- data/.husky/pre-commit +0 -13
- data/.release-please-config.json +0 -36
- data/.release-please-manifest.json +0 -3
- data/.rspec +0 -2
- data/.rubocop.yml +0 -44
- data/.rubocop_todo.yml +0 -30
- data/.yard-lint.yml +0 -75
- data/CLAUDE.md +0 -11
- data/Gemfile +0 -22
- data/Rakefile +0 -41
- data/docker/test/Dockerfile +0 -32
- data/docker/test/docker-compose.yml +0 -0
- data/package.json +0 -10
- data/redesign/1_architecture_existing.md +0 -102
- data/redesign/2_architecture_redesign.md +0 -449
- data/redesign/3_architecture_implementation.md +0 -1623
- data/redesign/Phase 4 - Step A.md +0 -366
- data/redesign/Phase 4 - Step B.md +0 -921
- data/redesign/Phase 4 - Step C.md +0 -833
- data/redesign/beta_release.md +0 -107
- data/redesign/branch_parse_refactor_plan.md +0 -163
- data/redesign/c1a-public-api-scope.tsv +0 -256
- data/redesign/c1c2_audit.md +0 -566
- data/redesign/c1c2_bucket6_lib_orphans.md +0 -626
- data/redesign/config_design.rb +0 -501
- data/redesign/index.md +0 -34
- data/redesign/info_object_migration_plan.md +0 -126
- data/redesign/integration_test_analysis.md +0 -521
- data/redesign/phase-4-step-b-test-audit.tsv +0 -485
- data/redesign/remote_refactor_plan.md +0 -164
- data/redesign/reverse_dependencies.sql +0 -44
- data/tasks/gem_tasks.rake +0 -14
- data/tasks/npm_tasks.rake +0 -7
- data/tasks/rspec.rake +0 -111
- data/tasks/rubocop.rake +0 -5
- data/tasks/test_gem.rake +0 -12
- data/tasks/yard.rake +0 -57
|
@@ -10,8 +10,8 @@ require 'git/repository/shared_private'
|
|
|
10
10
|
|
|
11
11
|
module Git
|
|
12
12
|
class Repository
|
|
13
|
-
# Facade methods for merge operations: merging branches into the current branch
|
|
14
|
-
# and finding common ancestors between commits
|
|
13
|
+
# Facade methods for merge operations: merging branches into the current branch
|
|
14
|
+
# or into another branch, and finding common ancestors between commits
|
|
15
15
|
#
|
|
16
16
|
# Included by {Git::Repository}.
|
|
17
17
|
#
|
|
@@ -97,6 +97,100 @@ module Git
|
|
|
97
97
|
Git::Commands::Merge::Start.new(@execution_context).call(*branches, no_edit: true, **opts).stdout
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
+
# Option keys accepted by {#merge_into}
|
|
101
|
+
#
|
|
102
|
+
# The keys accepted by {#merge} except `:no_commit`. A merge stopped before
|
|
103
|
+
# its commit leaves `target_branch` unchanged, and the restore checkout would
|
|
104
|
+
# carry the staged merge result onto the original branch instead.
|
|
105
|
+
MERGE_INTO_ALLOWED_OPTS = %i[no_ff m message].freeze
|
|
106
|
+
private_constant :MERGE_INTO_ALLOWED_OPTS
|
|
107
|
+
|
|
108
|
+
# Merge one or more branches into another branch without leaving the current branch
|
|
109
|
+
#
|
|
110
|
+
# Records the current branch (or the current commit when HEAD is detached),
|
|
111
|
+
# checks out `target_branch`, merges `branch` into it with {#merge}, then
|
|
112
|
+
# checks out the original branch or commit again. Use {#merge} directly when
|
|
113
|
+
# the target is the currently checked-out branch.
|
|
114
|
+
#
|
|
115
|
+
# `target_branch` must be an existing local branch. Unlike {#checkout}, a
|
|
116
|
+
# commit SHA, tag, or remote-tracking branch is rejected before any checkout
|
|
117
|
+
# happens: those detach HEAD, and the merge commit made there would be left
|
|
118
|
+
# dangling once the original branch is restored while the named ref stayed
|
|
119
|
+
# unchanged.
|
|
120
|
+
#
|
|
121
|
+
# HEAD must be on a branch with at least one commit, or detached: an unborn
|
|
122
|
+
# branch (no commits yet) cannot be checked out again by name, so it is
|
|
123
|
+
# rejected before any checkout happens.
|
|
124
|
+
#
|
|
125
|
+
# Option keys, the source list, and `target_branch` are checked before any
|
|
126
|
+
# branch is checked out, so those failures never leave the repository on
|
|
127
|
+
# `target_branch`. Anything rejected later, such as an option value that is
|
|
128
|
+
# not accepted or a source ref that does not exist, surfaces inside {#merge}
|
|
129
|
+
# after the checkout and follows the Note below.
|
|
130
|
+
#
|
|
131
|
+
# The `:no_commit` option is not accepted: a merge stopped before its commit
|
|
132
|
+
# would leave `target_branch` unchanged and the restore checkout would carry
|
|
133
|
+
# the staged result onto the original branch. To merge without committing,
|
|
134
|
+
# call {#checkout} and {#merge} directly.
|
|
135
|
+
#
|
|
136
|
+
# **Note:** the restore checkout is not wrapped in `ensure`. If the merge
|
|
137
|
+
# fails (for example, on a conflict), the repository is left checked out on
|
|
138
|
+
# `target_branch` with the merge in progress rather than restored to the
|
|
139
|
+
# original branch.
|
|
140
|
+
#
|
|
141
|
+
# @example Merge a feature branch into main while staying on the current branch
|
|
142
|
+
# repo.merge_into('main', 'feature')
|
|
143
|
+
#
|
|
144
|
+
# @example Merge with a no-fast-forward commit message
|
|
145
|
+
# repo.merge_into('main', 'feature', 'Merge feature into main', no_ff: true)
|
|
146
|
+
#
|
|
147
|
+
# @example Octopus merge of multiple branches into main
|
|
148
|
+
# repo.merge_into('main', %w[feature-a feature-b])
|
|
149
|
+
#
|
|
150
|
+
# @param target_branch [String] the name of an existing local branch to
|
|
151
|
+
# merge into
|
|
152
|
+
#
|
|
153
|
+
# @param branch [#to_s, Array<#to_s>] the branch or branches to merge into
|
|
154
|
+
# `target_branch`; accepts the same forms as {#merge}, but must name at
|
|
155
|
+
# least one branch
|
|
156
|
+
#
|
|
157
|
+
# @param message [String, nil] optional commit message for the merge commit;
|
|
158
|
+
# see {#merge} for how it interacts with the `:message` and `:m` options
|
|
159
|
+
#
|
|
160
|
+
# @param opts [Hash] additional options forwarded to {#merge}
|
|
161
|
+
#
|
|
162
|
+
# @option opts [Boolean, nil] :no_ff (nil) create a merge commit even when
|
|
163
|
+
# fast-forward is possible (`--no-ff`)
|
|
164
|
+
#
|
|
165
|
+
# @option opts [String] :message (nil) commit message; prefer the `:m` option
|
|
166
|
+
#
|
|
167
|
+
# @option opts [String] :m (nil) commit message (`-m` flag)
|
|
168
|
+
#
|
|
169
|
+
# @return [String] git's stdout from the merge command
|
|
170
|
+
#
|
|
171
|
+
# @raise [ArgumentError] when unsupported options (including `:no_commit`)
|
|
172
|
+
# are provided
|
|
173
|
+
#
|
|
174
|
+
# @raise [ArgumentError] when `branch` is `nil` or an empty Array
|
|
175
|
+
#
|
|
176
|
+
# @raise [ArgumentError] when `target_branch` is not an existing local branch
|
|
177
|
+
#
|
|
178
|
+
# @raise [Git::Error] when HEAD is on an unborn branch
|
|
179
|
+
#
|
|
180
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
181
|
+
#
|
|
182
|
+
def merge_into(target_branch, branch, message = nil, opts = {})
|
|
183
|
+
SharedPrivate.assert_valid_opts!(MERGE_INTO_ALLOWED_OPTS, **opts)
|
|
184
|
+
raise ArgumentError, 'at least one branch to merge is required' if Array(branch).empty?
|
|
185
|
+
|
|
186
|
+
SharedPrivate.assert_local_branch!(self, target_branch)
|
|
187
|
+
restore_point = SharedPrivate.head_restore_point(self)
|
|
188
|
+
checkout(target_branch)
|
|
189
|
+
output = merge(branch, message, opts)
|
|
190
|
+
checkout(restore_point)
|
|
191
|
+
output
|
|
192
|
+
end
|
|
193
|
+
|
|
100
194
|
# Find common ancestor commit(s) for use in a merge
|
|
101
195
|
#
|
|
102
196
|
# @example Find the common ancestor of two branches
|
|
@@ -525,7 +525,37 @@ module Git
|
|
|
525
525
|
#
|
|
526
526
|
# @raise [Git::FailedError] when git exits with a non-zero status
|
|
527
527
|
#
|
|
528
|
+
# @deprecated Use `remote_list.find { |r| r.name == name }` for the fields
|
|
529
|
+
# {Git::RemoteInfo} models, or filter {Git::Configuring#config_list} on
|
|
530
|
+
# the `remote.<name>.` key prefix to keep every entry
|
|
531
|
+
#
|
|
532
|
+
# {#remote_list} returns a {Git::RemoteInfo} per remote. Its `url` and
|
|
533
|
+
# `fetch` members hold every configured value as `Array<String>`,
|
|
534
|
+
# whereas this method returns a flat hash in which a repeated `url` or
|
|
535
|
+
# `fetch` key overwrites the earlier value.
|
|
536
|
+
#
|
|
537
|
+
# {Git::RemoteInfo} models only the remote variables git defines and
|
|
538
|
+
# drops any other `remote.<name>.*` entry, whereas this method returns
|
|
539
|
+
# every entry. Callers that read custom keys should filter
|
|
540
|
+
# {Git::Configuring#config_list} instead, which returns the same hash
|
|
541
|
+
# (shown here for the `origin` remote):
|
|
542
|
+
#
|
|
543
|
+
# prefix = 'remote.origin.'
|
|
544
|
+
# repo.config_list
|
|
545
|
+
# .select { |entry| entry.key.start_with?(prefix) }
|
|
546
|
+
# .to_h { |entry| [entry.key.delete_prefix(prefix), entry.value] }
|
|
547
|
+
#
|
|
548
|
+
# @see #remote_list
|
|
549
|
+
#
|
|
550
|
+
# @see Git::Configuring#config_list
|
|
551
|
+
#
|
|
528
552
|
def config_remote(name)
|
|
553
|
+
Git::Deprecation.warn(
|
|
554
|
+
'Git::Repository#config_remote is deprecated and will be removed in v6.0.0. ' \
|
|
555
|
+
'Use Git::Repository#remote_list.find { |r| r.name == name } for the fields ' \
|
|
556
|
+
'Git::RemoteInfo models, or filter Git::Repository#config_list on the ' \
|
|
557
|
+
'"remote.<name>." key prefix to keep every entry.'
|
|
558
|
+
)
|
|
529
559
|
prefix = "remote.#{name}."
|
|
530
560
|
Private.config_list(@execution_context).each_with_object({}) do |(key, value), hsh|
|
|
531
561
|
hsh[key.delete_prefix(prefix)] = value if key.start_with?(prefix)
|
|
@@ -574,7 +604,19 @@ module Git
|
|
|
574
604
|
#
|
|
575
605
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
576
606
|
#
|
|
607
|
+
# @deprecated Use `remote_list.find { |r| r.name == name }` instead
|
|
608
|
+
#
|
|
609
|
+
# {#remote_list} returns immutable {Git::RemoteInfo} value objects
|
|
610
|
+
# rather than {Git::Remote}. Call the corresponding {Git::Repository}
|
|
611
|
+
# method (e.g. {#fetch}, {#remote_remove}) for operations on a remote.
|
|
612
|
+
#
|
|
613
|
+
# @see #remote_list
|
|
614
|
+
#
|
|
577
615
|
def remote(name = 'origin')
|
|
616
|
+
Git::Deprecation.warn(
|
|
617
|
+
'Git::Repository#remote is deprecated and will be removed in v6.0.0. ' \
|
|
618
|
+
'Use Git::Repository#remote_list.find { |r| r.name == name } instead.'
|
|
619
|
+
)
|
|
578
620
|
Git::Remote.new(self, name)
|
|
579
621
|
end
|
|
580
622
|
|
|
@@ -589,7 +631,22 @@ module Git
|
|
|
589
631
|
#
|
|
590
632
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
591
633
|
#
|
|
634
|
+
# @deprecated Use {#remote_list} instead
|
|
635
|
+
#
|
|
636
|
+
# {#remote_list} returns `Array<Git::RemoteInfo>` (immutable value
|
|
637
|
+
# objects) rather than `Array<Git::Remote>`. Call the corresponding
|
|
638
|
+
# {Git::Repository} method (e.g. {#fetch}, {#remote_remove}) for
|
|
639
|
+
# operations on a remote. Each {Git::Remote} this method constructs
|
|
640
|
+
# emits its own deprecation warning, so a call produces one warning
|
|
641
|
+
# for this method plus one per remote returned.
|
|
642
|
+
#
|
|
643
|
+
# @see #remote_list
|
|
644
|
+
#
|
|
592
645
|
def remotes
|
|
646
|
+
Git::Deprecation.warn(
|
|
647
|
+
'Git::Repository#remotes is deprecated and will be removed in v6.0.0. ' \
|
|
648
|
+
'Use Git::Repository#remote_list instead.'
|
|
649
|
+
)
|
|
593
650
|
result = Git::Commands::Remote::List.new(@execution_context).call
|
|
594
651
|
result.stdout.split("\n").map { |name| Git::Remote.new(self, name) }
|
|
595
652
|
end
|
|
@@ -46,6 +46,73 @@ module Git
|
|
|
46
46
|
|
|
47
47
|
raise ArgumentError, "Unknown options: #{unknown.join(', ')}"
|
|
48
48
|
end
|
|
49
|
+
|
|
50
|
+
# Raise unless `branch` names an existing local branch
|
|
51
|
+
#
|
|
52
|
+
# Used by facade methods that check out a branch, do work on it, and switch
|
|
53
|
+
# back. {Git::Repository#checkout} also accepts commit SHAs, tags, and
|
|
54
|
+
# remote-tracking branches, all of which detach HEAD; work committed there
|
|
55
|
+
# would be left dangling once the original branch is restored, and git has
|
|
56
|
+
# no way to report that.
|
|
57
|
+
#
|
|
58
|
+
# @example With an existing local branch
|
|
59
|
+
# SharedPrivate.assert_local_branch!(repo, 'feature') #=> nil
|
|
60
|
+
#
|
|
61
|
+
# @example With a tag
|
|
62
|
+
# SharedPrivate.assert_local_branch!(repo, 'v1.0.0')
|
|
63
|
+
# #=> raises ArgumentError: 'v1.0.0' is not an existing local branch
|
|
64
|
+
#
|
|
65
|
+
# @param repository [Git::Repository] the repository to check
|
|
66
|
+
#
|
|
67
|
+
# @param branch [String] the branch name to verify
|
|
68
|
+
#
|
|
69
|
+
# @return [void]
|
|
70
|
+
#
|
|
71
|
+
# @raise [ArgumentError] when `branch` is not an existing local branch
|
|
72
|
+
#
|
|
73
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
74
|
+
#
|
|
75
|
+
def assert_local_branch!(repository, branch)
|
|
76
|
+
return if repository.local_branch?(branch)
|
|
77
|
+
|
|
78
|
+
raise ArgumentError, "'#{branch}' is not an existing local branch"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Returns a revision that restores the current HEAD after switching branches
|
|
82
|
+
#
|
|
83
|
+
# Used by facade methods that temporarily check out another branch and
|
|
84
|
+
# then switch back. On a branch, the branch name is enough. When HEAD is
|
|
85
|
+
# detached, {Git::Repository#current_branch} reports `'HEAD'`, which after
|
|
86
|
+
# a checkout resolves to the new branch rather than the original commit,
|
|
87
|
+
# so the commit SHA is captured instead. An unborn branch (one with no
|
|
88
|
+
# commits yet) has no ref to check out by name, so it is rejected here,
|
|
89
|
+
# before the caller switches away from it.
|
|
90
|
+
#
|
|
91
|
+
# @example On a branch
|
|
92
|
+
# SharedPrivate.head_restore_point(repo) #=> "main"
|
|
93
|
+
#
|
|
94
|
+
# @example With a detached HEAD
|
|
95
|
+
# SharedPrivate.head_restore_point(repo) #=> "9b9b31e704c0b85ffdd8d2af2ded85170a5af87d"
|
|
96
|
+
#
|
|
97
|
+
# @param repository [Git::Repository] the repository whose HEAD to record
|
|
98
|
+
#
|
|
99
|
+
# @return [String] the current branch name, or the full HEAD commit SHA
|
|
100
|
+
# when HEAD is detached
|
|
101
|
+
#
|
|
102
|
+
# @raise [Git::Error] when HEAD is on an unborn branch
|
|
103
|
+
#
|
|
104
|
+
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
105
|
+
#
|
|
106
|
+
def head_restore_point(repository)
|
|
107
|
+
head = repository.current_branch_state
|
|
108
|
+
case head.state
|
|
109
|
+
when :detached then repository.rev_parse('HEAD').strip
|
|
110
|
+
when :unborn
|
|
111
|
+
raise Git::Error, "HEAD is on the unborn branch '#{head.name}', which cannot be restored " \
|
|
112
|
+
'after switching branches; make a commit on it first'
|
|
113
|
+
else head.name
|
|
114
|
+
end
|
|
115
|
+
end
|
|
49
116
|
end
|
|
50
117
|
|
|
51
118
|
private_constant :SharedPrivate
|
data/lib/git/stash_info.rb
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
require 'git/author_info'
|
|
6
|
+
|
|
3
7
|
module Git
|
|
4
8
|
# Immutable value object representing stash entry information
|
|
5
9
|
#
|
|
6
10
|
# StashInfo encapsulates the parsed data from `git stash list` output.
|
|
7
11
|
# Each entry contains comprehensive information about the stash including
|
|
8
|
-
# its index, reference name, commit SHA, branch, message, author
|
|
9
|
-
#
|
|
12
|
+
# its index, reference name, commit SHA, branch, message, and the author and
|
|
13
|
+
# committer identities.
|
|
10
14
|
#
|
|
15
|
+
# The author and committer are nested {Git::AuthorInfo} values. Their `date`
|
|
16
|
+
# is a `Time` parsed from git's ISO 8601 output, not an ISO 8601 string.
|
|
11
17
|
#
|
|
12
18
|
# @example Create a StashInfo from parsed stash list output
|
|
13
19
|
# info = Git::StashInfo.new(
|
|
@@ -17,12 +23,16 @@ module Git
|
|
|
17
23
|
# short_oid: 'abc123d',
|
|
18
24
|
# branch: 'main',
|
|
19
25
|
# message: 'WIP on main: abc123 Initial commit',
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
+
# author: Git::AuthorInfo.new(
|
|
27
|
+
# name: 'Jane Doe',
|
|
28
|
+
# email: 'jane@example.com',
|
|
29
|
+
# date: Time.iso8601('2026-01-24T10:30:00-08:00')
|
|
30
|
+
# ),
|
|
31
|
+
# committer: Git::AuthorInfo.new(
|
|
32
|
+
# name: 'Jane Doe',
|
|
33
|
+
# email: 'jane@example.com',
|
|
34
|
+
# date: Time.iso8601('2026-01-24T10:30:00-08:00')
|
|
35
|
+
# )
|
|
26
36
|
# )
|
|
27
37
|
#
|
|
28
38
|
# info.index # => 0
|
|
@@ -31,12 +41,12 @@ module Git
|
|
|
31
41
|
# info.short_oid # => 'abc123d'
|
|
32
42
|
# info.branch # => 'main'
|
|
33
43
|
# info.message # => 'WIP on main: abc123 Initial commit'
|
|
34
|
-
# info.
|
|
35
|
-
# info.
|
|
36
|
-
# info.
|
|
37
|
-
# info.
|
|
38
|
-
#
|
|
39
|
-
#
|
|
44
|
+
# info.author.name # => 'Jane Doe'
|
|
45
|
+
# info.author.email # => 'jane@example.com'
|
|
46
|
+
# info.author.date # => 2026-01-24 10:30:00 -0800
|
|
47
|
+
# info.committer.name # => 'Jane Doe'
|
|
48
|
+
#
|
|
49
|
+
# @see Git::AuthorInfo for the nested author and committer identities
|
|
40
50
|
#
|
|
41
51
|
# @api public
|
|
42
52
|
#
|
|
@@ -59,23 +69,15 @@ module Git
|
|
|
59
69
|
# @!attribute [r] message
|
|
60
70
|
# @return [String] the stash message (e.g., 'WIP on main: abc123 commit msg')
|
|
61
71
|
#
|
|
62
|
-
# @!attribute [r]
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# @!attribute [r] author_email
|
|
66
|
-
# @return [String] the email of the stash author
|
|
67
|
-
#
|
|
68
|
-
# @!attribute [r] author_date
|
|
69
|
-
# @return [String] the author date in ISO 8601 format
|
|
72
|
+
# @!attribute [r] author
|
|
73
|
+
# The identity of the stash author; the nested `date` is a `Time`.
|
|
70
74
|
#
|
|
71
|
-
#
|
|
72
|
-
# @return [String] the name of the stash committer
|
|
75
|
+
# @return [Git::AuthorInfo] the author of the stash commit
|
|
73
76
|
#
|
|
74
|
-
# @!attribute [r]
|
|
75
|
-
#
|
|
77
|
+
# @!attribute [r] committer
|
|
78
|
+
# The identity of the stash committer; the nested `date` is a `Time`.
|
|
76
79
|
#
|
|
77
|
-
#
|
|
78
|
-
# @return [String] the committer date in ISO 8601 format
|
|
80
|
+
# @return [Git::AuthorInfo] the committer of the stash commit
|
|
79
81
|
#
|
|
80
82
|
StashInfo = Data.define(
|
|
81
83
|
:index,
|
|
@@ -84,12 +86,8 @@ module Git
|
|
|
84
86
|
:short_oid,
|
|
85
87
|
:branch,
|
|
86
88
|
:message,
|
|
87
|
-
:
|
|
88
|
-
:
|
|
89
|
-
:author_date,
|
|
90
|
-
:committer_name,
|
|
91
|
-
:committer_email,
|
|
92
|
-
:committer_date
|
|
89
|
+
:author,
|
|
90
|
+
:committer
|
|
93
91
|
) do
|
|
94
92
|
# Returns the stash reference name
|
|
95
93
|
#
|
data/lib/git/tag_info.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
require 'git/author_info'
|
|
4
6
|
|
|
5
7
|
module Git
|
|
6
8
|
# Value object representing tag metadata from git tag output
|
|
@@ -9,19 +11,25 @@ module Git
|
|
|
9
11
|
# commands. It contains only the data parsed from git output without any
|
|
10
12
|
# repository context or operations.
|
|
11
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
|
+
#
|
|
12
17
|
# @example Annotated tag
|
|
13
18
|
# info = Git::TagInfo.new(
|
|
14
19
|
# name: 'v1.0.0',
|
|
15
20
|
# oid: 'abc123def456', # tag object's ID
|
|
16
21
|
# target_oid: 'def456abc789', # commit it points to
|
|
17
22
|
# objecttype: 'tag',
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
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
|
+
# ),
|
|
21
28
|
# message: 'Release version 1.0.0'
|
|
22
29
|
# )
|
|
23
30
|
# info.annotated? #=> true
|
|
24
31
|
# info.tagger.name #=> 'John Doe'
|
|
32
|
+
# info.tagger.date #=> 2024-01-15 10:30:00 -0800
|
|
25
33
|
#
|
|
26
34
|
# @example Lightweight tag
|
|
27
35
|
# info = Git::TagInfo.new(
|
|
@@ -29,9 +37,7 @@ module Git
|
|
|
29
37
|
# oid: nil, # no tag object exists
|
|
30
38
|
# target_oid: 'def456abc789', # commit ID
|
|
31
39
|
# objecttype: 'commit',
|
|
32
|
-
#
|
|
33
|
-
# tagger_email: nil,
|
|
34
|
-
# tagger_date: nil,
|
|
40
|
+
# tagger: nil,
|
|
35
41
|
# message: nil
|
|
36
42
|
# )
|
|
37
43
|
# info.lightweight? #=> true
|
|
@@ -41,6 +47,8 @@ module Git
|
|
|
41
47
|
#
|
|
42
48
|
# @see Git::Commands::Tag::List for the command that produces these
|
|
43
49
|
#
|
|
50
|
+
# @see Git::AuthorInfo for the nested tagger identity
|
|
51
|
+
#
|
|
44
52
|
# @api public
|
|
45
53
|
#
|
|
46
54
|
# @!attribute [r] name
|
|
@@ -65,19 +73,18 @@ module Git
|
|
|
65
73
|
# @!attribute [r] objecttype
|
|
66
74
|
# @return [String] 'tag' for annotated tags, 'commit' for lightweight tags
|
|
67
75
|
#
|
|
68
|
-
# @!attribute [r]
|
|
69
|
-
#
|
|
76
|
+
# @!attribute [r] tagger
|
|
77
|
+
# The identity of the person who created the tag object.
|
|
70
78
|
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
79
|
+
# Lightweight tags have no tag object and therefore no tagger. The nested
|
|
80
|
+
# `email` has no angle brackets and the nested `date` is a `Time`.
|
|
73
81
|
#
|
|
74
|
-
#
|
|
75
|
-
# @return [String, nil] the tag date in ISO 8601 format, or nil for lightweight tags
|
|
82
|
+
# @return [Git::AuthorInfo, nil] the tagger, or nil for lightweight tags
|
|
76
83
|
#
|
|
77
84
|
# @!attribute [r] message
|
|
78
85
|
# @return [String, nil] the tag message, or nil for lightweight tags
|
|
79
86
|
#
|
|
80
|
-
TagInfo = Data.define(:name, :oid, :target_oid, :objecttype, :
|
|
87
|
+
TagInfo = Data.define(:name, :oid, :target_oid, :objecttype, :tagger, :message) do
|
|
81
88
|
# @return [Boolean] true if this is an annotated tag (oid is present)
|
|
82
89
|
def annotated?
|
|
83
90
|
!oid.nil?
|
|
@@ -87,20 +94,5 @@ module Git
|
|
|
87
94
|
def lightweight?
|
|
88
95
|
oid.nil?
|
|
89
96
|
end
|
|
90
|
-
|
|
91
|
-
# Return the tagger as an Author object
|
|
92
|
-
#
|
|
93
|
-
# @return [Git::Author, nil] the tagger as an Author object, or nil for lightweight tags
|
|
94
|
-
def tagger
|
|
95
|
-
return nil unless annotated? && tagger_name && tagger_email
|
|
96
|
-
|
|
97
|
-
# Git::Author expects format "Name <email> timestamp timezone"
|
|
98
|
-
# We construct a minimal format that will parse correctly
|
|
99
|
-
author = Git::Author.new('')
|
|
100
|
-
author.name = tagger_name
|
|
101
|
-
# Remove angle brackets if present
|
|
102
|
-
author.email = tagger_email.gsub(/\A<|>\z/, '')
|
|
103
|
-
author
|
|
104
|
-
end
|
|
105
97
|
end
|
|
106
98
|
end
|
data/lib/git/version.rb
CHANGED
data/lib/git.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: git
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Scott Chacon and others
|
|
@@ -43,14 +43,14 @@ dependencies:
|
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '4.
|
|
46
|
+
version: '4.1'
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '4.
|
|
53
|
+
version: '4.1'
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: rchardet
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -298,83 +298,20 @@ executables: []
|
|
|
298
298
|
extensions: []
|
|
299
299
|
extra_rdoc_files: []
|
|
300
300
|
files:
|
|
301
|
-
- ".claude/commands/address-copilot-reviews.md"
|
|
302
|
-
- ".claude/settings.json"
|
|
303
|
-
- ".claude/skills"
|
|
304
|
-
- ".commitlintrc.yml"
|
|
305
|
-
- ".dockerignore"
|
|
306
|
-
- ".github/copilot-instructions.md"
|
|
307
|
-
- ".github/hooks/bin-setup-on-worktree.json"
|
|
308
|
-
- ".github/hooks/run-bin-setup-once.sh"
|
|
309
|
-
- ".github/issue_template.md"
|
|
310
|
-
- ".github/prompts/iteratively-address-copilot-reviews.prompt.md"
|
|
311
|
-
- ".github/pull_request_template.md"
|
|
312
|
-
- ".github/skills-deprecated/README.md"
|
|
313
|
-
- ".github/skills-deprecated/extract-command-from-lib/SKILL.md"
|
|
314
|
-
- ".github/skills-deprecated/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md"
|
|
315
|
-
- ".github/skills-deprecated/extract-facade-from-base-lib/SKILL.md"
|
|
316
|
-
- ".github/skills-deprecated/review-backward-compatibility/SKILL.md"
|
|
317
|
-
- ".github/skills/breaking-change-analysis/SKILL.md"
|
|
318
|
-
- ".github/skills/ci-cd-troubleshooting/SKILL.md"
|
|
319
|
-
- ".github/skills/command-implementation/REFERENCE.md"
|
|
320
|
-
- ".github/skills/command-implementation/SKILL.md"
|
|
321
|
-
- ".github/skills/command-test-conventions/SKILL.md"
|
|
322
|
-
- ".github/skills/command-yard-documentation/SKILL.md"
|
|
323
|
-
- ".github/skills/dependency-management/SKILL.md"
|
|
324
|
-
- ".github/skills/development-workflow/SKILL.md"
|
|
325
|
-
- ".github/skills/facade-implementation/REFERENCE.md"
|
|
326
|
-
- ".github/skills/facade-implementation/SKILL.md"
|
|
327
|
-
- ".github/skills/facade-test-conventions/SKILL.md"
|
|
328
|
-
- ".github/skills/facade-yard-documentation/SKILL.md"
|
|
329
|
-
- ".github/skills/make-skill-template/SKILL.md"
|
|
330
|
-
- ".github/skills/pr-readiness-review/SKILL.md"
|
|
331
|
-
- ".github/skills/project-context/SKILL.md"
|
|
332
|
-
- ".github/skills/pull-request-review/SKILL.md"
|
|
333
|
-
- ".github/skills/rebase/SKILL.md"
|
|
334
|
-
- ".github/skills/refactor-command-to-commandlineresult/SKILL.md"
|
|
335
|
-
- ".github/skills/release-management/SKILL.md"
|
|
336
|
-
- ".github/skills/resolve-feedback/SKILL.md"
|
|
337
|
-
- ".github/skills/review-arguments-dsl/CHECKLIST.md"
|
|
338
|
-
- ".github/skills/review-arguments-dsl/SKILL.md"
|
|
339
|
-
- ".github/skills/review-cross-command-consistency/SKILL.md"
|
|
340
|
-
- ".github/skills/reviewing-skills/SKILL.md"
|
|
341
|
-
- ".github/skills/rspec-unit-testing-standards/SKILL.md"
|
|
342
|
-
- ".github/skills/tdd-refactor-step/SKILL.md"
|
|
343
|
-
- ".github/skills/test-debugging/SKILL.md"
|
|
344
|
-
- ".github/skills/yard-documentation/SKILL.md"
|
|
345
|
-
- ".github/skills/yard-documentation/element-rules.md"
|
|
346
|
-
- ".github/workflows/continuous_integration.yml"
|
|
347
|
-
- ".github/workflows/enforce_conventional_commits.yml"
|
|
348
|
-
- ".github/workflows/experimental_continuous_integration.yml"
|
|
349
|
-
- ".github/workflows/release.yml"
|
|
350
|
-
- ".github/workflows/warm_bundler_caches.yml"
|
|
351
|
-
- ".gitignore"
|
|
352
|
-
- ".husky/commit-msg"
|
|
353
|
-
- ".husky/pre-commit"
|
|
354
|
-
- ".release-please-config.json"
|
|
355
|
-
- ".release-please-manifest.json"
|
|
356
|
-
- ".rspec"
|
|
357
|
-
- ".rubocop.yml"
|
|
358
|
-
- ".rubocop_todo.yml"
|
|
359
|
-
- ".yard-lint.yml"
|
|
360
301
|
- ".yardopts"
|
|
361
302
|
- AI_POLICY.md
|
|
362
303
|
- CHANGELOG.md
|
|
363
|
-
- CLAUDE.md
|
|
364
304
|
- CODE_OF_CONDUCT.md
|
|
365
305
|
- CONTRIBUTING.md
|
|
366
306
|
- GOVERNANCE.md
|
|
367
|
-
- Gemfile
|
|
368
307
|
- LICENSE
|
|
369
308
|
- MAINTAINERS.md
|
|
370
309
|
- README.md
|
|
371
|
-
- Rakefile
|
|
372
310
|
- UPGRADING.md
|
|
373
|
-
- docker/test/Dockerfile
|
|
374
|
-
- docker/test/docker-compose.yml
|
|
375
311
|
- git.gemspec
|
|
376
312
|
- lib/git.rb
|
|
377
313
|
- lib/git/author.rb
|
|
314
|
+
- lib/git/author_info.rb
|
|
378
315
|
- lib/git/branch.rb
|
|
379
316
|
- lib/git/branch_delete_failure.rb
|
|
380
317
|
- lib/git/branch_delete_result.rb
|
|
@@ -600,39 +537,14 @@ files:
|
|
|
600
537
|
- lib/git/version_constraint.rb
|
|
601
538
|
- lib/git/worktree.rb
|
|
602
539
|
- lib/git/worktrees.rb
|
|
603
|
-
- package.json
|
|
604
|
-
- redesign/1_architecture_existing.md
|
|
605
|
-
- redesign/2_architecture_redesign.md
|
|
606
|
-
- redesign/3_architecture_implementation.md
|
|
607
|
-
- redesign/Phase 4 - Step A.md
|
|
608
|
-
- redesign/Phase 4 - Step B.md
|
|
609
|
-
- redesign/Phase 4 - Step C.md
|
|
610
|
-
- redesign/beta_release.md
|
|
611
|
-
- redesign/branch_parse_refactor_plan.md
|
|
612
|
-
- redesign/c1a-public-api-scope.tsv
|
|
613
|
-
- redesign/c1c2_audit.md
|
|
614
|
-
- redesign/c1c2_bucket6_lib_orphans.md
|
|
615
|
-
- redesign/config_design.rb
|
|
616
|
-
- redesign/index.md
|
|
617
|
-
- redesign/info_object_migration_plan.md
|
|
618
|
-
- redesign/integration_test_analysis.md
|
|
619
|
-
- redesign/phase-4-step-b-test-audit.tsv
|
|
620
|
-
- redesign/remote_refactor_plan.md
|
|
621
|
-
- redesign/reverse_dependencies.sql
|
|
622
|
-
- tasks/gem_tasks.rake
|
|
623
|
-
- tasks/npm_tasks.rake
|
|
624
|
-
- tasks/rspec.rake
|
|
625
|
-
- tasks/rubocop.rake
|
|
626
|
-
- tasks/test_gem.rake
|
|
627
|
-
- tasks/yard.rake
|
|
628
540
|
homepage: http://github.com/ruby-git/ruby-git
|
|
629
541
|
licenses:
|
|
630
542
|
- MIT
|
|
631
543
|
metadata:
|
|
632
544
|
homepage_uri: http://github.com/ruby-git/ruby-git
|
|
633
545
|
source_code_uri: http://github.com/ruby-git/ruby-git
|
|
634
|
-
changelog_uri: https://rubydoc.info/gems/git/5.
|
|
635
|
-
documentation_uri: https://rubydoc.info/gems/git/5.
|
|
546
|
+
changelog_uri: https://rubydoc.info/gems/git/5.3.0/file/CHANGELOG.md
|
|
547
|
+
documentation_uri: https://rubydoc.info/gems/git/5.3.0
|
|
636
548
|
rubygems_mfa_required: 'true'
|
|
637
549
|
rdoc_options: []
|
|
638
550
|
require_paths:
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Address all unresolved Copilot review threads on the active pull request
|
|
3
|
-
argument-hint: "[PR number — defaults to the PR for the current branch]"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Follow the shared agent prompt in
|
|
7
|
-
`.github/prompts/iteratively-address-copilot-reviews.prompt.md` exactly. That file
|
|
8
|
-
is the canonical instructions for this task and is shared with other AI agents; read
|
|
9
|
-
it before doing anything else.
|
|
10
|
-
|
|
11
|
-
@.github/prompts/iteratively-address-copilot-reviews.prompt.md
|
|
12
|
-
|
|
13
|
-
If `$ARGUMENTS` is non-empty, treat it as the pull request number to operate on
|
|
14
|
-
instead of detecting the PR from the current branch.
|