git 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf601afe6ddef5cc504f0a350bd9595feb76cc95822bd65716d6b5cecf2d324d
4
- data.tar.gz: 5f334a391220774ab0fea9c789a87fe3a45d9de55e0745d87f59c0bc9a52e5a9
3
+ metadata.gz: bfdec3b45e4e9b00ce87e37026c6b8fe81c306fdc7c127f01e1e682a8655986c
4
+ data.tar.gz: 3273f3eb91ab29af0143f1c5e0e5548bbc4e4575bc0a2a8ad4c6faa7cca3252b
5
5
  SHA512:
6
- metadata.gz: 20133b00f0f50ccc00dc1bd4bb88107911ff5f438e127b804270752c43029e2447b15a5212c701a24a49a6f98d7b12359cb3326924ea3dadf631408b316e626e
7
- data.tar.gz: 11ca7ae94de18e0b3d4aad99d315c2b973a8e2521ee24a935e5236fdc91eace943074ad388889a09ef4d8e33e2a4b1355d2590fe16fe0a1eda05357e1a315290
6
+ metadata.gz: 137c05e180c79fc9b3e2810c1fb67a7a9304c365bf7ea445788cbf392c4e0bfadc04d91871e5f1aaf93db8c457b08b55487043abeff0e6a986fc1f812712ffe4
7
+ data.tar.gz: 8e7c483a7d5b8699cc48f523678e2d5b586b51fd900ca3a9f5ca3535d3fe9ce3275e449345783de6f5b2656f620dc81225595b17a7881946319c867b089f6d22
data/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@
5
5
 
6
6
  # Change Log
7
7
 
8
+ ## v2.2.0 (2024-08-26)
9
+
10
+ [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.1.1..v2.2.0)
11
+
12
+ Changes since v2.1.1:
13
+
14
+ * 7292f2c Omit the test for signed commit data on Windows
15
+ * 2d6157c Document this gem's (aspirational) design philosophy
16
+ * d4f66ab Sanitize non-option arguments passed to `git name-rev`
17
+ * 0296442 Refactor Git::Lib#rev_parse
18
+ * 9b9b31e Verify that the revision-range passed to git log does not resemble a command-line option
19
+ * dc46ede Verify that the commit-ish passed to git describe does not resemble a command-line option
20
+ * 00c4939 Verify that the commit(s) passed to git diff do not resemble a command-line option
21
+ * a08f89b Update README
22
+ * 737c4bb ls-tree optional recursion into subtrees
23
+
24
+ ## v2.1.1 (2024-06-01)
25
+
26
+ [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.1.0..v2.1.1)
27
+
28
+ Changes since v2.1.0:
29
+
30
+ * 6ce3d4d Handle ignored files with quoted (non-ASCII) filenames
31
+ * dd8e8d4 Supply all of the _specific_ color options too
32
+ * 749a72d Memoize all of the significant calls in Git::Status
33
+ * 2bacccc When core.ignoreCase, check for untracked files case-insensitively
34
+ * 7758ee4 When core.ignoreCase, check for deleted files case-insensitively
35
+ * 993eb78 When core.ignoreCase, check for added files case-insensitively
36
+ * d943bf4 When core.ignoreCase, check for changed files case-insensitively
37
+
8
38
  ## v2.1.0 (2024-05-31)
9
39
 
10
40
  [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.0.1..v2.1.0)
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
@@ -309,6 +309,13 @@ module Git
309
309
  self.object('HEAD').grep(string, path_limiter, opts)
310
310
  end
311
311
 
312
+ # List the files in the worktree that are ignored by git
313
+ # @return [Array<String>] the list of ignored files relative to teh root of the worktree
314
+ #
315
+ def ignored_files
316
+ self.lib.ignored_files
317
+ end
318
+
312
319
  # removes file(s) from the git repository
313
320
  def rm(path = '.', opts = {})
314
321
  self.lib.rm(path, opts)
@@ -627,16 +634,19 @@ module Git
627
634
  # runs git rev-parse to convert the objectish to a full sha
628
635
  #
629
636
  # @example
630
- # git.revparse("HEAD^^")
631
- # git.revparse('v2.4^{tree}')
632
- # 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')
633
640
  #
634
- def revparse(objectish)
635
- self.lib.revparse(objectish)
641
+ def rev_parse(objectish)
642
+ self.lib.rev_parse(objectish)
636
643
  end
637
644
 
638
- def ls_tree(objectish)
639
- 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)
640
650
  end
641
651
 
642
652
  def cat_file(objectish)
@@ -3,7 +3,7 @@
3
3
  module Git
4
4
  # Represents an escaped Git path string
5
5
  #
6
- # Git commands that output paths (e.g. ls-files, diff), will escape usual
6
+ # Git commands that output paths (e.g. ls-files, diff), will escape unusual
7
7
  # characters in the path with backslashes in the same way C escapes control
8
8
  # characters (e.g. \t for TAB, \n for LF, \\ for backslash) or bytes with values
9
9
  # larger than 0x80 (e.g. octal \302\265 for "micro" in UTF-8).
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,21 +311,48 @@ 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
 
354
+ alias :namerev :name_rev
355
+
253
356
  def object_type(sha)
254
357
  command('cat-file', '-t', sha)
255
358
  end
@@ -374,10 +477,15 @@ module Git
374
477
  end
375
478
  end
376
479
 
377
- def ls_tree(sha)
480
+ def ls_tree(sha, opts = {})
378
481
  data = { 'blob' => {}, 'tree' => {}, 'commit' => {} }
379
482
 
380
- command_lines('ls-tree', sha).each do |line|
483
+ ls_tree_opts = []
484
+ ls_tree_opts << '-r' if opts[:recursive]
485
+ # path must be last arg
486
+ ls_tree_opts << opts[:path] if opts[:path]
487
+
488
+ command_lines('ls-tree', sha, *ls_tree_opts).each do |line|
381
489
  (info, filenm) = line.split("\t")
382
490
  (mode, type, sha) = info.split
383
491
  data[type][filenm] = {:mode => mode, :sha => sha}
@@ -521,7 +629,24 @@ module Git
521
629
  hsh
522
630
  end
523
631
 
632
+ # Validate that the given arguments cannot be mistaken for a command-line option
633
+ #
634
+ # @param arg_name [String] the name of the arguments to mention in the error message
635
+ # @param args [Array<String, nil>] the arguments to validate
636
+ #
637
+ # @raise [ArgumentError] if any of the parameters are a string starting with a hyphen
638
+ # @return [void]
639
+ #
640
+ def assert_args_are_not_options(arg_name, *args)
641
+ invalid_args = args.select { |arg| arg&.start_with?('-') }
642
+ if invalid_args.any?
643
+ raise ArgumentError, "Invalid #{arg_name}: '#{invalid_args.join("', '")}'"
644
+ end
645
+ end
646
+
524
647
  def diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})
648
+ assert_args_are_not_options('commit or commit range', obj1, obj2)
649
+
525
650
  diff_opts = ['-p']
526
651
  diff_opts << obj1
527
652
  diff_opts << obj2 if obj2.is_a?(String)
@@ -531,6 +656,8 @@ module Git
531
656
  end
532
657
 
533
658
  def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
659
+ assert_args_are_not_options('commit or commit range', obj1, obj2)
660
+
534
661
  diff_opts = ['--numstat']
535
662
  diff_opts << obj1
536
663
  diff_opts << obj2 if obj2.is_a?(String)
@@ -551,6 +678,8 @@ module Git
551
678
  end
552
679
 
553
680
  def diff_name_status(reference1 = nil, reference2 = nil, opts = {})
681
+ assert_args_are_not_options('commit or commit range', reference1, reference2)
682
+
554
683
  opts_arr = ['--name-status']
555
684
  opts_arr << reference1 if reference1
556
685
  opts_arr << reference2 if reference2
@@ -574,18 +703,52 @@ module Git
574
703
  diff_as_hash('diff-index', treeish)
575
704
  end
576
705
 
706
+ # List all files that are in the index
707
+ #
708
+ # @param location [String] the location to list the files from
709
+ #
710
+ # @return [Hash<String, Hash>] a hash of files in the index
711
+ # * key: file [String] the file path
712
+ # * value: file_info [Hash] the file information containing the following keys:
713
+ # * :path [String] the file path
714
+ # * :mode_index [String] the file mode
715
+ # * :sha_index [String] the file sha
716
+ # * :stage [String] the file stage
717
+ #
577
718
  def ls_files(location=nil)
578
719
  location ||= '.'
579
- hsh = {}
580
- command_lines('ls-files', '--stage', location).each do |line|
581
- (info, file) = line.split("\t")
582
- (mode, sha, stage) = info.split
583
- if file.start_with?('"') && file.end_with?('"')
584
- file = Git::EscapedPath.new(file[1..-2]).unescape
720
+ {}.tap do |files|
721
+ command_lines('ls-files', '--stage', location).each do |line|
722
+ (info, file) = line.split("\t")
723
+ (mode, sha, stage) = info.split
724
+ files[unescape_quoted_path(file)] = {
725
+ :path => file, :mode_index => mode, :sha_index => sha, :stage => stage
726
+ }
585
727
  end
586
- hsh[file] = {:path => file, :mode_index => mode, :sha_index => sha, :stage => stage}
587
728
  end
588
- hsh
729
+ end
730
+
731
+ # Unescape a path if it is quoted
732
+ #
733
+ # Git commands that output paths (e.g. ls-files, diff), will escape unusual
734
+ # characters.
735
+ #
736
+ # @example
737
+ # lib.unescape_if_quoted('"quoted_file_\\342\\230\\240"') # => 'quoted_file_☠'
738
+ # lib.unescape_if_quoted('unquoted_file') # => 'unquoted_file'
739
+ #
740
+ # @param path [String] the path to unescape if quoted
741
+ #
742
+ # @return [String] the unescaped path if quoted otherwise the original path
743
+ #
744
+ # @api private
745
+ #
746
+ def unescape_quoted_path(path)
747
+ if path.start_with?('"') && path.end_with?('"')
748
+ Git::EscapedPath.new(path[1..-2]).unescape
749
+ else
750
+ path
751
+ end
589
752
  end
590
753
 
591
754
  def ls_remote(location=nil, opts={})
@@ -606,7 +769,7 @@ module Git
606
769
  end
607
770
 
608
771
  def ignored_files
609
- command_lines('ls-files', '--others', '-i', '--exclude-standard')
772
+ command_lines('ls-files', '--others', '-i', '--exclude-standard').map { |f| unescape_quoted_path(f) }
610
773
  end
611
774
 
612
775
  def untracked_files
@@ -1223,6 +1386,14 @@ module Git
1223
1386
  global_opts << "--work-tree=#{@git_work_dir}" if !@git_work_dir.nil?
1224
1387
  global_opts << '-c' << 'core.quotePath=true'
1225
1388
  global_opts << '-c' << 'color.ui=false'
1389
+ global_opts << '-c' << 'color.advice=false'
1390
+ global_opts << '-c' << 'color.diff=false'
1391
+ global_opts << '-c' << 'color.grep=false'
1392
+ global_opts << '-c' << 'color.push=false'
1393
+ global_opts << '-c' << 'color.remote=false'
1394
+ global_opts << '-c' << 'color.showBranch=false'
1395
+ global_opts << '-c' << 'color.status=false'
1396
+ global_opts << '-c' << 'color.transport=false'
1226
1397
  end
1227
1398
  end
1228
1399
 
data/lib/git/object.rb CHANGED
@@ -23,7 +23,7 @@ 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
@@ -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
data/lib/git/status.rb CHANGED
@@ -22,7 +22,7 @@ module Git
22
22
  #
23
23
  # @return [Enumerable]
24
24
  def changed
25
- @files.select { |_k, f| f.type == 'M' }
25
+ @_changed ||= @files.select { |_k, f| f.type == 'M' }
26
26
  end
27
27
 
28
28
  #
@@ -34,7 +34,7 @@ module Git
34
34
  # changed?('lib/git.rb')
35
35
  # @return [Boolean]
36
36
  def changed?(file)
37
- changed.member?(file)
37
+ case_aware_include?(:changed, :lc_changed, file)
38
38
  end
39
39
 
40
40
  # Returns an Enumerable containing files that have been added.
@@ -42,7 +42,7 @@ module Git
42
42
  #
43
43
  # @return [Enumerable]
44
44
  def added
45
- @files.select { |_k, f| f.type == 'A' }
45
+ @_added ||= @files.select { |_k, f| f.type == 'A' }
46
46
  end
47
47
 
48
48
  # Determines whether the given file has been added to the repository
@@ -54,7 +54,7 @@ module Git
54
54
  # added?('lib/git.rb')
55
55
  # @return [Boolean]
56
56
  def added?(file)
57
- added.member?(file)
57
+ case_aware_include?(:added, :lc_added, file)
58
58
  end
59
59
 
60
60
  #
@@ -63,7 +63,7 @@ module Git
63
63
  #
64
64
  # @return [Enumerable]
65
65
  def deleted
66
- @files.select { |_k, f| f.type == 'D' }
66
+ @_deleted ||= @files.select { |_k, f| f.type == 'D' }
67
67
  end
68
68
 
69
69
  #
@@ -75,7 +75,7 @@ module Git
75
75
  # deleted?('lib/git.rb')
76
76
  # @return [Boolean]
77
77
  def deleted?(file)
78
- deleted.member?(file)
78
+ case_aware_include?(:deleted, :lc_deleted, file)
79
79
  end
80
80
 
81
81
  #
@@ -84,7 +84,7 @@ module Git
84
84
  #
85
85
  # @return [Enumerable]
86
86
  def untracked
87
- @files.select { |_k, f| f.untracked }
87
+ @_untracked ||= @files.select { |_k, f| f.untracked }
88
88
  end
89
89
 
90
90
  #
@@ -96,7 +96,7 @@ module Git
96
96
  # untracked?('lib/git.rb')
97
97
  # @return [Boolean]
98
98
  def untracked?(file)
99
- untracked.member?(file)
99
+ case_aware_include?(:untracked, :lc_untracked, file)
100
100
  end
101
101
 
102
102
  def pretty
@@ -264,5 +264,43 @@ module Git
264
264
  end
265
265
  end
266
266
  end
267
+
268
+ # It's worth noting that (like git itself) this gem will not behave well if
269
+ # ignoreCase is set inconsistently with the file-system itself. For details:
270
+ # https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreignoreCase
271
+ def ignore_case?
272
+ return @_ignore_case if defined?(@_ignore_case)
273
+ @_ignore_case = @base.config('core.ignoreCase') == 'true'
274
+ rescue Git::FailedError
275
+ @_ignore_case = false
276
+ end
277
+
278
+ def downcase_keys(hash)
279
+ hash.map { |k, v| [k.downcase, v] }.to_h
280
+ end
281
+
282
+ def lc_changed
283
+ @_lc_changed ||= changed.transform_keys(&:downcase)
284
+ end
285
+
286
+ def lc_added
287
+ @_lc_added ||= added.transform_keys(&:downcase)
288
+ end
289
+
290
+ def lc_deleted
291
+ @_lc_deleted ||= deleted.transform_keys(&:downcase)
292
+ end
293
+
294
+ def lc_untracked
295
+ @_lc_untracked ||= untracked.transform_keys(&:downcase)
296
+ end
297
+
298
+ def case_aware_include?(cased_hash, downcased_hash, file)
299
+ if ignore_case?
300
+ send(downcased_hash).include?(file.downcase)
301
+ else
302
+ send(cased_hash).include?(file)
303
+ end
304
+ end
267
305
  end
268
306
  end
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.0'
4
+ VERSION='2.2.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.0
4
+ version: 2.2.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-05-31 00:00:00.000000000 Z
11
+ date: 2024-08-26 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.0/file/CHANGELOG.md
247
- documentation_uri: https://rubydoc.info/gems/git/2.1.0
246
+ changelog_uri: https://rubydoc.info/gems/git/2.2.0/file/CHANGELOG.md
247
+ documentation_uri: https://rubydoc.info/gems/git/2.2.0
248
248
  post_install_message:
249
249
  rdoc_options: []
250
250
  require_paths: