git 1.19.1 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/pull_request_template.md +8 -0
- data/.github/workflows/continuous_integration.yml +14 -20
- data/.github/workflows/experimental_continuous_integration.yml +43 -0
- data/CHANGELOG.md +88 -0
- data/CONTRIBUTING.md +22 -67
- data/README.md +166 -52
- data/RELEASING.md +49 -34
- data/git.gemspec +8 -8
- data/lib/git/base.rb +173 -47
- data/lib/git/command_line.rb +377 -0
- data/lib/git/config.rb +5 -1
- data/lib/git/errors.rb +206 -0
- data/lib/git/escaped_path.rb +1 -1
- data/lib/git/lib.rb +244 -177
- data/lib/git/log.rb +65 -4
- data/lib/git/object.rb +69 -67
- data/lib/git/status.rb +132 -24
- data/lib/git/version.rb +1 -1
- data/lib/git.rb +8 -7
- metadata +41 -30
- data/.github/stale.yml +0 -25
- data/Dockerfile.changelog-rs +0 -12
- data/PULL_REQUEST_TEMPLATE.md +0 -9
- data/lib/git/base/factory.rb +0 -99
- data/lib/git/failed_error.rb +0 -53
- data/lib/git/git_execute_error.rb +0 -7
- data/lib/git/signaled_error.rb +0 -50
- /data/{ISSUE_TEMPLATE.md → .github/issue_template.md} +0 -0
data/RELEASING.md
CHANGED
@@ -7,64 +7,79 @@
|
|
7
7
|
|
8
8
|
Releasing a new version of the `git` gem requires these steps:
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
These instructions use an example where:
|
17
|
-
|
18
|
-
- The default branch is `master`
|
19
|
-
- The current release version is `1.5.0`
|
20
|
-
- You want to create a new *minor* release, `1.6.0`
|
10
|
+
* [Install Prerequisites](#install-prerequisites)
|
11
|
+
* [Determine the SemVer release type](#determine-the-semver-release-type)
|
12
|
+
* [Create the release](#create-the-release)
|
13
|
+
* [Review the CHANGELOG and release PR](#review-the-changelog-and-release-pr)
|
14
|
+
* [Manually merge the release PR](#manually-merge-the-release-pr)
|
15
|
+
* [Publish the git gem to RubyGems.org](#publish-the-git-gem-to-rubygemsorg)
|
21
16
|
|
22
17
|
## Install Prerequisites
|
23
18
|
|
24
19
|
The following tools need to be installed in order to create the release:
|
25
20
|
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
* [create_githhub_release](https://github.com/main-branch/create_github_release) is used to create the release
|
22
|
+
* [git](https://git-scm.com) is used by `create-github-release` to interact with the local and remote repositories
|
23
|
+
* [gh](https://cli.github.com) is used by `create-github-release` to create the release and PR in GitHub
|
29
24
|
|
30
|
-
On a Mac, these tools can be installed using [brew](https://brew.sh):
|
25
|
+
On a Mac, these tools can be installed using [gem](https://guides.rubygems.org/rubygems-basics/) and [brew](https://brew.sh):
|
31
26
|
|
32
27
|
```shell
|
28
|
+
$ gem install create_github_release
|
29
|
+
...
|
33
30
|
$ brew install git
|
34
31
|
...
|
35
32
|
$ brew install gh
|
36
33
|
...
|
37
|
-
$ brew install --cask docker
|
38
|
-
...
|
39
34
|
$
|
40
35
|
```
|
41
36
|
|
42
|
-
##
|
37
|
+
## Determine the SemVer release type
|
43
38
|
|
44
|
-
|
39
|
+
Determine the SemVer version increment that should be applied for the new release:
|
45
40
|
|
46
|
-
|
41
|
+
* `major`: when the release includes incompatible API or functional changes.
|
42
|
+
* `minor`: when the release adds functionality in a backward-compatible manner
|
43
|
+
* `patch`: when the release includes small user-facing changes that are
|
44
|
+
backward-compatible and do not introduce new functionality.
|
47
45
|
|
48
|
-
|
49
|
-
- Install development dependencies using bundle `bundle install`
|
50
|
-
- Based upon the nature of the changes, decide on the type of release: `major`, `minor`, or `patch` (in this example we will use `minor`)
|
51
|
-
- Run the release script `bundle exec create-github-release minor`
|
46
|
+
## Create the release
|
52
47
|
|
53
|
-
|
48
|
+
Create the release using the `create-github-release` command. If the release type
|
49
|
+
is `major`, the command is:
|
54
50
|
|
55
|
-
|
51
|
+
```shell
|
52
|
+
create-github-release major
|
53
|
+
```
|
56
54
|
|
57
|
-
|
55
|
+
Follow the directions given by the `create-github-release` command to finish the
|
56
|
+
release. Where the instructions given by the command differ than the instructions
|
57
|
+
below, follow the instructions given by the command.
|
58
58
|
|
59
|
-
|
59
|
+
## Review the CHANGELOG and release PR
|
60
60
|
|
61
|
-
-
|
62
|
-
|
61
|
+
The `create-github-release` command will output a link to the CHANGELOG and the PR
|
62
|
+
it created for the release. Review the CHANGELOG and have someone review and approve
|
63
|
+
the release PR.
|
63
64
|
|
64
|
-
##
|
65
|
+
## Manually merge the release PR
|
65
66
|
|
66
|
-
|
67
|
+
It is important to manually merge the PR so a separate merge commit can be avoided.
|
68
|
+
Use the commands output by the `create-github-release` which will looks like this
|
69
|
+
if you are creating a 2.0.0 release:
|
67
70
|
|
68
|
-
|
71
|
+
```shell
|
72
|
+
git checkout master
|
73
|
+
git merge --ff-only release-v2.0.0
|
74
|
+
git push
|
75
|
+
```
|
76
|
+
|
77
|
+
This will automatically close the release PR.
|
78
|
+
|
79
|
+
## Publish the git gem to RubyGems.org
|
69
80
|
|
70
|
-
|
81
|
+
Finally, publish the git gem to RubyGems.org using the following command:
|
82
|
+
|
83
|
+
```shell
|
84
|
+
rake release:rubygem_push
|
85
|
+
```
|
data/git.gemspec
CHANGED
@@ -24,22 +24,22 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{s.name}/#{s.version}"
|
25
25
|
|
26
26
|
s.require_paths = ['lib']
|
27
|
-
s.required_ruby_version = '>=
|
28
|
-
s.
|
29
|
-
s.requirements = ['git 1.6.0.0, or greater']
|
27
|
+
s.required_ruby_version = '>= 3.0.0'
|
28
|
+
s.requirements = ['git 2.28.0 or greater']
|
30
29
|
|
30
|
+
s.add_runtime_dependency 'activesupport', '>= 5.0'
|
31
31
|
s.add_runtime_dependency 'addressable', '~> 2.8'
|
32
|
+
s.add_runtime_dependency 'process_executer', '~> 1.1'
|
32
33
|
s.add_runtime_dependency 'rchardet', '~> 1.8'
|
33
34
|
|
34
|
-
s.add_development_dependency '
|
35
|
-
s.add_development_dependency 'create_github_release', '~> 0.2'
|
35
|
+
s.add_development_dependency 'create_github_release', '~> 1.4'
|
36
36
|
s.add_development_dependency 'minitar', '~> 0.9'
|
37
37
|
s.add_development_dependency 'mocha', '~> 2.1'
|
38
|
-
s.add_development_dependency 'rake', '~> 13.
|
39
|
-
s.add_development_dependency 'test-unit', '~> 3.
|
38
|
+
s.add_development_dependency 'rake', '~> 13.1'
|
39
|
+
s.add_development_dependency 'test-unit', '~> 3.6'
|
40
40
|
|
41
41
|
unless RUBY_PLATFORM == 'java'
|
42
|
-
s.add_development_dependency 'redcarpet', '~> 3.
|
42
|
+
s.add_development_dependency 'redcarpet', '~> 3.6'
|
43
43
|
s.add_development_dependency 'yard', '~> 0.9', '>= 0.9.28'
|
44
44
|
s.add_development_dependency 'yardstick', '~> 0.9'
|
45
45
|
end
|
data/lib/git/base.rb
CHANGED
@@ -1,17 +1,16 @@
|
|
1
|
-
require 'git/base/factory'
|
2
1
|
require 'logger'
|
3
2
|
require 'open3'
|
4
3
|
|
5
4
|
module Git
|
6
|
-
#
|
5
|
+
# The main public interface for interacting with Git commands
|
7
6
|
#
|
8
7
|
# Instead of creating a Git::Base directly, obtain a Git::Base instance by
|
9
8
|
# calling one of the follow {Git} class methods: {Git.open}, {Git.init},
|
10
9
|
# {Git.clone}, or {Git.bare}.
|
11
10
|
#
|
11
|
+
# @api public
|
12
|
+
#
|
12
13
|
class Base
|
13
|
-
include Git::Base::Factory
|
14
|
-
|
15
14
|
# (see Git.bare)
|
16
15
|
def self.bare(git_dir, options = {})
|
17
16
|
normalize_paths(options, default_repository: git_dir, bare: true)
|
@@ -122,6 +121,62 @@ module Git
|
|
122
121
|
@index = options[:index] ? Git::Index.new(options[:index], false) : nil
|
123
122
|
end
|
124
123
|
|
124
|
+
# Update the index from the current worktree to prepare the for the next commit
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
# lib.add('path/to/file')
|
128
|
+
# lib.add(['path/to/file1','path/to/file2'])
|
129
|
+
# lib.add(all: true)
|
130
|
+
#
|
131
|
+
# @param [String, Array<String>] paths a file or files to be added to the repository (relative to the worktree root)
|
132
|
+
# @param [Hash] options
|
133
|
+
#
|
134
|
+
# @option options [Boolean] :all Add, modify, and remove index entries to match the worktree
|
135
|
+
# @option options [Boolean] :force Allow adding otherwise ignored files
|
136
|
+
#
|
137
|
+
def add(paths = '.', **options)
|
138
|
+
self.lib.add(paths, options)
|
139
|
+
end
|
140
|
+
|
141
|
+
# adds a new remote to this repository
|
142
|
+
# url can be a git url or a Git::Base object if it's a local reference
|
143
|
+
#
|
144
|
+
# @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git')
|
145
|
+
# @git.fetch('scotts_git')
|
146
|
+
# @git.merge('scotts_git/master')
|
147
|
+
#
|
148
|
+
# Options:
|
149
|
+
# :fetch => true
|
150
|
+
# :track => <branch_name>
|
151
|
+
def add_remote(name, url, opts = {})
|
152
|
+
url = url.repo.path if url.is_a?(Git::Base)
|
153
|
+
self.lib.remote_add(name, url, opts)
|
154
|
+
Git::Remote.new(self, name)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Create a new git tag
|
158
|
+
#
|
159
|
+
# @example
|
160
|
+
# repo.add_tag('tag_name', object_reference)
|
161
|
+
# repo.add_tag('tag_name', object_reference, {:options => 'here'})
|
162
|
+
# repo.add_tag('tag_name', {:options => 'here'})
|
163
|
+
#
|
164
|
+
# @param [String] name The name of the tag to add
|
165
|
+
# @param [Hash] options Opstions to pass to `git tag`.
|
166
|
+
# See [git-tag](https://git-scm.com/docs/git-tag) for more details.
|
167
|
+
# @option options [boolean] :annotate Make an unsigned, annotated tag object
|
168
|
+
# @option options [boolean] :a An alias for the `:annotate` option
|
169
|
+
# @option options [boolean] :d Delete existing tag with the given names.
|
170
|
+
# @option options [boolean] :f Replace an existing tag with the given name (instead of failing)
|
171
|
+
# @option options [String] :message Use the given tag message
|
172
|
+
# @option options [String] :m An alias for the `:message` option
|
173
|
+
# @option options [boolean] :s Make a GPG-signed tag.
|
174
|
+
#
|
175
|
+
def add_tag(name, *options)
|
176
|
+
self.lib.tag(name, *options)
|
177
|
+
self.tag(name)
|
178
|
+
end
|
179
|
+
|
125
180
|
# changes current working directory for a block
|
126
181
|
# to the git working directory
|
127
182
|
#
|
@@ -254,27 +309,11 @@ module Git
|
|
254
309
|
self.object('HEAD').grep(string, path_limiter, opts)
|
255
310
|
end
|
256
311
|
|
257
|
-
#
|
258
|
-
#
|
259
|
-
# @example
|
260
|
-
# git.add
|
261
|
-
# git.add('path/to/file')
|
262
|
-
# git.add(['path/to/file1','path/to/file2'])
|
263
|
-
# git.add(:all => true)
|
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
|
264
314
|
#
|
265
|
-
|
266
|
-
|
267
|
-
#
|
268
|
-
# @param [String,Array] paths files paths to be added (optional, default='.')
|
269
|
-
# @param [Hash] options
|
270
|
-
# @option options [boolean] :all
|
271
|
-
# Update the index not only where the working tree has a file matching
|
272
|
-
# <pathspec> but also where the index already has an entry.
|
273
|
-
# See [the --all option to git-add](https://git-scm.com/docs/git-add#Documentation/git-add.txt--A)
|
274
|
-
# for more details.
|
275
|
-
#
|
276
|
-
def add(paths = '.', **options)
|
277
|
-
self.lib.add(paths, options)
|
315
|
+
def ignored_files
|
316
|
+
self.lib.ignored_files
|
278
317
|
end
|
279
318
|
|
280
319
|
# removes file(s) from the git repository
|
@@ -409,14 +448,27 @@ module Git
|
|
409
448
|
self.lib.conflicts(&block)
|
410
449
|
end
|
411
450
|
|
412
|
-
#
|
451
|
+
# Pulls the given branch from the given remote into the current branch
|
452
|
+
#
|
453
|
+
# @param remote [String] the remote repository to pull from
|
454
|
+
# @param branch [String] the branch to pull from
|
455
|
+
# @param opts [Hash] options to pass to the pull command
|
413
456
|
#
|
414
|
-
#
|
415
|
-
#
|
416
|
-
#
|
457
|
+
# @option opts [Boolean] :allow_unrelated_histories (false) Merges histories of two projects that started their
|
458
|
+
# lives independently
|
459
|
+
# @example pulls from origin/master
|
460
|
+
# @git.pull
|
461
|
+
# @example pulls from upstream/master
|
462
|
+
# @git.pull('upstream')
|
463
|
+
# @example pulls from upstream/develop
|
464
|
+
# @git.pull('upstream', 'develop')
|
417
465
|
#
|
418
|
-
|
419
|
-
|
466
|
+
# @return [Void]
|
467
|
+
#
|
468
|
+
# @raise [Git::FailedError] if the pull fails
|
469
|
+
# @raise [ArgumentError] if a branch is given without a remote
|
470
|
+
def pull(remote = nil, branch = nil, opts = {})
|
471
|
+
self.lib.pull(remote, branch, opts)
|
420
472
|
end
|
421
473
|
|
422
474
|
# returns an array of Git:Remote objects
|
@@ -424,22 +476,6 @@ module Git
|
|
424
476
|
self.lib.remotes.map { |r| Git::Remote.new(self, r) }
|
425
477
|
end
|
426
478
|
|
427
|
-
# adds a new remote to this repository
|
428
|
-
# url can be a git url or a Git::Base object if it's a local reference
|
429
|
-
#
|
430
|
-
# @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git')
|
431
|
-
# @git.fetch('scotts_git')
|
432
|
-
# @git.merge('scotts_git/master')
|
433
|
-
#
|
434
|
-
# Options:
|
435
|
-
# :fetch => true
|
436
|
-
# :track => <branch_name>
|
437
|
-
def add_remote(name, url, opts = {})
|
438
|
-
url = url.repo.path if url.is_a?(Git::Base)
|
439
|
-
self.lib.remote_add(name, url, opts)
|
440
|
-
Git::Remote.new(self, name)
|
441
|
-
end
|
442
|
-
|
443
479
|
# sets the url for a remote
|
444
480
|
# url can be a git url or a Git::Base object if it's a local reference
|
445
481
|
#
|
@@ -463,7 +499,7 @@ module Git
|
|
463
499
|
self.lib.tags.map { |r| tag(r) }
|
464
500
|
end
|
465
501
|
|
466
|
-
#
|
502
|
+
# Create a new git tag
|
467
503
|
#
|
468
504
|
# @example
|
469
505
|
# repo.add_tag('tag_name', object_reference)
|
@@ -619,6 +655,96 @@ module Git
|
|
619
655
|
self.lib.branch_current
|
620
656
|
end
|
621
657
|
|
658
|
+
# @return [Git::Branch] an object for branch_name
|
659
|
+
def branch(branch_name = self.current_branch)
|
660
|
+
Git::Branch.new(self, branch_name)
|
661
|
+
end
|
662
|
+
|
663
|
+
# @return [Git::Branches] a collection of all the branches in the repository.
|
664
|
+
# Each branch is represented as a {Git::Branch}.
|
665
|
+
def branches
|
666
|
+
Git::Branches.new(self)
|
667
|
+
end
|
668
|
+
|
669
|
+
# returns a Git::Worktree object for dir, commitish
|
670
|
+
def worktree(dir, commitish = nil)
|
671
|
+
Git::Worktree.new(self, dir, commitish)
|
672
|
+
end
|
673
|
+
|
674
|
+
# returns a Git::worktrees object of all the Git::Worktrees
|
675
|
+
# objects for this repo
|
676
|
+
def worktrees
|
677
|
+
Git::Worktrees.new(self)
|
678
|
+
end
|
679
|
+
|
680
|
+
# @return [Git::Object::Commit] a commit object
|
681
|
+
def commit_tree(tree = nil, opts = {})
|
682
|
+
Git::Object::Commit.new(self, self.lib.commit_tree(tree, opts))
|
683
|
+
end
|
684
|
+
|
685
|
+
# @return [Git::Diff] a Git::Diff object
|
686
|
+
def diff(objectish = 'HEAD', obj2 = nil)
|
687
|
+
Git::Diff.new(self, objectish, obj2)
|
688
|
+
end
|
689
|
+
|
690
|
+
# @return [Git::Object] a Git object
|
691
|
+
def gblob(objectish)
|
692
|
+
Git::Object.new(self, objectish, 'blob')
|
693
|
+
end
|
694
|
+
|
695
|
+
# @return [Git::Object] a Git object
|
696
|
+
def gcommit(objectish)
|
697
|
+
Git::Object.new(self, objectish, 'commit')
|
698
|
+
end
|
699
|
+
|
700
|
+
# @return [Git::Object] a Git object
|
701
|
+
def gtree(objectish)
|
702
|
+
Git::Object.new(self, objectish, 'tree')
|
703
|
+
end
|
704
|
+
|
705
|
+
# @return [Git::Log] a log with the specified number of commits
|
706
|
+
def log(count = 30)
|
707
|
+
Git::Log.new(self, count)
|
708
|
+
end
|
709
|
+
|
710
|
+
# returns a Git::Object of the appropriate type
|
711
|
+
# you can also call @git.gtree('tree'), but that's
|
712
|
+
# just for readability. If you call @git.gtree('HEAD') it will
|
713
|
+
# still return a Git::Object::Commit object.
|
714
|
+
#
|
715
|
+
# object calls a method that will run a rev-parse
|
716
|
+
# on the objectish and determine the type of the object and return
|
717
|
+
# an appropriate object for that type
|
718
|
+
#
|
719
|
+
# @return [Git::Object] an instance of the appropriate type of Git::Object
|
720
|
+
def object(objectish)
|
721
|
+
Git::Object.new(self, objectish)
|
722
|
+
end
|
723
|
+
|
724
|
+
# @return [Git::Remote] a remote of the specified name
|
725
|
+
def remote(remote_name = 'origin')
|
726
|
+
Git::Remote.new(self, remote_name)
|
727
|
+
end
|
728
|
+
|
729
|
+
# @return [Git::Status] a status object
|
730
|
+
def status
|
731
|
+
Git::Status.new(self)
|
732
|
+
end
|
733
|
+
|
734
|
+
# @return [Git::Object::Tag] a tag object
|
735
|
+
def tag(tag_name)
|
736
|
+
Git::Object.new(self, tag_name, 'tag', true)
|
737
|
+
end
|
738
|
+
|
739
|
+
# Find as good common ancestors as possible for a merge
|
740
|
+
# example: g.merge_base('master', 'some_branch', 'some_sha', octopus: true)
|
741
|
+
#
|
742
|
+
# @return [Array<Git::Object::Commit>] a collection of common ancestors
|
743
|
+
def merge_base(*args)
|
744
|
+
shas = self.lib.merge_base(*args)
|
745
|
+
shas.map { |sha| gcommit(sha) }
|
746
|
+
end
|
747
|
+
|
622
748
|
private
|
623
749
|
|
624
750
|
# Normalize options before they are sent to Git::Base.new
|