git 2.1.1 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b171ab737c87e925d5752b52f2f05bdd2361592624d88b8db8db380dde051019
4
- data.tar.gz: d7b3b7cdaba4996288c4c0e8fffe7819da6c0933ade68ca810d9fb3519d5cda0
3
+ metadata.gz: 1e24e434e4639e6c31133234cee6d96708baf23d212c2f78cf4b94159810b090
4
+ data.tar.gz: 9fc37b011ac0cb0e87a0ee50b7993e751a7075a7496d6feb41431d2f3612e823
5
5
  SHA512:
6
- metadata.gz: '08dd5a4ea7b07230642e2dd87fca85ea634890f4700b77a996b3ff4443fc62d3c11a230c082c4d5b2c45c6c7d6916d9b98ce7362676e72d1a4bdd6f0fe2043e6'
7
- data.tar.gz: 568111f5579b6b1728974dbfa12dc4d742f3715e951645dbed9a54d91399492157b77659b2e956ee995c142c8dbb01f3ee07357fb4db2a9c2bd0e1870e83dc79
6
+ metadata.gz: 232624614200233e3f2ed308a4e73580345fef5be0a98e64f35992ecb222fa96c4163399b2f08afbfcdf69cd3b2f8f6c57c309fe9122f18a56e9bc31f827b301
7
+ data.tar.gz: 4ae699244e5ff9f679795279b8dbfeebe35ce8c9bfb7e5d9a18552b77b3d86b630f50bd9fedb4eec4f697269cfec6c90f72adfa2edeada25258ab457f3b5dad8
data/CHANGELOG.md CHANGED
@@ -5,6 +5,32 @@
5
5
 
6
6
  # Change Log
7
7
 
8
+ ## v2.3.0 (2024-09-01)
9
+
10
+ [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.2.0..v2.3.0)
11
+
12
+ Changes since v2.2.0:
13
+
14
+ * f8bc987 Fix windows CI build error
15
+ * 471f5a8 Sanatize object ref sent to cat-file command
16
+ * 604a9a2 Make Git::Base#branch work when HEAD is detached
17
+
18
+ ## v2.2.0 (2024-08-26)
19
+
20
+ [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.1.1..v2.2.0)
21
+
22
+ Changes since v2.1.1:
23
+
24
+ * 7292f2c Omit the test for signed commit data on Windows
25
+ * 2d6157c Document this gem's (aspirational) design philosophy
26
+ * d4f66ab Sanitize non-option arguments passed to `git name-rev`
27
+ * 0296442 Refactor Git::Lib#rev_parse
28
+ * 9b9b31e Verify that the revision-range passed to git log does not resemble a command-line option
29
+ * dc46ede Verify that the commit-ish passed to git describe does not resemble a command-line option
30
+ * 00c4939 Verify that the commit(s) passed to git diff do not resemble a command-line option
31
+ * a08f89b Update README
32
+ * 737c4bb ls-tree optional recursion into subtrees
33
+
8
34
  ## v2.1.1 (2024-06-01)
9
35
 
10
36
  [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.1.0..v2.1.1)
data/CONTRIBUTING.md CHANGED
@@ -3,116 +3,191 @@
3
3
  # @title How To Contribute
4
4
  -->
5
5
 
6
- # Contributing to ruby-git
7
-
8
- Thank you for your interest in contributing to the ruby-git project.
9
-
10
- This document gives the guidelines for contributing to the ruby-git project.
11
- These guidelines may not fit every situation. When contributing use your best
12
- judgement.
13
-
14
- Propose changes to these guidelines with a pull request.
6
+ * [How to contribute](#how-to-contribute)
7
+ * [How to report an issue or request a feature](#how-to-report-an-issue-or-request-a-feature)
8
+ * [How to submit a code or documentation change](#how-to-submit-a-code-or-documentation-change)
9
+ * [Commit your changes to a fork of `ruby-git`](#commit-your-changes-to-a-fork-of-ruby-git)
10
+ * [Create a pull request](#create-a-pull-request)
11
+ * [Get your pull request reviewed](#get-your-pull-request-reviewed)
12
+ * [Design philosophy](#design-philosophy)
13
+ * [Direct mapping to git commands](#direct-mapping-to-git-commands)
14
+ * [Parameter naming](#parameter-naming)
15
+ * [Output processing](#output-processing)
16
+ * [Coding standards](#coding-standards)
17
+ * [1 PR = 1 Commit](#1-pr--1-commit)
18
+ * [Unit tests](#unit-tests)
19
+ * [Continuous integration](#continuous-integration)
20
+ * [Documentation](#documentation)
21
+ * [Licensing](#licensing)
22
+
23
+
24
+ # Contributing to the git gem
25
+
26
+ Thank you for your interest in contributing to the `ruby-git` project.
27
+
28
+ This document provides guidelines for contributing to the `ruby-git` project. While
29
+ these guidelines may not cover every situation, we encourage you to use your best
30
+ judgment when contributing.
31
+
32
+ If you have suggestions for improving these guidelines, please propose changes via a
33
+ pull request.
15
34
 
16
35
  ## How to contribute
17
36
 
18
- You can contribute in two ways:
37
+ You can contribute in the following ways:
19
38
 
20
- 1. [Report an issue or make a feature request](#how-to-report-an-issue-or-make-a-feature-request)
21
- 2. [Submit a code or documentation change](#how-to-submit-a-code-or-documentation-change)
39
+ 1. [Report an issue or request a
40
+ feature](#how-to-report-an-issue-or-request-a-feature)
41
+ 2. [Submit a code or documentation
42
+ change](#how-to-submit-a-code-or-documentation-change)
22
43
 
23
- ## How to report an issue or make a feature request
44
+ ## How to report an issue or request a feature
24
45
 
25
- ruby-git utilizes [GitHub Issues](https://help.github.com/en/github/managing-your-work-on-github/about-issues)
46
+ `ruby-git` utilizes [GitHub
47
+ Issues](https://help.github.com/en/github/managing-your-work-on-github/about-issues)
26
48
  for issue tracking and feature requests.
27
49
 
28
- Report an issue or feature request by [creating a ruby-git Github issue](https://github.com/ruby-git/ruby-git/issues/new).
29
- Fill in the template to describe the issue or feature request the best you can.
50
+ To report an issue or request a feature, please [create a `ruby-git` GitHub
51
+ issue](https://github.com/ruby-git/ruby-git/issues/new). Fill in the template as
52
+ thoroughly as possible to describe the issue or feature request.
30
53
 
31
54
  ## How to submit a code or documentation change
32
55
 
33
- There is three step process for code or documentation changes:
56
+ There is a three-step process for submitting code or documentation changes:
34
57
 
35
- 1. [Commit your changes to a fork of ruby-git](#commit-changes-to-a-fork-of-ruby-git)
58
+ 1. [Commit your changes to a fork of
59
+ `ruby-git`](#commit-your-changes-to-a-fork-of-ruby-git)
36
60
  2. [Create a pull request](#create-a-pull-request)
37
61
  3. [Get your pull request reviewed](#get-your-pull-request-reviewed)
38
62
 
39
- ### Commit changes to a fork of ruby-git
63
+ ### Commit your changes to a fork of `ruby-git`
40
64
 
41
- Make your changes in a fork of the ruby-git repository.
65
+ Make your changes in a fork of the `ruby-git` repository.
42
66
 
43
67
  ### Create a pull request
44
68
 
45
- See [this article](https://help.github.com/articles/about-pull-requests/) if you
46
- are not familiar with GitHub Pull Requests.
69
+ If you are not familiar with GitHub Pull Requests, please refer to [this
70
+ article](https://help.github.com/articles/about-pull-requests/).
47
71
 
48
72
  Follow the instructions in the pull request template.
49
73
 
50
74
  ### Get your pull request reviewed
51
75
 
52
- Code review takes place in a GitHub pull request using the [the Github pull request review feature](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews).
76
+ Code review takes place in a GitHub pull request using the [GitHub pull request
77
+ review
78
+ feature](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews).
53
79
 
54
80
  Once your pull request is ready for review, request a review from at least one
55
- [maintainer](MAINTAINERS.md) and any number of other contributors.
81
+ [maintainer](MAINTAINERS.md) and any other contributors you deem necessary.
82
+
83
+ During the review process, you may need to make additional commits, which should be
84
+ squashed. Additionally, you may need to rebase your branch to the latest `master`
85
+ branch if other changes have been merged.
86
+
87
+ At least one approval from a project maintainer is required before your pull request
88
+ can be merged. The maintainer is responsible for ensuring that the pull request meets
89
+ [the project's coding standards](#coding-standards).
90
+
91
+ ## Design philosophy
92
+
93
+ *Note: As of v2.x of the `git` gem, this design philosophy is aspirational. Future
94
+ versions may include interface changes to fully align with these principles.*
95
+
96
+ The `git` gem is designed as a lightweight wrapper around the `git` command-line
97
+ tool, providing Ruby developers with a simple and intuitive interface for
98
+ programmatically interacting with Git.
99
+
100
+ This gem adheres to the "principle of least surprise," ensuring that it does not
101
+ introduce unnecessary abstraction layers or modify Git's core functionality. Instead,
102
+ the gem maintains a close alignment with the existing `git` command-line interface,
103
+ avoiding extensions or alterations that could lead to unexpected behaviors.
104
+
105
+ By following this philosophy, the `git` gem allows users to leverage their existing
106
+ knowledge of Git while benefiting from the expressiveness and power of Ruby's syntax
107
+ and paradigms.
108
+
109
+ ### Direct mapping to git commands
56
110
 
57
- During the review process, you may need to make additional commits which would
58
- need to be squashed. It may also be necessary to rebase to master again if other
59
- changes are merged before your PR.
111
+ Git commands are implemented within the `Git::Base` class, with each method directly
112
+ corresponding to a `git` command. When a `Git::Base` object is instantiated via
113
+ `Git.open`, `Git.clone`, or `Git.init`, the user can invoke these methods to interact
114
+ with the underlying Git repository.
60
115
 
61
- At least one approval is required from a project maintainer before your pull
62
- request can be merged. The maintainer is responsible for ensuring that the pull
63
- request meets [the project's coding standards](#coding-standards).
116
+ For example, the `git add` command is implemented as `Git::Base#add`, and the `git
117
+ ls-files` command is implemented as `Git::Base#ls_files`.
118
+
119
+ When a single Git command serves multiple distinct purposes, method names within the
120
+ `Git::Base` class should use the `git` command name as a prefix, followed by a
121
+ descriptive suffix to indicate the specific function.
122
+
123
+ For instance, `#ls_files_untracked` and `#ls_files_staged` could be used to execute
124
+ the `git ls-files` command and return untracked and staged files, respectively.
125
+
126
+ To enhance usability, aliases may be introduced to provide more user-friendly method
127
+ names where appropriate.
128
+
129
+ ### Parameter naming
130
+
131
+ Parameters within the `git` gem methods are named after their corresponding long
132
+ command-line options, ensuring familiarity and ease of use for developers already
133
+ accustomed to Git. Note that not all Git command options are supported.
134
+
135
+ ### Output processing
136
+
137
+ The `git` gem translates the output of many Git commands into Ruby objects, making it
138
+ easier to work with programmatically.
139
+
140
+ These Ruby objects often include methods that allow for further Git operations where
141
+ useful, providing additional functionality while staying true to the underlying Git
142
+ behavior.
64
143
 
65
144
  ## Coding standards
66
145
 
67
- In order to ensure high quality, all pull requests must meet these requirements:
146
+ To ensure high-quality contributions, all pull requests must meet the following
147
+ requirements:
68
148
 
69
149
  ### 1 PR = 1 Commit
70
150
 
71
- * All commits for a PR must be squashed into one commit
72
- * To avoid an extra merge commit, the PR must be able to be merged as [a fast forward
73
- merge](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging)
74
- * The easiest way to ensure a fast forward merge is to rebase your local branch to
75
- the ruby-git master branch
151
+ * All commits for a PR must be squashed into a single commit.
152
+ * To avoid an extra merge commit, the PR must be able to be merged as [a fast-forward
153
+ merge](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging).
154
+ * The easiest way to ensure a fast-forward merge is to rebase your local branch to
155
+ the `ruby-git` master branch.
76
156
 
77
157
  ### Unit tests
78
158
 
79
- * All changes must be accompanied by new or modified unit tests
159
+ * All changes must be accompanied by new or modified unit tests.
80
160
  * The entire test suite must pass when `bundle exec rake default` is run from the
81
161
  project's local working copy.
82
162
 
83
- While working on specific features you can run individual test files or
84
- a group of tests using `bin/test`:
163
+ While working on specific features, you can run individual test files or a group of
164
+ tests using `bin/test`:
85
165
 
86
- # run a single file (from tests/units):
87
- $ bin/test test_object
166
+ ```bash
167
+ # run a single file (from tests/units):
168
+ $ bin/test test_object
88
169
 
89
- # run multiple files:
90
- $ bin/test test_object test_archive
170
+ # run multiple files:
171
+ $ bin/test test_object test_archive
91
172
 
92
- # run all unit tests:
93
- $ bin/test
173
+ # run all unit tests:
174
+ $ bin/test
175
+ ```
94
176
 
95
177
  ### Continuous integration
96
178
 
97
- * All tests must pass in the project's [GitHub Continuous Integration
98
- build](https://github.com/ruby-git/ruby-git/actions?query=workflow%3ACI) before the
99
- pull request will be merged.
100
- * The [Continuous Integration
101
- workflow](https://github.com/ruby-git/ruby-git/blob/master/.github/workflows/continuous_integration.yml)
102
- runs both `bundle exec rake default` and `bundle exec rake test:gem` from the
103
- project's [Rakefile](https://github.com/ruby-git/ruby-git/blob/master/Rakefile).
179
+ All tests must pass in the project's [GitHub Continuous Integration build](https://github.com/ruby-git/ruby-git/actions?query=workflow%3ACI) before the pull request will be merged.
180
+
181
+ The [Continuous Integration workflow](https://github.com/ruby-git/ruby-git/blob/master/.github/workflows/continuous_integration.yml) runs both `bundle exec rake default` and `bundle exec rake test:gem` from the project's [Rakefile](https://github.com/ruby-git/ruby-git/blob/master/Rakefile).
104
182
 
105
183
  ### Documentation
106
184
 
107
- * New and updated public methods must have [YARD](https://yardoc.org/) documentation
108
- added to them
109
- * New and updated public facing features should be documented in the project's
110
- [README.md](README.md)
185
+ New and updated public methods must include [YARD](https://yardoc.org/) documentation.
186
+
187
+ New and updated public-facing features should be documented in the project's [README.md](README.md).
111
188
 
112
189
  ## Licensing
113
190
 
114
- ruby-git uses [the MIT license](https://choosealicense.com/licenses/mit/) as
115
- declared in the [LICENSE](LICENSE) file.
191
+ `ruby-git` uses [the MIT license](https://choosealicense.com/licenses/mit/) as declared in the [LICENSE](LICENSE) file.
116
192
 
117
- Licensing is very important to open source projects. It helps ensure the
118
- software continues to be available under the terms that the author desired.
193
+ Licensing is critical to open-source projects as it ensures the software remains available under the terms desired by the author.
data/README.md CHANGED
@@ -236,6 +236,9 @@ g.index.writable?
236
236
  g.repo
237
237
  g.dir
238
238
 
239
+ # ls-tree with recursion into subtrees (list files)
240
+ g.ls_tree("HEAD", recursive: true)
241
+
239
242
  # log - returns a Git::Log object, which is an Enumerator of Git::Commit objects
240
243
  # default configuration returns a max of 30 commits
241
244
  g.log
@@ -274,7 +277,7 @@ tree.blobs
274
277
  tree.subtrees
275
278
  tree.children # blobs and subtrees
276
279
 
277
- g.revparse('v2.5:Makefile')
280
+ g.rev_parse('v2.0.0:README.md')
278
281
 
279
282
  g.branches # returns Git::Branch objects
280
283
  g.branches.local
data/lib/git/base.rb CHANGED
@@ -634,23 +634,33 @@ module Git
634
634
  # runs git rev-parse to convert the objectish to a full sha
635
635
  #
636
636
  # @example
637
- # git.revparse("HEAD^^")
638
- # git.revparse('v2.4^{tree}')
639
- # git.revparse('v2.4:/doc/index.html')
637
+ # git.rev_parse("HEAD^^")
638
+ # git.rev_parse('v2.4^{tree}')
639
+ # git.rev_parse('v2.4:/doc/index.html')
640
640
  #
641
- def revparse(objectish)
642
- self.lib.revparse(objectish)
641
+ def rev_parse(objectish)
642
+ self.lib.rev_parse(objectish)
643
643
  end
644
644
 
645
- def ls_tree(objectish)
646
- self.lib.ls_tree(objectish)
645
+ # For backwards compatibility
646
+ alias revparse rev_parse
647
+
648
+ def ls_tree(objectish, opts = {})
649
+ self.lib.ls_tree(objectish, opts)
647
650
  end
648
651
 
649
652
  def cat_file(objectish)
650
- self.lib.object_contents(objectish)
653
+ self.lib.cat_file(objectish)
651
654
  end
652
655
 
653
- # returns the name of the branch the working directory is currently on
656
+ # The name of the branch HEAD refers to or 'HEAD' if detached
657
+ #
658
+ # Returns one of the following:
659
+ # * The branch name that HEAD refers to (even if it is an unborn branch)
660
+ # * 'HEAD' if in a detached HEAD state
661
+ #
662
+ # @return [String] the name of the branch HEAD refers to or 'HEAD' if detached
663
+ #
654
664
  def current_branch
655
665
  self.lib.branch_current
656
666
  end
data/lib/git/lib.rb CHANGED
@@ -169,27 +169,33 @@ module Git
169
169
 
170
170
  ## READ COMMANDS ##
171
171
 
172
+ # Finds most recent tag that is reachable from a commit
172
173
  #
173
- # Returns most recent tag that is reachable from a commit
174
+ # @see https://git-scm.com/docs/git-describe git-describe
174
175
  #
175
- # accepts options:
176
- # :all
177
- # :tags
178
- # :contains
179
- # :debug
180
- # :exact_match
181
- # :dirty
182
- # :abbrev
183
- # :candidates
184
- # :long
185
- # :always
186
- # :math
187
- #
188
- # @param [String|NilClass] committish target commit sha or object name
189
- # @param [{Symbol=>Object}] opts the given options
190
- # @return [String] the tag name
191
- #
192
- def describe(committish=nil, opts={})
176
+ # @param commit_ish [String, nil] target commit sha or object name
177
+ #
178
+ # @param opts [Hash] the given options
179
+ #
180
+ # @option opts :all [Boolean]
181
+ # @option opts :tags [Boolean]
182
+ # @option opts :contains [Boolean]
183
+ # @option opts :debug [Boolean]
184
+ # @option opts :long [Boolean]
185
+ # @option opts :always [Boolean]
186
+ # @option opts :exact_match [Boolean]
187
+ # @option opts :dirty [true, String]
188
+ # @option opts :abbrev [String]
189
+ # @option opts :candidates [String]
190
+ # @option opts :match [String]
191
+ #
192
+ # @return [String] the tag name
193
+ #
194
+ # @raise [ArgumentError] if the commit_ish is a string starting with a hyphen
195
+ #
196
+ def describe(commit_ish = nil, opts = {})
197
+ assert_args_are_not_options('commit-ish object', commit_ish)
198
+
193
199
  arr_opts = []
194
200
 
195
201
  arr_opts << '--all' if opts[:all]
@@ -207,12 +213,42 @@ module Git
207
213
  arr_opts << "--candidates=#{opts[:candidates]}" if opts[:candidates]
208
214
  arr_opts << "--match=#{opts[:match]}" if opts[:match]
209
215
 
210
- arr_opts << committish if committish
216
+ arr_opts << commit_ish if commit_ish
211
217
 
212
218
  return command('describe', *arr_opts)
213
219
  end
214
220
 
215
- def log_commits(opts={})
221
+ # Return the commits that are within the given revision range
222
+ #
223
+ # @see https://git-scm.com/docs/git-log git-log
224
+ #
225
+ # @param opts [Hash] the given options
226
+ #
227
+ # @option opts :count [Integer] the maximum number of commits to return (maps to max-count)
228
+ # @option opts :all [Boolean]
229
+ # @option opts :cherry [Boolean]
230
+ # @option opts :since [String]
231
+ # @option opts :until [String]
232
+ # @option opts :grep [String]
233
+ # @option opts :author [String]
234
+ # @option opts :between [Array<String>] an array of two commit-ish strings to specify a revision range
235
+ #
236
+ # Only :between or :object options can be used, not both.
237
+ #
238
+ # @option opts :object [String] the revision range for the git log command
239
+ #
240
+ # Only :between or :object options can be used, not both.
241
+ #
242
+ # @option opts :path_limiter [Array<String>, String] only include commits that impact files from the specified paths
243
+ #
244
+ # @return [Array<String>] the log output
245
+ #
246
+ # @raise [ArgumentError] if the resulting revision range is a string starting with a hyphen
247
+ #
248
+ def log_commits(opts = {})
249
+ assert_args_are_not_options('between', opts[:between]&.first)
250
+ assert_args_are_not_options('object', opts[:object])
251
+
216
252
  arr_opts = log_common_options(opts)
217
253
 
218
254
  arr_opts << '--pretty=oneline'
@@ -222,7 +258,47 @@ module Git
222
258
  command_lines('log', *arr_opts).map { |l| l.split.first }
223
259
  end
224
260
 
225
- def full_log_commits(opts={})
261
+ # Return the commits that are within the given revision range
262
+ #
263
+ # @see https://git-scm.com/docs/git-log git-log
264
+ #
265
+ # @param opts [Hash] the given options
266
+ #
267
+ # @option opts :count [Integer] the maximum number of commits to return (maps to max-count)
268
+ # @option opts :all [Boolean]
269
+ # @option opts :cherry [Boolean]
270
+ # @option opts :since [String]
271
+ # @option opts :until [String]
272
+ # @option opts :grep [String]
273
+ # @option opts :author [String]
274
+ # @option opts :between [Array<String>] an array of two commit-ish strings to specify a revision range
275
+ #
276
+ # Only :between or :object options can be used, not both.
277
+ #
278
+ # @option opts :object [String] the revision range for the git log command
279
+ #
280
+ # Only :between or :object options can be used, not both.
281
+ #
282
+ # @option opts :path_limiter [Array<String>, String] only include commits that impact files from the specified paths
283
+ # @option opts :skip [Integer]
284
+ #
285
+ # @return [Array<Hash>] the log output parsed into an array of hashs for each commit
286
+ #
287
+ # Each hash contains the following keys:
288
+ # * 'sha' [String] the commit sha
289
+ # * 'author' [String] the author of the commit
290
+ # * 'message' [String] the commit message
291
+ # * 'parent' [Array<String>] the commit shas of the parent commits
292
+ # * 'tree' [String] the tree sha
293
+ # * 'author' [String] the author of the commit and timestamp of when the changes were created
294
+ # * 'committer' [String] the committer of the commit and timestamp of when the commit was applied
295
+ #
296
+ # @raise [ArgumentError] if the revision range (specified with :between or :object) is a string starting with a hyphen
297
+ #
298
+ def full_log_commits(opts = {})
299
+ assert_args_are_not_options('between', opts[:between]&.first)
300
+ assert_args_are_not_options('object', opts[:object])
301
+
226
302
  arr_opts = log_common_options(opts)
227
303
 
228
304
  arr_opts << '--pretty=raw'
@@ -235,36 +311,147 @@ module Git
235
311
  process_commit_log_data(full_log)
236
312
  end
237
313
 
238
- def revparse(string)
239
- return string if string =~ /^[A-Fa-f0-9]{40}$/ # passing in a sha - just no-op it
240
- rev = ['head', 'remotes', 'tags'].map do |d|
241
- File.join(@git_dir, 'refs', d, string)
242
- end.find do |path|
243
- File.file?(path)
244
- end
245
- return File.read(rev).chomp if rev
246
- command('rev-parse', string)
314
+ # Verify and resolve a Git revision to its full SHA
315
+ #
316
+ # @see https://git-scm.com/docs/git-rev-parse git-rev-parse
317
+ # @see https://git-scm.com/docs/git-rev-parse#_specifying_revisions Valid ways to specify revisions
318
+ # @see https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt-emltrefnamegtemegemmasterememheadsmasterememrefsheadsmasterem Ref disambiguation rules
319
+ #
320
+ # @example
321
+ # lib.rev_parse('HEAD') # => '9b9b31e704c0b85ffdd8d2af2ded85170a5af87d'
322
+ # lib.rev_parse('9b9b31e') # => '9b9b31e704c0b85ffdd8d2af2ded85170a5af87d'
323
+ #
324
+ # @param revision [String] the revision to resolve
325
+ #
326
+ # @return [String] the full commit hash
327
+ #
328
+ # @raise [Git::FailedError] if the revision cannot be resolved
329
+ # @raise [ArgumentError] if the revision is a string starting with a hyphen
330
+ #
331
+ def rev_parse(revision)
332
+ assert_args_are_not_options('rev', revision)
333
+
334
+ command('rev-parse', revision)
247
335
  end
248
336
 
249
- def namerev(string)
250
- command('name-rev', string).split[1]
337
+ # For backwards compatibility with the old method name
338
+ alias :revparse :rev_parse
339
+
340
+ # Find the first symbolic name for given commit_ish
341
+ #
342
+ # @param commit_ish [String] the commit_ish to find the symbolic name of
343
+ #
344
+ # @return [String, nil] the first symbolic name or nil if the commit_ish isn't found
345
+ #
346
+ # @raise [ArgumentError] if the commit_ish is a string starting with a hyphen
347
+ #
348
+ def name_rev(commit_ish)
349
+ assert_args_are_not_options('commit_ish', commit_ish)
350
+
351
+ command('name-rev', commit_ish).split[1]
251
352
  end
252
353
 
253
- def object_type(sha)
254
- command('cat-file', '-t', sha)
354
+ alias :namerev :name_rev
355
+
356
+ # Output the contents or other properties of one or more objects.
357
+ #
358
+ # @see https://git-scm.com/docs/git-cat-file git-cat-file
359
+ #
360
+ # @example Get the contents of a file without a block
361
+ # lib.cat_file_contents('README.md') # => "This is a README file\n"
362
+ #
363
+ # @example Get the contents of a file with a block
364
+ # lib.cat_file_contents('README.md') { |f| f.read } # => "This is a README file\n"
365
+ #
366
+ # @param object [String] the object whose contents to return
367
+ #
368
+ # @return [String] the object contents
369
+ #
370
+ # @raise [ArgumentError] if object is a string starting with a hyphen
371
+ #
372
+ def cat_file_contents(object, &block)
373
+ assert_args_are_not_options('object', object)
374
+
375
+ if block_given?
376
+ Tempfile.create do |file|
377
+ # If a block is given, write the output from the process to a temporary
378
+ # file and then yield the file to the block
379
+ #
380
+ command('cat-file', "-p", object, out: file, err: file)
381
+ file.rewind
382
+ yield file
383
+ end
384
+ else
385
+ # If a block is not given, return the file contents as a string
386
+ command('cat-file', '-p', object)
387
+ end
255
388
  end
256
389
 
257
- def object_size(sha)
258
- command('cat-file', '-s', sha).to_i
390
+ alias :object_contents :cat_file_contents
391
+
392
+ # Get the type for the given object
393
+ #
394
+ # @see https://git-scm.com/docs/git-cat-file git-cat-file
395
+ #
396
+ # @param object [String] the object to get the type
397
+ #
398
+ # @return [String] the object type
399
+ #
400
+ # @raise [ArgumentError] if object is a string starting with a hyphen
401
+ #
402
+ def cat_file_type(object)
403
+ assert_args_are_not_options('object', object)
404
+
405
+ command('cat-file', '-t', object)
259
406
  end
260
407
 
261
- # returns useful array of raw commit object data
262
- def commit_data(sha)
263
- sha = sha.to_s
264
- cdata = command_lines('cat-file', 'commit', sha)
265
- process_commit_data(cdata, sha)
408
+ alias :object_type :cat_file_type
409
+
410
+ # Get the size for the given object
411
+ #
412
+ # @see https://git-scm.com/docs/git-cat-file git-cat-file
413
+ #
414
+ # @param object [String] the object to get the type
415
+ #
416
+ # @return [String] the object type
417
+ #
418
+ # @raise [ArgumentError] if object is a string starting with a hyphen
419
+ #
420
+ def cat_file_size(object)
421
+ assert_args_are_not_options('object', object)
422
+
423
+ command('cat-file', '-s', object).to_i
424
+ end
425
+
426
+ alias :object_size :cat_file_size
427
+
428
+ # Return a hash of commit data
429
+ #
430
+ # @see https://git-scm.com/docs/git-cat-file git-cat-file
431
+ #
432
+ # @param object [String] the object to get the type
433
+ #
434
+ # @return [Hash] commit data
435
+ #
436
+ # The returned commit data has the following keys:
437
+ # * tree [String]
438
+ # * parent [Array<String>]
439
+ # * author [String] the author name, email, and commit timestamp
440
+ # * committer [String] the committer name, email, and merge timestamp
441
+ # * message [String] the commit message
442
+ # * gpgsig [String] the public signing key of the commit (if signed)
443
+ #
444
+ # @raise [ArgumentError] if object is a string starting with a hyphen
445
+ #
446
+ def cat_file_commit(object)
447
+ assert_args_are_not_options('object', object)
448
+
449
+ cdata = command_lines('cat-file', 'commit', object)
450
+ process_commit_data(cdata, object)
266
451
  end
267
452
 
453
+ alias :commit_data :cat_file_commit
454
+
268
455
  def process_commit_data(data, sha)
269
456
  hsh = {
270
457
  'sha' => sha,
@@ -299,12 +486,50 @@ module Git
299
486
  end
300
487
  end
301
488
 
302
- def tag_data(name)
303
- sha = sha.to_s
304
- tdata = command_lines('cat-file', 'tag', name)
305
- process_tag_data(tdata, name)
489
+ # Return a hash of annotated tag data
490
+ #
491
+ # Does not work with lightweight tags. List all annotated tags in your repository with the following command:
492
+ #
493
+ # ```sh
494
+ # git for-each-ref --format='%(refname:strip=2)' refs/tags | while read tag; do git cat-file tag $tag >/dev/null 2>&1 && echo $tag; done
495
+ # ```
496
+ #
497
+ # @see https://git-scm.com/docs/git-cat-file git-cat-file
498
+ #
499
+ # @param object [String] the tag to retrieve
500
+ #
501
+ # @return [Hash] tag data
502
+ #
503
+ # Example tag data returned:
504
+ # ```ruby
505
+ # {
506
+ # "name" => "annotated_tag",
507
+ # "object" => "46abbf07e3c564c723c7c039a43ab3a39e5d02dd",
508
+ # "type" => "commit",
509
+ # "tag" => "annotated_tag",
510
+ # "tagger" => "Scott Chacon <schacon@gmail.com> 1724799270 -0700",
511
+ # "message" => "Creating an annotated tag\n"
512
+ # }
513
+ # ```
514
+ #
515
+ # The returned commit data has the following keys:
516
+ # * object [String] the sha of the tag object
517
+ # * type [String]
518
+ # * tag [String] tag name
519
+ # * tagger [String] the name and email of the user who created the tag and the timestamp of when the tag was created
520
+ # * message [String] the tag message
521
+ #
522
+ # @raise [ArgumentError] if object is a string starting with a hyphen
523
+ #
524
+ def cat_file_tag(object)
525
+ assert_args_are_not_options('object', object)
526
+
527
+ tdata = command_lines('cat-file', 'tag', object)
528
+ process_tag_data(tdata, object)
306
529
  end
307
530
 
531
+ alias :tag_data :cat_file_tag
532
+
308
533
  def process_tag_data(data, name)
309
534
  hsh = { 'name' => name }
310
535
 
@@ -358,26 +583,15 @@ module Git
358
583
  return hsh_array
359
584
  end
360
585
 
361
- def object_contents(sha, &block)
362
- if block_given?
363
- Tempfile.create do |file|
364
- # If a block is given, write the output from the process to a temporary
365
- # file and then yield the file to the block
366
- #
367
- command('cat-file', "-p", sha, out: file, err: file)
368
- file.rewind
369
- yield file
370
- end
371
- else
372
- # If a block is not given, return stdout
373
- command('cat-file', '-p', sha)
374
- end
375
- end
376
-
377
- def ls_tree(sha)
586
+ def ls_tree(sha, opts = {})
378
587
  data = { 'blob' => {}, 'tree' => {}, 'commit' => {} }
379
588
 
380
- command_lines('ls-tree', sha).each do |line|
589
+ ls_tree_opts = []
590
+ ls_tree_opts << '-r' if opts[:recursive]
591
+ # path must be last arg
592
+ ls_tree_opts << opts[:path] if opts[:path]
593
+
594
+ command_lines('ls-tree', sha, *ls_tree_opts).each do |line|
381
595
  (info, filenm) = line.split("\t")
382
596
  (mode, type, sha) = info.split
383
597
  data[type][filenm] = {:mode => mode, :sha => sha}
@@ -483,8 +697,54 @@ module Git
483
697
  files
484
698
  end
485
699
 
700
+ # The state and name of branch pointed to by `HEAD`
701
+ #
702
+ # HEAD can be in the following states:
703
+ #
704
+ # **:active**: `HEAD` points to a branch reference which in turn points to a
705
+ # commit representing the tip of that branch. This is the typical state when
706
+ # working on a branch.
707
+ #
708
+ # **:unborn**: `HEAD` points to a branch reference that does not yet exist
709
+ # because no commits have been made on that branch. This state occurs in two
710
+ # scenarios:
711
+ #
712
+ # * When a repository is newly initialized, and no commits have been made on the
713
+ # initial branch.
714
+ # * When a new branch is created using `git checkout --orphan <branch>`, starting
715
+ # a new branch with no history.
716
+ #
717
+ # **:detached**: `HEAD` points directly to a specific commit (identified by its
718
+ # SHA) rather than a branch reference. This state occurs when you check out a
719
+ # commit, a tag, or any state that is not directly associated with a branch. The
720
+ # branch name in this case is `HEAD`.
721
+ #
722
+ HeadState = Struct.new(:state, :name)
723
+
724
+ # The current branch state which is the state of `HEAD`
725
+ #
726
+ # @return [HeadState] the state and name of the current branch
727
+ #
728
+ def current_branch_state
729
+ branch_name = command('branch', '--show-current')
730
+ return HeadState.new(:detached, 'HEAD') if branch_name.empty?
731
+
732
+ state =
733
+ begin
734
+ command('rev-parse', '--verify', '--quiet', branch_name)
735
+ :active
736
+ rescue Git::FailedError => e
737
+ raise unless e.result.status.exitstatus == 1 && e.result.stderr.empty?
738
+
739
+ :unborn
740
+ end
741
+
742
+ return HeadState.new(state, branch_name)
743
+ end
744
+
486
745
  def branch_current
487
- branches_all.select { |b| b[1] }.first[0] rescue nil
746
+ branch_name = command('branch', '--show-current')
747
+ branch_name.empty? ? 'HEAD' : branch_name
488
748
  end
489
749
 
490
750
  def branch_contains(commit, branch_name="")
@@ -521,7 +781,24 @@ module Git
521
781
  hsh
522
782
  end
523
783
 
784
+ # Validate that the given arguments cannot be mistaken for a command-line option
785
+ #
786
+ # @param arg_name [String] the name of the arguments to mention in the error message
787
+ # @param args [Array<String, nil>] the arguments to validate
788
+ #
789
+ # @raise [ArgumentError] if any of the parameters are a string starting with a hyphen
790
+ # @return [void]
791
+ #
792
+ def assert_args_are_not_options(arg_name, *args)
793
+ invalid_args = args.select { |arg| arg&.start_with?('-') }
794
+ if invalid_args.any?
795
+ raise ArgumentError, "Invalid #{arg_name}: '#{invalid_args.join("', '")}'"
796
+ end
797
+ end
798
+
524
799
  def diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})
800
+ assert_args_are_not_options('commit or commit range', obj1, obj2)
801
+
525
802
  diff_opts = ['-p']
526
803
  diff_opts << obj1
527
804
  diff_opts << obj2 if obj2.is_a?(String)
@@ -531,6 +808,8 @@ module Git
531
808
  end
532
809
 
533
810
  def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
811
+ assert_args_are_not_options('commit or commit range', obj1, obj2)
812
+
534
813
  diff_opts = ['--numstat']
535
814
  diff_opts << obj1
536
815
  diff_opts << obj2 if obj2.is_a?(String)
@@ -551,6 +830,8 @@ module Git
551
830
  end
552
831
 
553
832
  def diff_name_status(reference1 = nil, reference2 = nil, opts = {})
833
+ assert_args_are_not_options('commit or commit range', reference1, reference2)
834
+
554
835
  opts_arr = ['--name-status']
555
836
  opts_arr << reference1 if reference1
556
837
  opts_arr << reference2 if reference2
data/lib/git/object.rb CHANGED
@@ -23,11 +23,11 @@ module Git
23
23
  end
24
24
 
25
25
  def sha
26
- @sha ||= @base.lib.revparse(@objectish)
26
+ @sha ||= @base.lib.rev_parse(@objectish)
27
27
  end
28
28
 
29
29
  def size
30
- @size ||= @base.lib.object_size(@objectish)
30
+ @size ||= @base.lib.cat_file_size(@objectish)
31
31
  end
32
32
 
33
33
  # Get the object's contents.
@@ -38,9 +38,9 @@ module Git
38
38
  # Use this for large files so that they are not held in memory.
39
39
  def contents(&block)
40
40
  if block_given?
41
- @base.lib.object_contents(@objectish, &block)
41
+ @base.lib.cat_file_contents(@objectish, &block)
42
42
  else
43
- @contents ||= @base.lib.object_contents(@objectish)
43
+ @contents ||= @base.lib.cat_file_contents(@objectish)
44
44
  end
45
45
  end
46
46
 
@@ -175,7 +175,7 @@ module Git
175
175
  end
176
176
 
177
177
  def name
178
- @base.lib.namerev(sha)
178
+ @base.lib.name_rev(sha)
179
179
  end
180
180
 
181
181
  def gtree
@@ -237,7 +237,7 @@ module Git
237
237
  def check_commit
238
238
  return if @tree
239
239
 
240
- data = @base.lib.commit_data(@objectish)
240
+ data = @base.lib.cat_file_commit(@objectish)
241
241
  set_commit(data)
242
242
  end
243
243
 
@@ -254,7 +254,7 @@ module Git
254
254
  end
255
255
 
256
256
  def annotated?
257
- @annotated ||= (@base.lib.object_type(self.name) == 'tag')
257
+ @annotated ||= (@base.lib.cat_file_type(self.name) == 'tag')
258
258
  end
259
259
 
260
260
  def message
@@ -279,7 +279,7 @@ module Git
279
279
  if !self.annotated?
280
280
  @message = @tagger = nil
281
281
  else
282
- tdata = @base.lib.tag_data(@name)
282
+ tdata = @base.lib.cat_file_tag(@name)
283
283
  @message = tdata['message'].chomp
284
284
  @tagger = Git::Author.new(tdata['tagger'])
285
285
  end
@@ -300,7 +300,7 @@ module Git
300
300
  return Git::Object::Tag.new(base, sha, objectish)
301
301
  end
302
302
 
303
- type ||= base.lib.object_type(objectish)
303
+ type ||= base.lib.cat_file_type(objectish)
304
304
  klass =
305
305
  case type
306
306
  when /blob/ then Blob
data/lib/git/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Git
2
2
  # The current gem version
3
3
  # @return [String] the current gem version.
4
- VERSION='2.1.1'
4
+ VERSION='2.3.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Chacon and others
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-01 00:00:00.000000000 Z
11
+ date: 2024-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -243,8 +243,8 @@ licenses:
243
243
  metadata:
244
244
  homepage_uri: http://github.com/ruby-git/ruby-git
245
245
  source_code_uri: http://github.com/ruby-git/ruby-git
246
- changelog_uri: https://rubydoc.info/gems/git/2.1.1/file/CHANGELOG.md
247
- documentation_uri: https://rubydoc.info/gems/git/2.1.1
246
+ changelog_uri: https://rubydoc.info/gems/git/2.3.0/file/CHANGELOG.md
247
+ documentation_uri: https://rubydoc.info/gems/git/2.3.0
248
248
  post_install_message:
249
249
  rdoc_options: []
250
250
  require_paths: