git 5.6.0 → 6.0.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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +132 -16
  3. data/CONTRIBUTING.md +44 -31
  4. data/README.md +135 -67
  5. data/UPGRADING.md +915 -268
  6. data/git.gemspec +6 -8
  7. data/lib/git/author_info.rb +1 -2
  8. data/lib/git/commands/base.rb +22 -2
  9. data/lib/git/commands/cat_file/raw.rb +0 -68
  10. data/lib/git/commands/maintenance/register.rb +0 -4
  11. data/lib/git/commands/maintenance/run.rb +0 -4
  12. data/lib/git/commands/maintenance/start.rb +0 -4
  13. data/lib/git/commands/maintenance/stop.rb +0 -4
  14. data/lib/git/commands/maintenance/unregister.rb +0 -4
  15. data/lib/git/commands/maintenance.rb +0 -2
  16. data/lib/git/commands/show_ref/exclude_existing.rb +1 -1
  17. data/lib/git/commands/show_ref/exists.rb +0 -5
  18. data/lib/git/commands/show_ref/list.rb +1 -1
  19. data/lib/git/commands/show_ref/verify.rb +1 -1
  20. data/lib/git/commands/show_ref.rb +1 -1
  21. data/lib/git/commands/worktree/repair.rb +0 -5
  22. data/lib/git/diff_path_status.rb +2 -2
  23. data/lib/git/encoding_utils.rb +25 -0
  24. data/lib/git/errors.rb +23 -5
  25. data/lib/git/factories.rb +361 -125
  26. data/lib/git/log.rb +3 -75
  27. data/lib/git/object.rb +4 -185
  28. data/lib/git/path_resolver.rb +104 -36
  29. data/lib/git/repository/branching.rb +21 -189
  30. data/lib/git/repository/committing.rb +0 -25
  31. data/lib/git/repository/context_helpers.rb +249 -155
  32. data/lib/git/repository/diffing.rb +2 -44
  33. data/lib/git/repository/merging.rb +32 -54
  34. data/lib/git/repository/object_operations.rb +121 -338
  35. data/lib/git/repository/remote_operations.rb +7 -219
  36. data/lib/git/repository/staging.rb +6 -184
  37. data/lib/git/repository/stashing.rb +126 -130
  38. data/lib/git/repository/status_operations.rb +1 -54
  39. data/lib/git/repository/worktree_operations.rb +31 -118
  40. data/lib/git/repository.rb +20 -299
  41. data/lib/git/system_call_guard.rb +95 -0
  42. data/lib/git/version.rb +1 -1
  43. data/lib/git.rb +47 -364
  44. metadata +25 -19
  45. data/lib/git/author.rb +0 -46
  46. data/lib/git/branch.rb +0 -693
  47. data/lib/git/branches.rb +0 -194
  48. data/lib/git/remote.rb +0 -191
  49. data/lib/git/stash.rb +0 -124
  50. data/lib/git/stashes.rb +0 -198
  51. data/lib/git/status.rb +0 -384
  52. data/lib/git/worktree.rb +0 -180
  53. data/lib/git/worktrees.rb +0 -152
data/lib/git/branches.rb DELETED
@@ -1,194 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Git
4
- # Collection of all Git branches in a repository
5
- #
6
- # Wraps both local and remote-tracking branches and provides filtering,
7
- # enumeration, and name-based lookup.
8
- #
9
- # @example Enumerate all branches
10
- # branches = repo.branches
11
- # branches.each { |b| puts b.name }
12
- #
13
- # @deprecated Use {Git::Repository::Branching#branch_list} instead
14
- #
15
- # {Git::Repository::Branching#branch_list} returns `Array<Git::BranchInfo>`
16
- # (immutable value objects). Filter it with `select(&:remote?)` or
17
- # `reject(&:remote?)` in place of {#remote} and {#local}, and look a
18
- # branch up by name with `branch_list(name).first` in place of {#[]}.
19
- # Constructing a `Git::Branches` emits a deprecation warning.
20
- #
21
- # @api public
22
- #
23
- class Branches
24
- include Enumerable
25
-
26
- # Creates a new Branches collection populated from the given repository
27
- #
28
- # @param base [Git::Repository] the repository to enumerate
29
- # branches from
30
- #
31
- # @return [void]
32
- #
33
- # @raise [Git::FailedError] if git exits with a non-zero exit status
34
- #
35
- # @deprecated Use {Git::Repository::Branching#branch_list} instead
36
- #
37
- # @see Git::Repository::Branching#branch_list
38
- #
39
- def initialize(base)
40
- Git::Deprecation.warn(
41
- 'Git::Branches is deprecated and will be removed in v6.0.0. ' \
42
- 'Use Git::Repository#branch_list instead.'
43
- )
44
- @branches = {}
45
- @lookup = {}
46
-
47
- @base = base
48
-
49
- load_branches
50
- end
51
-
52
- # Returns all local (non-remote-tracking) branches
53
- #
54
- # @example List local branch names
55
- # repo.branches.local.map(&:name)
56
- #
57
- # @return [Array<Git::Branch>] the local branches
58
- #
59
- def local
60
- reject(&:remote)
61
- end
62
-
63
- # Returns all remote-tracking branches
64
- #
65
- # @example List remote branch names
66
- # repo.branches.remote.map(&:name)
67
- #
68
- # @return [Array<Git::Branch>] the remote-tracking branches
69
- #
70
- def remote
71
- self.select(&:remote)
72
- end
73
-
74
- # Returns the number of branches in the collection
75
- #
76
- # @example Count all branches
77
- # repo.branches.size # => 3
78
- #
79
- # @return [Integer] the total number of branches
80
- #
81
- def size
82
- @branches.size
83
- end
84
-
85
- # Iterates over every branch in the collection
86
- #
87
- # @overload each
88
- #
89
- # @example Get an enumerator over all branches
90
- # enum = repo.branches.each
91
- #
92
- # @return [Enumerator<Git::Branch>] an enumerator over all branches
93
- #
94
- # @overload each(&block)
95
- #
96
- # @example Print every branch name
97
- # repo.branches.each { |b| puts b.name }
98
- #
99
- # @return [Array<Git::Branch>] the full list of branches
100
- #
101
- # @yield [branch] passes each branch to the block
102
- #
103
- # @yieldparam branch [Git::Branch] a branch in the repository
104
- #
105
- # @yieldreturn [void]
106
- #
107
- def each(&)
108
- @branches.values.each(&)
109
- end
110
-
111
- # Returns the branch with the given name
112
- #
113
- # Supports short names (`'main'`), remote-qualified names
114
- # (`'working/master'`), and full refspec names
115
- # (`'remotes/working/master'`).
116
- #
117
- # @example Look up a branch by short name
118
- # repo.branches['main']
119
- #
120
- # @example Look up a remote-tracking branch
121
- # repo.branches['working/master']
122
- #
123
- # @param branch_name [#to_s] the name of the branch to retrieve
124
- #
125
- # @return [Git::Branch, nil] the matching branch, or `nil` if not found
126
- #
127
- def [](branch_name)
128
- @lookup[branch_name.to_s]
129
- end
130
-
131
- # Returns a string listing all branches, prefixed with `*` for the current branch
132
- #
133
- # @example Display all branches
134
- # puts repo.branches.to_s
135
- #
136
- # @return [String] a formatted branch listing
137
- #
138
- def to_s
139
- out = +''
140
- @branches.each_value do |b|
141
- # Git::Branch#current is deprecated too; silence it so one to_s call emits one warning
142
- current = Git::Deprecation.silence { b.current }
143
- out << (current ? '* ' : ' ') << b.to_s << "\n"
144
- end
145
- out
146
- end
147
-
148
- private
149
-
150
- # Builds a Git::Branch for every branch in the repository and indexes it
151
- #
152
- # @return [void]
153
- #
154
- # @api private
155
- #
156
- def load_branches
157
- branch_repository.branch_list.each do |branch_info|
158
- branch = Git::Branch.new(@base, branch_info)
159
-
160
- @branches[branch_info.refname] = branch
161
- index_branch_lookup(branch, refname: branch_info.refname)
162
- end
163
- end
164
-
165
- # @return [Git::Repository] the repository used to enumerate branches
166
- #
167
- # @api private
168
- #
169
- def branch_repository
170
- @base
171
- end
172
-
173
- # Indexes all supported lookup keys for a branch without mutating
174
- # the canonical `@branches` collection used by enumeration
175
- #
176
- # @param branch [Git::Branch] the branch to index
177
- #
178
- # @param refname [String] the full refname key to use for primary lookup
179
- #
180
- # @return [void]
181
- #
182
- # @api private
183
- #
184
- def index_branch_lookup(branch, refname:)
185
- @lookup[refname] ||= branch
186
- @lookup[branch.full] ||= branch
187
-
188
- return unless branch.full.start_with?('remotes/')
189
-
190
- # Mirror git compatibility: allow omitting a leading "remotes/".
191
- @lookup[branch.full.delete_prefix('remotes/')] ||= branch
192
- end
193
- end
194
- end
data/lib/git/remote.rb DELETED
@@ -1,191 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'git/branch'
4
- require 'git/branch_info'
5
-
6
- module Git
7
- # A remote in a Git repository
8
- #
9
- # Remote objects provide access to remote metadata and operations like fetch,
10
- # merge, and remove. This class and `Git::Repository#remote`, which returns
11
- # it, are both deprecated: read remote configuration through
12
- # {Git::Repository::RemoteOperations#remote_list} and call the
13
- # repository-level operations with the remote name instead.
14
- #
15
- # @example Reading a remote and fetching from it without Git::Remote
16
- # git = Git.open('.')
17
- # origin = git.remote_list.find { |r| r.name == 'origin' } #=> Git::RemoteInfo
18
- # origin.url.first
19
- # git.fetch(origin.name)
20
- #
21
- # @deprecated Use {Git::Repository::RemoteOperations#remote_list} and the
22
- # repository-level remote operations instead
23
- #
24
- # {Git::Repository::RemoteOperations#remote_list} returns immutable
25
- # {Git::RemoteInfo} value objects. Operations that lived on this class are
26
- # called on the repository with the remote name instead (for example
27
- # {Git::Repository::RemoteOperations#fetch} and
28
- # {Git::Repository::RemoteOperations#remote_remove}). Constructing a
29
- # `Git::Remote` emits a deprecation warning.
30
- #
31
- # @api public
32
- #
33
- class Remote
34
- # The name of this remote (e.g. `'origin'`)
35
- #
36
- # @return [String] the remote name
37
- #
38
- attr_accessor :name
39
-
40
- # The URL of this remote
41
- #
42
- # @return [String, nil] the remote URL
43
- #
44
- attr_accessor :url
45
-
46
- # The fetch refspec for this remote
47
- #
48
- # @return [String, nil] the fetch options string
49
- #
50
- attr_accessor :fetch_opts
51
-
52
- # Initialize a new Remote object
53
- #
54
- # @param base [Git::Repository] the git repository
55
- #
56
- # @param name [String] the remote name (e.g. `'origin'`)
57
- #
58
- # @note Do not construct directly. `Git::Repository#remote` is deprecated as
59
- # well; use {Git::Repository::RemoteOperations#remote_list} and the
60
- # repository-level remote operations instead.
61
- #
62
- # @api private
63
- #
64
- def initialize(base, name)
65
- Git::Deprecation.warn(
66
- 'Git::Remote is deprecated and will be removed in v6.0.0. ' \
67
- 'Use Git::Repository#remote_list and the repository-level remote operations instead.'
68
- )
69
- @base = base
70
- # config_remote is deprecated too; silence it so one Git::Remote.new emits one warning
71
- config = Git::Deprecation.silence { remote_repository.config_remote(name) }
72
- @name = name
73
- @url = config['url']
74
- @fetch_opts = config['fetch']
75
- end
76
-
77
- # Fetches from this remote
78
- #
79
- # @example Fetch from origin
80
- # git.remote('origin').fetch
81
- #
82
- # @param opts [Hash] options for the fetch command
83
- #
84
- # @option opts [Boolean, nil] :tags (nil) fetch all tags from the remote
85
- # (`--tags`)
86
- #
87
- # @option opts [Boolean, nil] :prune (nil) remove remote-tracking references
88
- # that no longer exist on the remote (`--prune`)
89
- #
90
- # @option opts [Boolean, nil] :prune_tags (nil) remove local tags that no
91
- # longer exist on the remote (`--prune-tags`)
92
- #
93
- # @option opts [Boolean, nil] :force (nil) override the fast-forward check
94
- # when using explicit refspecs (`--force`)
95
- #
96
- # @option opts [Boolean, nil] :update_head_ok (nil) allow `git fetch` to
97
- # update the branch pointed to by `HEAD` (`--update-head-ok`)
98
- #
99
- # @option opts [Boolean, nil] :unshallow (nil) convert a shallow clone into a
100
- # full repository (`--unshallow`)
101
- #
102
- # @option opts [String, Integer, nil] :depth (nil) limit history to N commits
103
- # from each branch tip (`--depth=N`)
104
- #
105
- # @option opts [String, Array<String>, nil] :ref (nil) one or more refspecs to
106
- # fetch as positional arguments after the remote name
107
- #
108
- # @return [String] git's stdout from the fetch
109
- #
110
- # @raise [Git::FailedError] if git exits with a non-zero exit status
111
- #
112
- def fetch(opts = {})
113
- remote_repository.fetch(@name, opts)
114
- end
115
-
116
- # Merges this remote into the given (or current) local branch
117
- #
118
- # @example Merge origin/main into the current branch
119
- # git.remote('origin').merge('main')
120
- #
121
- # @param branch [String] the local branch to merge into (defaults to current branch)
122
- #
123
- # @return [String] git's stdout from the merge
124
- #
125
- # @raise [Git::FailedError] if git exits with a non-zero exit status
126
- #
127
- def merge(branch = nil)
128
- branch ||= remote_repository.current_branch
129
- remote_tracking_branch = "#{@name}/#{branch}"
130
- remote_repository.merge(remote_tracking_branch)
131
- end
132
-
133
- # Returns a {Git::Branch} object for the given branch on this remote
134
- #
135
- # @example Get the remote-tracking branch object
136
- # git.remote('origin').branch('main') #=> #<Git::Branch 'origin/main'>
137
- #
138
- # @param branch [String] the branch name on this remote (defaults to current branch)
139
- #
140
- # @return [Git::Branch] a branch object representing `<remote>/<branch>`
141
- #
142
- # @deprecated Use
143
- # `Git::Repository#branch_list("#{name}/#{branch || current_branch}").first`
144
- # instead
145
- #
146
- # With no argument this method falls back to the current branch, so the
147
- # replacement has to supply `Git::Repository#current_branch` itself. The
148
- # replacement returns a {Git::BranchInfo} value object rather than a
149
- # {Git::Branch}, and returns `nil` when the remote-tracking branch does
150
- # not exist.
151
- #
152
- def branch(branch = nil)
153
- branch ||= remote_repository.current_branch
154
- Git::Branch.new(@base, "#{@name}/#{branch}")
155
- end
156
-
157
- # Removes this remote from the repository
158
- #
159
- # @example Remove the upstream remote
160
- # git.remote('upstream').remove
161
- #
162
- # @return [Git::CommandLine::Result] the result of `git remote remove`
163
- #
164
- # @raise [Git::FailedError] if git exits with a non-zero exit status
165
- #
166
- def remove
167
- remote_repository.remote_remove(@name)
168
- end
169
-
170
- # Returns the name of this remote as a string
171
- #
172
- # @example Get the remote name as a string
173
- # git.remote('origin').to_s #=> 'origin'
174
- #
175
- # @return [String] the remote name
176
- #
177
- def to_s
178
- @name
179
- end
180
-
181
- private
182
-
183
- # @return [Git::Repository]
184
- #
185
- # @api private
186
- #
187
- def remote_repository
188
- @base
189
- end
190
- end
191
- end
data/lib/git/stash.rb DELETED
@@ -1,124 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Git
4
- # Represents a single stash entry in a Git repository
5
- #
6
- # This class is deprecated and will be removed in v6.0.0. Use the
7
- # {Git::Repository} stash methods and {Git::StashInfo} instead:
8
- # {Git::Repository#stash_push} replaces `Git::Stash.new(repo, message)` and
9
- # returns a {Git::StashInfo}, or `nil` when there was nothing to stash.
10
- #
11
- # @example Create a stash and inspect the result (deprecated)
12
- # stash = Git::Stash.new(repo, 'WIP: feature work')
13
- # stash.message #=> "WIP: feature work"
14
- # stash.saved? #=> true
15
- #
16
- # @example The replacement
17
- # info = repo.stash_push(message: 'WIP: feature work')
18
- # info.message #=> "On main: WIP: feature work"
19
- # info.nil? #=> false
20
- #
21
- # @deprecated Use {Git::Repository#stash_push} and {Git::StashInfo} instead
22
- #
23
- # @see Git::Repository#stash_push
24
- #
25
- # @api public
26
- #
27
- class Stash
28
- # Initialize a Stash object
29
- #
30
- # When `existing` is `false` (the default), immediately calls {#save} to push
31
- # the current working-directory state onto the stash stack.
32
- #
33
- # Emits one deprecation warning per object.
34
- #
35
- # @example Create a new stash entry
36
- # stash = Git::Stash.new(repo, 'WIP: feature work')
37
- # stash.saved? #=> true
38
- #
39
- # @example Reference an existing stash without pushing
40
- # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
41
- # stash.saved? #=> nil
42
- #
43
- # @param base [Git::Repository] the git repository
44
- #
45
- # @param message [String] the stash message
46
- #
47
- # @param existing [Boolean] (false) when `true`, wraps an existing stash entry
48
- # without pushing any changes
49
- #
50
- # @return [void]
51
- #
52
- # @deprecated Use {Git::Repository#stash_push} and {Git::StashInfo} instead
53
- #
54
- def initialize(base, message, existing: false)
55
- Git::Deprecation.warn(
56
- 'Git::Stash is deprecated and will be removed in v6.0.0. ' \
57
- 'Use the Git::Repository stash methods (stash_push, stash_infos, stash_apply) ' \
58
- 'and Git::StashInfo instead.'
59
- )
60
- @base = base
61
- @message = message
62
- save unless existing
63
- end
64
-
65
- # Saves the current working-directory state to the stash stack
66
- #
67
- # @example Save changes to the stash stack
68
- # stash = Git::Stash.new(repo, 'WIP', existing: true)
69
- # stash.save #=> true
70
- #
71
- # @return [Boolean] `true` if changes were stashed, `false` if there were no
72
- # local changes to save
73
- #
74
- # @raise [Git::FailedError] if git exits with a non-zero exit status
75
- #
76
- def save
77
- # stash_save is deprecated too; silence it so one Git::Stash call emits one warning
78
- @saved = Git::Deprecation.silence { stash_repository.stash_save(@message) }
79
- end
80
-
81
- # Returns whether the stash was saved successfully
82
- #
83
- # @example Check if changes were stashed
84
- # stash = Git::Stash.new(repo, 'WIP: feature work')
85
- # stash.saved? #=> true
86
- #
87
- # @return [Boolean, nil] `true` if changes were stashed, `false` if there were no
88
- # local changes, `nil` if {#save} has not been called (e.g. `existing: true`)
89
- #
90
- def saved?
91
- @saved
92
- end
93
-
94
- # Returns the stash description
95
- #
96
- # @example Read the stash message
97
- # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
98
- # stash.message #=> "WIP: feature work"
99
- #
100
- # @return [String] the stash message
101
- #
102
- attr_reader :message
103
-
104
- # Returns the stash description as a string
105
- #
106
- # @example Convert stash to string
107
- # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
108
- # stash.to_s #=> "WIP: feature work"
109
- #
110
- # @return [String] the stash message
111
- #
112
- def to_s
113
- message
114
- end
115
-
116
- private
117
-
118
- # @return [Git::Repository]
119
- #
120
- def stash_repository
121
- @base
122
- end
123
- end
124
- end
data/lib/git/stashes.rb DELETED
@@ -1,198 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Git
4
- # Collection of stash entries for a Git repository
5
- #
6
- # This class is deprecated and will be removed in v6.0.0. Use the
7
- # {Git::Repository} stash methods and {Git::StashInfo} instead:
8
- # {Git::Repository#stash_infos} replaces the collection, and
9
- # {Git::Repository#stash_push}, {Git::Repository#stash_apply}, and
10
- # {Git::Repository#stash_clear} replace {#save}, {#apply}, and {#clear}.
11
- #
12
- # @example Iterate over stash entries (deprecated)
13
- # git.stashes.each { |s| puts s.message }
14
- #
15
- # @example The replacement
16
- # repo.stash_infos.each { |info| puts info.message }
17
- # repo.stash_infos.size #=> 2
18
- # repo.stash_apply
19
- #
20
- # @deprecated Use {Git::Repository#stash_infos} and {Git::StashInfo} instead
21
- #
22
- # @see Git::Repository#stash_infos
23
- #
24
- # @api public
25
- #
26
- class Stashes
27
- include Enumerable
28
-
29
- # Initialize the stashes collection
30
- #
31
- # Loads all existing stash entries from the repository at construction time.
32
- # Emits one deprecation warning per object.
33
- #
34
- # @example Load stashes for a repository
35
- # stashes = Git::Stashes.new(repo)
36
- # stashes.size #=> 2
37
- #
38
- # @param base [Git::Repository] the git repository
39
- #
40
- # @return [void]
41
- #
42
- # @raise [Git::FailedError] if git exits with a non-zero exit status
43
- #
44
- # @deprecated Use {Git::Repository#stash_infos} and {Git::StashInfo} instead
45
- #
46
- def initialize(base)
47
- Git::Deprecation.warn(
48
- 'Git::Stashes is deprecated and will be removed in v6.0.0. ' \
49
- 'Use the Git::Repository stash methods (stash_infos, stash_push, stash_apply, stash_clear) ' \
50
- 'and Git::StashInfo instead.'
51
- )
52
- @stashes = []
53
- @base = base
54
- # stashes_all and Git::Stash are deprecated too; silence them so one
55
- # Git::Stashes.new emits one warning
56
- Git::Deprecation.silence { load_stashes }
57
- end
58
-
59
- # Returns all stash entries as an array of index and message pairs
60
- #
61
- # Entries are listed in oldest-first order matching {Git::Repository#stashes_all}.
62
- #
63
- # @example List all stash entries
64
- # git.stashes.all #=> [[0, "testing-stash-all"], [1, "another-stash"]]
65
- #
66
- # @return [Array<Array(Integer, String)>] array of `[index, message]` pairs where
67
- # index 0 is the oldest stash
68
- #
69
- # @raise [Git::FailedError] if git exits with a non-zero exit status
70
- #
71
- def all
72
- # stashes_all is deprecated too; silence it so this call emits no second warning
73
- Git::Deprecation.silence { stash_repository.stashes_all }
74
- end
75
-
76
- # Saves the current working-directory state to a new stash entry
77
- #
78
- # @example Save current changes to the stash
79
- # git.stashes.save('WIP: feature work')
80
- # git.stashes.size #=> 1
81
- #
82
- # @param message [String] the stash message
83
- #
84
- # @return [void]
85
- #
86
- # @raise [Git::FailedError] if git exits with a non-zero exit status
87
- #
88
- def save(message)
89
- # Git::Stash is deprecated too; silence it so this call emits no second warning
90
- s = Git::Deprecation.silence { Git::Stash.new(@base, message) }
91
- @stashes.unshift(s) if s.saved?
92
- end
93
-
94
- # Applies a stash entry to the working directory
95
- #
96
- # @example Apply the most recent stash
97
- # git.stashes.apply
98
- #
99
- # @example Apply a specific stash by index
100
- # git.stashes.apply(1)
101
- #
102
- # @param index [Integer, nil] the stash index to apply (default: latest)
103
- #
104
- # @return [String] the output from the git stash apply command
105
- #
106
- # @raise [Git::FailedError] if git exits with a non-zero exit status
107
- #
108
- def apply(index = nil)
109
- stash_repository.stash_apply(index)
110
- end
111
-
112
- # Removes all stash entries
113
- #
114
- # @example Clear all stashes
115
- # git.stashes.clear
116
- # git.stashes.size #=> 0
117
- #
118
- # @return [void]
119
- #
120
- # @raise [Git::FailedError] if git exits with a non-zero exit status
121
- #
122
- def clear
123
- stash_repository.stash_clear
124
- @stashes = []
125
- nil
126
- end
127
-
128
- # Returns the number of stash entries
129
- #
130
- # @example Check how many stashes exist
131
- # git.stashes.size #=> 2
132
- #
133
- # @return [Integer] the number of stashes
134
- #
135
- def size
136
- @stashes.size
137
- end
138
-
139
- # Iterates over each stash entry in newest-first order
140
- #
141
- # @example Iterate over stashes
142
- # git.stashes.each { |s| puts s.message }
143
- #
144
- # @overload each
145
- #
146
- # @return [Enumerator<Git::Stash>] an enumerator over stash entries
147
- #
148
- # @overload each(&block)
149
- #
150
- # @yield [stash] each stash entry
151
- #
152
- # @yieldparam stash [Git::Stash] the current stash entry
153
- #
154
- # @yieldreturn [void]
155
- #
156
- # @return [Array<Git::Stash>] the stash entries
157
- #
158
- def each(&)
159
- @stashes.each(&)
160
- end
161
-
162
- # Returns the stash entry at the given index
163
- #
164
- # Stashes are stored in newest-first order; index 0 is the most recent stash.
165
- #
166
- # @example Access the most recent stash
167
- # git.stashes[0].message #=> "WIP: feature work"
168
- #
169
- # @param index [Integer, #to_i] the stash index (0 = most recent)
170
- #
171
- # @return [Git::Stash, nil] the stash entry, or `nil` if the index is out of bounds
172
- #
173
- def [](index)
174
- @stashes[index.to_i]
175
- end
176
-
177
- private
178
-
179
- # Wraps every entry from the repository in a Git::Stash, newest first
180
- #
181
- # @return [void]
182
- #
183
- def load_stashes
184
- stash_repository.stashes_all.each do |stash|
185
- message = stash[1]
186
- @stashes.unshift(Git::Stash.new(@base, message, existing: true))
187
- end
188
- end
189
-
190
- # Returns the facade interface for stash operations
191
- #
192
- # @return [Git::Repository]
193
- #
194
- def stash_repository
195
- @base
196
- end
197
- end
198
- end