git 5.3.0 → 5.4.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 +16 -0
- data/README.md +1 -1
- data/UPGRADING.md +320 -22
- data/lib/git/branch.rb +9 -5
- data/lib/git/object.rb +56 -8
- data/lib/git/parsers/status.rb +251 -0
- data/lib/git/parsers/worktree.rb +185 -0
- data/lib/git/repository/object_operations.rb +257 -20
- data/lib/git/repository/stashing.rb +532 -52
- data/lib/git/repository/status_operations.rb +56 -8
- data/lib/git/repository/worktree_operations.rb +198 -18
- data/lib/git/stash.rb +31 -2
- data/lib/git/stashes.rb +47 -11
- data/lib/git/status.rb +14 -0
- data/lib/git/status_file_info.rb +258 -0
- data/lib/git/status_info.rb +189 -0
- data/lib/git/tag_info.rb +2 -1
- data/lib/git/version.rb +1 -1
- data/lib/git/worktree.rb +39 -0
- data/lib/git/worktree_info.rb +128 -0
- data/lib/git/worktrees.rb +19 -1
- data/lib/git.rb +4 -0
- metadata +8 -3
|
@@ -721,8 +721,28 @@ module Git
|
|
|
721
721
|
# @raise [Git::FailedError] if the underlying `git show-ref` invocation
|
|
722
722
|
# exits with an unexpected status (i.e., outside the allowed 0..1 range)
|
|
723
723
|
#
|
|
724
|
+
# @deprecated Use `tag_list(name).first` instead
|
|
725
|
+
#
|
|
726
|
+
# {#tag_list} returns immutable {Git::TagInfo} value objects rather
|
|
727
|
+
# than {Git::Object::Tag}. `tag_list(name).first` is `nil` when the tag
|
|
728
|
+
# does not exist, where this method raises
|
|
729
|
+
# {Git::UnexpectedResultError}. Call the corresponding
|
|
730
|
+
# {Git::Repository} method (e.g. {#archive}, {#log}, {#diff},
|
|
731
|
+
# {#cat_file_contents}) with `info.oid || info.target_oid` for
|
|
732
|
+
# operations on a tag; that is the object this method's return value
|
|
733
|
+
# pins at construction, so a later move of the tag does not redirect
|
|
734
|
+
# it, whereas the tag name would. The
|
|
735
|
+
# {Git::Object::Tag} constructor is deprecated too; this method
|
|
736
|
+
# silences it so one call emits one warning.
|
|
737
|
+
#
|
|
738
|
+
# @see #tag_list
|
|
739
|
+
#
|
|
724
740
|
def tag(tag_name)
|
|
725
|
-
Git::
|
|
741
|
+
Git::Deprecation.warn(
|
|
742
|
+
'Git::Repository#tag is deprecated and will be removed in v6.0.0. ' \
|
|
743
|
+
'Use Git::Repository#tag_list(name).first instead.'
|
|
744
|
+
)
|
|
745
|
+
Git::Deprecation.silence { Git::Object::Tag.new(self, tag_name) }
|
|
726
746
|
end
|
|
727
747
|
|
|
728
748
|
# Returns the appropriate git object for the given object reference
|
|
@@ -753,6 +773,47 @@ module Git
|
|
|
753
773
|
Git::Object.new(self, objectish)
|
|
754
774
|
end
|
|
755
775
|
|
|
776
|
+
# Returns the tags in the repository as structured objects
|
|
777
|
+
#
|
|
778
|
+
# @example List all tags
|
|
779
|
+
# repo.tag_list
|
|
780
|
+
# # => [#<data Git::TagInfo name="v1.0.0", oid=nil, target_oid="abc123...", ...>,
|
|
781
|
+
# # #<data Git::TagInfo name="v2.0.0", oid="def456...", target_oid="789abc...", ...>]
|
|
782
|
+
#
|
|
783
|
+
# @example Look up a single tag by name
|
|
784
|
+
# repo.tag_list('v1.0.0').first
|
|
785
|
+
# # => #<data Git::TagInfo name="v1.0.0", ...>
|
|
786
|
+
#
|
|
787
|
+
# @example Look up a tag that does not exist
|
|
788
|
+
# repo.tag_list('nonexistent').first #=> nil
|
|
789
|
+
#
|
|
790
|
+
# @example Filter using glob patterns
|
|
791
|
+
# repo.tag_list('v1.*', 'v2.*')
|
|
792
|
+
#
|
|
793
|
+
# @example List only annotated tags
|
|
794
|
+
# repo.tag_list.select(&:annotated?)
|
|
795
|
+
#
|
|
796
|
+
# @param patterns [Array<String>] optional shell wildcard patterns passed
|
|
797
|
+
# directly to `git tag --list`; when empty (the default) all tags are
|
|
798
|
+
# returned
|
|
799
|
+
#
|
|
800
|
+
# @return [Array<Git::TagInfo>] parsed tag information for every tag
|
|
801
|
+
# matching the patterns, in the order `git tag --list` reports them
|
|
802
|
+
#
|
|
803
|
+
# Returns an empty array when the repository has no tags or no tag
|
|
804
|
+
# matches the given patterns.
|
|
805
|
+
#
|
|
806
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
807
|
+
#
|
|
808
|
+
# @see https://git-scm.com/docs/git-tag git-tag
|
|
809
|
+
#
|
|
810
|
+
def tag_list(*patterns)
|
|
811
|
+
result = Git::Commands::Tag::List.new(@execution_context).call(
|
|
812
|
+
*patterns, format: Git::Parsers::Tag::FORMAT_STRING
|
|
813
|
+
)
|
|
814
|
+
Git::Parsers::Tag.parse_list(result.stdout)
|
|
815
|
+
end
|
|
816
|
+
|
|
756
817
|
# Returns all tags in the repository as tag objects
|
|
757
818
|
#
|
|
758
819
|
# Runs `git tag --list` with a machine-readable format, parses the output,
|
|
@@ -769,30 +830,50 @@ module Git
|
|
|
769
830
|
#
|
|
770
831
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
771
832
|
#
|
|
833
|
+
# @deprecated Use {#tag_list} instead
|
|
834
|
+
#
|
|
835
|
+
# {#tag_list} returns `Array<Git::TagInfo>` (immutable value objects)
|
|
836
|
+
# rather than `Array<Git::Object::Tag>`. Look a tag up by name with
|
|
837
|
+
# `tag_list(name).first`, and call the corresponding {Git::Repository}
|
|
838
|
+
# method (e.g. {#archive}, {#log}, {#diff}, {#cat_file_contents}) with
|
|
839
|
+
# `info.oid || info.target_oid` for operations on a tag; that is the
|
|
840
|
+
# object each returned {Git::Object::Tag} pins at construction, so a
|
|
841
|
+
# later move of the tag does not redirect it, whereas the tag name
|
|
842
|
+
# would. The {Git::Object::Tag}
|
|
843
|
+
# constructor is deprecated too; this method silences it so one call
|
|
844
|
+
# emits one warning.
|
|
845
|
+
#
|
|
846
|
+
# @see #tag_list
|
|
847
|
+
#
|
|
772
848
|
def tags
|
|
773
|
-
|
|
774
|
-
|
|
849
|
+
Git::Deprecation.warn(
|
|
850
|
+
'Git::Repository#tags is deprecated and will be removed in v6.0.0. ' \
|
|
851
|
+
'Use Git::Repository#tag_list instead.'
|
|
852
|
+
)
|
|
853
|
+
Git::Deprecation.silence { tag_list.map { |info| Git::Object::Tag.new(self, info.name) } }
|
|
775
854
|
end
|
|
776
855
|
|
|
777
|
-
# Option keys accepted by {#tag_add}
|
|
778
|
-
|
|
856
|
+
# Option keys accepted by {#tag_create} and {#tag_add}
|
|
857
|
+
TAG_CREATE_ALLOWED_OPTS = %i[
|
|
779
858
|
annotate a sign s no_sign local_user u force f message m file F
|
|
780
859
|
edit e no_edit trailer cleanup create_reflog
|
|
781
860
|
].freeze
|
|
782
|
-
private_constant :
|
|
861
|
+
private_constant :TAG_CREATE_ALLOWED_OPTS
|
|
783
862
|
|
|
784
|
-
# Create a new tag
|
|
863
|
+
# Create a new tag and return its metadata
|
|
785
864
|
#
|
|
786
|
-
# @overload
|
|
865
|
+
# @overload tag_create(name, options = {})
|
|
787
866
|
#
|
|
788
867
|
# @example Create a lightweight tag on HEAD
|
|
789
|
-
# repo.
|
|
868
|
+
# repo.tag_create('v1.0.0')
|
|
869
|
+
# # => #<data Git::TagInfo name="v1.0.0", oid=nil, target_oid="abc123...", ...>
|
|
790
870
|
#
|
|
791
871
|
# @example Create an annotated tag on HEAD
|
|
792
|
-
# repo.
|
|
872
|
+
# repo.tag_create('v1.0.0', annotate: true, message: 'Release 1.0.0')
|
|
873
|
+
# # => #<data Git::TagInfo name="v1.0.0", oid="def456...", message="Release 1.0.0", ...>
|
|
793
874
|
#
|
|
794
875
|
# @example Replace an existing tag on HEAD
|
|
795
|
-
# repo.
|
|
876
|
+
# repo.tag_create('v1.0.0', force: true)
|
|
796
877
|
#
|
|
797
878
|
# @param name [String] the name of the tag to create
|
|
798
879
|
#
|
|
@@ -847,6 +928,65 @@ module Git
|
|
|
847
928
|
# @option options [Boolean, nil] :create_reflog (nil) create a reflog for
|
|
848
929
|
# the tag
|
|
849
930
|
#
|
|
931
|
+
# @return [Git::TagInfo] the newly created tag
|
|
932
|
+
#
|
|
933
|
+
# @overload tag_create(name, target, options = {})
|
|
934
|
+
#
|
|
935
|
+
# @example Create a lightweight tag on a specific commit
|
|
936
|
+
# repo.tag_create('v1.0.0', 'abc123')
|
|
937
|
+
#
|
|
938
|
+
# @example Create an annotated tag on a specific commit
|
|
939
|
+
# repo.tag_create('v1.0.0', 'abc123', annotate: true, message: 'Release 1.0.0')
|
|
940
|
+
#
|
|
941
|
+
# @param name [String] the name of the tag to create
|
|
942
|
+
#
|
|
943
|
+
# @param target [String] the object to tag (commit SHA, branch name, etc.)
|
|
944
|
+
#
|
|
945
|
+
# @param options [Hash] options for creating the tag (same keys as the
|
|
946
|
+
# first overload)
|
|
947
|
+
#
|
|
948
|
+
# @return [Git::TagInfo] the newly created tag
|
|
949
|
+
#
|
|
950
|
+
# @raise [ArgumentError] if unsupported options are provided, including the
|
|
951
|
+
# `:d` and `:delete` keys that {#tag_add} accepts; use {#tag_delete} to
|
|
952
|
+
# delete a tag
|
|
953
|
+
#
|
|
954
|
+
# @raise [ArgumentError] if an annotated or signed tag is requested without
|
|
955
|
+
# a message
|
|
956
|
+
#
|
|
957
|
+
# @raise [ArgumentError] if more than one positional argument follows the
|
|
958
|
+
# name (before any options hash); {#tag_add} silently ignored the extra
|
|
959
|
+
# arguments and tagged the first
|
|
960
|
+
#
|
|
961
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
962
|
+
#
|
|
963
|
+
# @see https://git-scm.com/docs/git-tag git-tag
|
|
964
|
+
#
|
|
965
|
+
def tag_create(name, *args)
|
|
966
|
+
target, options = Private.tag_target_and_options(args, strict: true)
|
|
967
|
+
SharedPrivate.assert_valid_opts!(TAG_CREATE_ALLOWED_OPTS, **options)
|
|
968
|
+
Private.create_tag(@execution_context, name, target, options)
|
|
969
|
+
tag_list(name).first
|
|
970
|
+
end
|
|
971
|
+
|
|
972
|
+
# Create a new tag
|
|
973
|
+
#
|
|
974
|
+
# @overload tag_add(name, options = {})
|
|
975
|
+
#
|
|
976
|
+
# @example Create a lightweight tag on HEAD
|
|
977
|
+
# repo.tag_add('v1.0.0')
|
|
978
|
+
#
|
|
979
|
+
# @example Create an annotated tag on HEAD
|
|
980
|
+
# repo.tag_add('v1.0.0', annotate: true, message: 'Release 1.0.0')
|
|
981
|
+
#
|
|
982
|
+
# @example Replace an existing tag on HEAD
|
|
983
|
+
# repo.tag_add('v1.0.0', force: true)
|
|
984
|
+
#
|
|
985
|
+
# @param name [String] the name of the tag to create
|
|
986
|
+
#
|
|
987
|
+
# @param options [Hash] options for creating the tag (same keys as
|
|
988
|
+
# {#tag_create})
|
|
989
|
+
#
|
|
850
990
|
# @return [Git::Object::Tag] the newly created tag
|
|
851
991
|
#
|
|
852
992
|
# @overload tag_add(name, target, options = {})
|
|
@@ -861,8 +1001,8 @@ module Git
|
|
|
861
1001
|
#
|
|
862
1002
|
# @param target [String] the object to tag (commit SHA, branch name, etc.)
|
|
863
1003
|
#
|
|
864
|
-
# @param options [Hash] options for creating the tag (same keys as
|
|
865
|
-
#
|
|
1004
|
+
# @param options [Hash] options for creating the tag (same keys as
|
|
1005
|
+
# {#tag_create})
|
|
866
1006
|
#
|
|
867
1007
|
# @return [Git::Object::Tag] the newly created tag
|
|
868
1008
|
#
|
|
@@ -893,17 +1033,31 @@ module Git
|
|
|
893
1033
|
#
|
|
894
1034
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
895
1035
|
#
|
|
1036
|
+
# @deprecated Use {#tag_create} instead
|
|
1037
|
+
#
|
|
1038
|
+
# {#tag_create} accepts the same `name`, `target`, and options and
|
|
1039
|
+
# returns a {Git::TagInfo} (an immutable value object) rather than a
|
|
1040
|
+
# {Git::Object::Tag}. It does not accept the `:d`/`:delete` form; use
|
|
1041
|
+
# {#tag_delete} for that. The {Git::Object::Tag} constructor is
|
|
1042
|
+
# deprecated too; this method silences it so one call emits one
|
|
1043
|
+
# warning, except that the `:d`/`:delete` form emits a second warning
|
|
1044
|
+
# of its own.
|
|
1045
|
+
#
|
|
1046
|
+
# @see #tag_create
|
|
1047
|
+
#
|
|
896
1048
|
def tag_add(name, *args)
|
|
897
|
-
|
|
898
|
-
|
|
1049
|
+
Git::Deprecation.warn(
|
|
1050
|
+
'Git::Repository#tag_add is deprecated and will be removed in v6.0.0. ' \
|
|
1051
|
+
'Use Git::Repository#tag_create instead.'
|
|
1052
|
+
)
|
|
1053
|
+
target, options = Private.tag_target_and_options(args)
|
|
899
1054
|
|
|
900
1055
|
return Private.tag_add_delete_deprecated(self, name, target, options) if options[:d] || options[:delete]
|
|
901
1056
|
|
|
902
1057
|
options = options.except(:d, :delete)
|
|
903
|
-
SharedPrivate.assert_valid_opts!(
|
|
904
|
-
Private.
|
|
905
|
-
Git::
|
|
906
|
-
tag(name)
|
|
1058
|
+
SharedPrivate.assert_valid_opts!(TAG_CREATE_ALLOWED_OPTS, **options)
|
|
1059
|
+
Private.create_tag(@execution_context, name, target, options)
|
|
1060
|
+
Git::Deprecation.silence { Git::Object::Tag.new(self, name) }
|
|
907
1061
|
end
|
|
908
1062
|
|
|
909
1063
|
# @overload add_tag(name, options = {})
|
|
@@ -931,7 +1085,14 @@ module Git
|
|
|
931
1085
|
#
|
|
932
1086
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
933
1087
|
#
|
|
934
|
-
# @deprecated Use {#
|
|
1088
|
+
# @deprecated Use {#tag_create} instead
|
|
1089
|
+
#
|
|
1090
|
+
# The warning names {#tag_add}, the replacement this method shipped
|
|
1091
|
+
# with, and {#tag_add} is deprecated as well, so a creation call emits
|
|
1092
|
+
# two warnings: one for this method and one for {#tag_add}. The delete
|
|
1093
|
+
# form `add_tag(name, d: true)` emits a third, for the deprecated `:d`
|
|
1094
|
+
# and `:delete` options on {#tag_add}; use {#tag_delete} for that. Go
|
|
1095
|
+
# straight to {#tag_create} for creation.
|
|
935
1096
|
#
|
|
936
1097
|
def add_tag(name, *)
|
|
937
1098
|
Git::Deprecation.warn(
|
|
@@ -982,6 +1143,82 @@ module Git
|
|
|
982
1143
|
module Private
|
|
983
1144
|
module_function
|
|
984
1145
|
|
|
1146
|
+
# Splits the variadic `*args` of {ObjectOperations#tag_create} and
|
|
1147
|
+
# {ObjectOperations#tag_add} into the target and the options hash
|
|
1148
|
+
#
|
|
1149
|
+
# Both methods accept `(name, opts = {})` and `(name, target, opts = {})`,
|
|
1150
|
+
# so a trailing `Hash` is the options and anything before it is the
|
|
1151
|
+
# target.
|
|
1152
|
+
#
|
|
1153
|
+
# @param args [Array] the arguments after the tag name
|
|
1154
|
+
#
|
|
1155
|
+
# @param strict [Boolean] when `true`, raise instead of silently ignoring
|
|
1156
|
+
# a second positional argument before the options; `tag_create` is
|
|
1157
|
+
# strict, while the deprecated `tag_add` keeps its lenient behavior
|
|
1158
|
+
#
|
|
1159
|
+
# @return [Array((String, nil), Hash)] the two-element tuple
|
|
1160
|
+
# `[target, options]`; `target` is `nil` when only options were given
|
|
1161
|
+
#
|
|
1162
|
+
# @raise [ArgumentError] if `strict` is `true` and more than one
|
|
1163
|
+
# positional argument precedes the options hash
|
|
1164
|
+
#
|
|
1165
|
+
# @api private
|
|
1166
|
+
#
|
|
1167
|
+
def tag_target_and_options(args, strict: false)
|
|
1168
|
+
args = args.dup
|
|
1169
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
1170
|
+
if strict && args.size > 1
|
|
1171
|
+
raise ArgumentError,
|
|
1172
|
+
"Expected at most one target before the options, got #{args.size}: #{args.inspect}"
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
[args.first, options]
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1178
|
+
# Validates the tag-creation options and runs `git tag`
|
|
1179
|
+
#
|
|
1180
|
+
# @param execution_context [Git::ExecutionContext::Repository] the
|
|
1181
|
+
# execution context for git commands
|
|
1182
|
+
#
|
|
1183
|
+
# @param name [String] the name of the tag to create
|
|
1184
|
+
#
|
|
1185
|
+
# @param target [String, nil] the object to tag, or `nil` for HEAD
|
|
1186
|
+
#
|
|
1187
|
+
# @param options [Hash] the tag-creation options, already checked
|
|
1188
|
+
# against the allowed keys (see {ObjectOperations#tag_create} for the
|
|
1189
|
+
# full list)
|
|
1190
|
+
#
|
|
1191
|
+
# @option options [Boolean, nil] :annotate (nil) make an annotated tag;
|
|
1192
|
+
# requires a message (alias: `:a`)
|
|
1193
|
+
#
|
|
1194
|
+
# @option options [Boolean, nil] :sign (nil) make a signed tag; requires
|
|
1195
|
+
# a message (alias: `:s`)
|
|
1196
|
+
#
|
|
1197
|
+
# @option options [String] :local_user (nil) sign with the given key;
|
|
1198
|
+
# requires a message (alias: `:u`)
|
|
1199
|
+
#
|
|
1200
|
+
# @option options [String] :message (nil) the tag message (alias: `:m`)
|
|
1201
|
+
#
|
|
1202
|
+
# @option options [String] :file (nil) a file to read the tag message
|
|
1203
|
+
# from (alias: `:F`)
|
|
1204
|
+
#
|
|
1205
|
+
# @option options [Boolean, nil] :force (nil) replace an existing tag
|
|
1206
|
+
# (alias: `:f`)
|
|
1207
|
+
#
|
|
1208
|
+
# @return [void]
|
|
1209
|
+
#
|
|
1210
|
+
# @raise [ArgumentError] when an annotated or signed tag is requested
|
|
1211
|
+
# without a message
|
|
1212
|
+
#
|
|
1213
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
1214
|
+
#
|
|
1215
|
+
# @api private
|
|
1216
|
+
#
|
|
1217
|
+
def create_tag(execution_context, name, target, options)
|
|
1218
|
+
validate_tag_options!(options)
|
|
1219
|
+
Git::Commands::Tag::Create.new(execution_context).call(name, target, **options)
|
|
1220
|
+
end
|
|
1221
|
+
|
|
985
1222
|
# Validate that a message is present when an annotated or signed tag is
|
|
986
1223
|
# requested
|
|
987
1224
|
#
|