git 5.0.0.beta.5 β†’ 5.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.
data/README.md CHANGED
@@ -19,23 +19,17 @@ Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?log
19
19
  - [Install](#install)
20
20
  - [Quick Start](#quick-start)
21
21
  - [Examples](#examples)
22
- - [Configuration](#configuration)
23
- - [Read Operations](#read-operations)
24
- - [Write Operations](#write-operations)
25
- - [Index and Tree Operations](#index-and-tree-operations)
26
- - [Errors Raised By This Gem](#errors-raised-by-this-gem)
27
- - [Specifying And Handling Timeouts](#specifying-and-handling-timeouts)
22
+ - [Gem Configuration](#gem-configuration)
23
+ - [Git Configuration](#git-configuration)
24
+ - [Full API](#full-api)
25
+ - [Errors Raised by This Gem](#errors-raised-by-this-gem)
26
+ - [Specifying and Handling Timeouts](#specifying-and-handling-timeouts)
28
27
  - [Deprecations](#deprecations)
29
- - [Upgrading from v4.x to v5.0.0](#upgrading-from-v4x-to-v500)
30
28
  - [Project Policies](#project-policies)
31
29
  - [Ruby Version Support Policy](#ruby-version-support-policy)
32
30
  - [Git Version Support Policy](#git-version-support-policy)
33
- - [πŸ“’ Project Announcements πŸ“’](#-project-announcements-)
34
- - [2026-07-13: v5.0.0.beta.5 Released](#2026-07-13-v500beta5-released)
35
- - [2026-07-11: v5.0.0.beta.4 Released](#2026-07-11-v500beta4-released)
36
- - [2026-06-26: v5.0.0.beta.3 Released](#2026-06-26-v500beta3-released)
37
- - [2026-06-25: v5.0.0.beta.2 Released](#2026-06-25-v500beta2-released)
38
- - [2026-06-04: v5.0.0.beta.1 Released](#2026-06-04-v500beta1-released)
31
+ - [Project Announcements](#project-announcements)
32
+ - [2026-07-28: v5.0.0 Released](#2026-07-28-v500-released)
39
33
  - [2026-01-07: AI Policy Introduced](#2026-01-07-ai-policy-introduced)
40
34
  - [2025-07-09: Architectural Redesign](#2025-07-09-architectural-redesign)
41
35
  - [2025-07-07: We Now Use RuboCop](#2025-07-07-we-now-use-rubocop)
@@ -61,6 +55,10 @@ Methods that can be called on a repository object are documented in
61
55
 
62
56
  ## Install
63
57
 
58
+ This gem is a wrapper around the `git` command line, so a `git` executable (version
59
+ 2.28.0 or greater) must be installed and on your `PATH`. See the [Git Version Support
60
+ Policy](#git-version-support-policy) for details.
61
+
64
62
  Install the gem and add to the application's Gemfile by executing:
65
63
 
66
64
  ```shell
@@ -91,7 +89,7 @@ require 'git'
91
89
 
92
90
  repo = Git.clone('https://github.com/ruby-git/ruby-git.git', 'ruby-git')
93
91
  repo.status.changed.each { |f| puts "changed: #{f.path}" }
94
- repo.log(5).each { |c| puts c.message }
92
+ repo.log(5).execute.each { |c| puts c.message }
95
93
  ```
96
94
 
97
95
  Open an existing repo and commit:
@@ -117,27 +115,10 @@ repo.commit('initial commit')
117
115
 
118
116
  ## Examples
119
117
 
120
- Beyond the basics covered in Quick Start, these examples show the full range of
121
- options and variations for each operation.
122
-
123
- ### Configuration
124
-
125
- Configure the `git` command line:
118
+ These examples cover configuring the gem and git itself. For the full set of
119
+ repository operations, see [Full API](#full-api) below.
126
120
 
127
- ```ruby
128
- # Global config (in ~/.gitconfig)
129
- entries = Git.config_list(global: true) # returns Array<Git::ConfigEntryInfo>
130
- entry = Git.config_get('user.email', global: true) # returns Git::ConfigEntryInfo or nil
131
- email = entry&.value # => "user@example.com" or nil
132
- Git.config_set('user.email', 'user@example.com', global: true)
133
-
134
- # Repository config
135
- repo = Git.open('path/to/repo')
136
- entries = repo.config_list # returns Array<Git::ConfigEntryInfo>
137
- entry = repo.config_get('user.email') # returns Git::ConfigEntryInfo or nil
138
- email = entry&.value # => "anotheruser@example.com" or nil
139
- repo.config_set('user.email', 'anotheruser@example.com')
140
- ```
121
+ ### Gem Configuration
141
122
 
142
123
  Configure the git gem:
143
124
 
@@ -179,326 +160,36 @@ git = Git.init('new-repo', git_ssh: 'ssh -i /path/to/private_key')
179
160
  This is especially useful in multi-threaded applications where different repositories
180
161
  require different SSH credentials.
181
162
 
182
- ### Read Operations
183
-
184
- Here are the operations that need read permission only:
185
-
186
- ```ruby
187
- repo = Git.open(working_dir, :log => Logger.new(STDOUT))
188
-
189
- repo.index # Pathname to the index file
190
- repo.index.readable? # check if index is readable
191
- repo.index.writable? # check if index is writable
192
- repo.repo # Pathname to the .git directory
193
- repo.dir # Pathname to the working directory
194
-
195
- # ls-tree with recursion into subtrees (list files)
196
- repo.ls_tree("HEAD", recursive: true)
197
-
198
- # log - returns a Git::Log object, which is an Enumerator of Git::Commit objects
199
- # default configuration returns a max of 30 commits
200
- repo.log
201
- repo.log(200) # 200 most recent commits
202
- repo.log.since('2 weeks ago') # default count of commits since 2 weeks ago.
203
- repo.log(200).since('2 weeks ago') # commits since 2 weeks ago, limited to 200.
204
- repo.log.between('v2.5', 'v2.6')
205
- repo.log.each {|l| puts l.sha }
206
- repo.gblob('v2.5:Makefile').log.since('2 weeks ago')
207
-
208
- repo.object('HEAD^').to_s # git show / git rev-parse
209
- repo.object('HEAD^').contents
210
- repo.object('v2.5:Makefile').size
211
- repo.object('v2.5:Makefile').sha
212
-
213
- repo.gtree(treeish)
214
- repo.gblob(treeish)
215
- repo.gcommit(treeish)
216
-
217
-
218
- commit = repo.gcommit('1cc8667014381')
219
-
220
- commit.gtree
221
- commit.parent.sha
222
- commit.parents.size
223
- commit.author.name
224
- commit.author.email
225
- commit.author.date.strftime("%m-%d-%y")
226
- commit.committer.name
227
- commit.date.strftime("%m-%d-%y")
228
- commit.message
229
-
230
- tree = repo.gtree("HEAD^{tree}")
231
-
232
- tree.blobs
233
- tree.subtrees
234
- tree.children # blobs and subtrees
235
-
236
- repo.rev_parse('v2.0.0:README.md')
237
-
238
- repo.branches # returns Git::Branch objects
239
- repo.branches.local
240
- repo.current_branch
241
- repo.branches.remote
242
- repo.branches[:main].gcommit
243
- repo.branches['origin/main'].gcommit
244
-
245
- repo.grep('hello') # implies HEAD
246
- repo.blob('v2.5:Makefile').grep('hello')
247
- repo.tag('v2.5').grep('hello', 'docs/')
248
- repo.describe()
249
- repo.describe('0djf2aa')
250
- repo.describe('HEAD', {:all => true, :tags => true})
251
-
252
- repo.diff(commit1, commit2).size
253
- repo.diff(commit1, commit2).stats
254
- repo.diff(commit1, commit2).name_status
255
- repo.gtree('v2.5').diff('v2.6').insertions
256
- repo.diff('gitsearch1', 'v2.5').path('lib/')
257
- repo.diff('gitsearch1', 'v2.5').path('lib/', 'docs/', 'README.md') # multiple paths
258
- repo.diff('gitsearch1', repo.gtree('v2.5'))
259
- repo.diff('gitsearch1', 'v2.5').path('docs/').patch
260
- repo.gtree('v2.5').diff('v2.6').patch
261
-
262
- repo.gtree('v2.5').diff('v2.6').each do |file_diff|
263
- puts file_diff.path
264
- puts file_diff.patch
265
- puts file_diff.blob(:src).contents
266
- end
267
-
268
- repo.worktrees # returns Git::Worktree objects
269
- repo.worktrees.count
270
- repo.worktrees.each do |worktree|
271
- worktree.dir
272
- worktree.gcommit
273
- worktree.to_s
274
- end
275
-
276
- # Check repository integrity with fsck
277
- result = repo.fsck
278
- result.dangling.each { |obj| puts "dangling #{obj.type}: #{obj.sha}" }
279
- result.missing.each { |obj| puts "missing #{obj.type}: #{obj.sha}" }
280
-
281
- # Check if repository has any issues
282
- puts "Repository is clean" if result.empty?
283
-
284
- # fsck with options
285
- result = repo.fsck(unreachable: true, strict: true)
286
-
287
- # Suppress dangling object output
288
- result = repo.fsck(dangling: false)
289
-
290
- repo.config_get('user.name')&.value # returns 'Scott Chacon'
291
- repo.config_list # returns Array<Git::ConfigEntryInfo>
292
-
293
- # Configuration can be set when cloning using the :config option.
294
- # This option can be an single configuration String or an Array
295
- # if multiple config items need to be set.
296
- #
297
- repo = Git.clone(
298
- git_uri, destination_path,
299
- :config => [
300
- 'core.sshCommand=ssh -i /home/user/.ssh/id_rsa',
301
- 'submodule.recurse=true'
302
- ]
303
- )
304
-
305
- repo.tags # returns array of Git::Tag objects
306
-
307
- repo.show()
308
- repo.show('HEAD')
309
- repo.show('v2.8', 'README.md')
310
-
311
- Git.ls_remote('https://github.com/ruby-git/ruby-git.git') # returns a hash containing the available references of the repo.
312
- Git.ls_remote('/path/to/local/repo')
313
- Git.ls_remote() # same as Git.ls_remote('.')
314
-
315
- Git.default_branch('https://github.com/ruby-git/ruby-git') #=> 'main'
316
- ```
317
-
318
- ### Write Operations
163
+ ### Git Configuration
319
164
 
320
- And here are the operations that will need to write to your git repository.
165
+ Read and set `git` configuration values (via `git config`):
321
166
 
322
167
  ```ruby
323
- repo = Git.init # default is the current directory
324
- repo = Git.init('project')
325
- repo = Git.init(
326
- '/home/schacon/proj',
327
- { :repository => '/opt/git/proj.git', :index => '/tmp/index'}
328
- )
329
-
330
- # Clone from a git url
331
- git_url = 'https://github.com/ruby-git/ruby-git.git'
332
- repo = Git.clone(git_url)
333
-
334
- # Clone into /tmp/clone/ruby-git-clean
335
- name = 'ruby-git-clean'
336
- path = '/tmp/clone'
337
- repo = Git.clone(git_url, name, :path => path)
338
- repo.dir #=> /tmp/clone/ruby-git-clean
339
-
340
- repo.config_set('user.name', 'Scott Chacon')
341
- repo.config_set('user.email', 'email@email.com')
342
-
343
- # Clone can take a filter to tell the serve to send a partial clone
344
- repo = Git.clone(git_url, name, :path => path, :filter => 'tree:0')
345
-
346
- # Clone can control single-branch behavior (nil default keeps current git behavior)
347
- repo = Git.clone(git_url, name, :path => path, :depth => 1, :single_branch => false)
348
-
349
- # Clone can take an optional logger
350
- logger = Logger.new(STDOUT)
351
- repo = Git.clone(git_url, 'my-repo', :log => logger)
352
-
353
- repo.add # git add -- "."
354
- repo.add(:all=>true) # git add --all -- "."
355
- repo.add('file_path') # git add -- "file_path"
356
- repo.add(['file_path_1', 'file_path_2']) # git add -- "file_path_1" "file_path_2"
357
-
358
- repo.remove() # git rm -f -- "."
359
- repo.remove('file.txt') # git rm -f -- "file.txt"
360
- repo.remove(['file.txt', 'file2.txt']) # git rm -f -- "file.txt" "file2.txt"
361
- repo.remove('file.txt', :recursive => true) # git rm -f -r -- "file.txt"
362
- repo.remove('file.txt', :cached => true) # git rm -f --cached -- "file.txt"
363
-
364
- repo.commit('message')
365
- repo.commit_all('message')
366
-
367
- # Sign a commit using the gpg key configured in the user.signingkey config setting
368
- repo.config_set('user.signingkey', '0A46826A')
369
- repo.commit('message', gpg_sign: true)
370
-
371
- # Sign a commit using a specified gpg key
372
- key_id = '0A46826A'
373
- repo.commit('message', gpg_sign: key_id)
374
-
375
- # Skip signing a commit (overriding any global gpgsign setting)
376
- repo.commit('message', no_gpg_sign: true)
377
-
378
- repo = Git.clone(git_url, 'myrepo')
379
- repo.chdir do
380
- File.write('test-file', 'blahblahblah')
381
- repo.status.changed.each do |file|
382
- puts file.blob(:index).contents
383
- end
384
- end
385
-
386
- repo.reset # defaults to HEAD
387
- repo.reset_hard(Git::Commit)
388
-
389
- repo.branch('new_branch') # creates new or fetches existing
390
- repo.branch('new_branch').checkout
391
- repo.branch('new_branch').delete
392
- repo.branch('existing_branch').checkout
393
- repo.branch('main').contains?('existing_branch')
394
-
395
- # delete remote branch
396
- repo.push('origin', 'remote_branch_name', force: true, delete: true)
397
-
398
- repo.checkout('new_branch')
399
- repo.checkout('new_branch', new_branch: true, start_point: 'main')
400
- repo.checkout(repo.branch('new_branch'))
401
-
402
- repo.branch(name).merge(branch2)
403
- repo.branch(branch2).merge # merges HEAD with branch2
404
-
405
- repo.branch(name).in_branch(message) { # add files } # auto-commits
406
- repo.merge('new_branch')
407
- repo.merge('new_branch', 'merge commit message', no_ff: true)
408
- repo.merge('origin/remote_branch')
409
- repo.merge(repo.branch('main'))
410
- repo.merge([branch1, branch2])
411
-
412
- repo.merge_base('branch1', 'branch2')
413
-
414
- r = repo.remote_add(name, uri) # Git::Remote
415
- r = repo.remote_add(name, other_repo) # Git::Remote (other_repo is a Git::Repository instance)
416
-
417
- repo.remotes # array of Git::Remotes
418
- repo.remote(name).fetch
419
- repo.remote(name).remove
420
- repo.remote(name).merge
421
- repo.remote(name).merge(branch)
422
-
423
- repo.remote_set_branches('origin', '*', add: true) # append additional fetch refspecs
424
- repo.remote_set_branches('origin', 'feature', 'release/*') # replace fetch refspecs
425
-
426
- repo.fetch
427
- repo.fetch(repo.remotes.first)
428
- repo.fetch('origin', {:ref => 'some/ref/head'} )
429
- repo.fetch(all: true, force: true, depth: 2)
430
- repo.fetch('origin', {:'update-head-ok' => true})
431
-
432
- repo.pull
433
- repo.pull(Git::Repo, Git::Branch) # fetch and a merge
434
-
435
- repo.tag_add('tag_name') # returns Git::Object::Tag
436
- repo.tag_add('tag_name', 'object_reference')
437
- repo.tag_add('tag_name', 'object_reference', {:options => 'here'})
438
- repo.tag_add('tag_name', {:options => 'here'})
439
-
440
- repo.tag_delete('tag_name')
441
-
442
- repo.repack
443
-
444
- repo.push
445
- repo.push(repo.remote('name'))
446
-
447
- # delete remote branch
448
- repo.push('origin', 'remote_branch_name', force: true, delete: true)
449
-
450
- # push all branches to remote at one time
451
- repo.push('origin', all: true)
168
+ # Global config (in ~/.gitconfig)
169
+ entries = Git.config_list(global: true) # returns Array<Git::ConfigEntryInfo>
170
+ entry = Git.config_get('user.email', global: true) # returns Git::ConfigEntryInfo or nil
171
+ email = entry&.value # => "user@example.com" or nil
172
+ Git.config_set('user.email', 'user@example.com', global: true)
452
173
 
453
- repo.worktree('/tmp/new_worktree').add
454
- repo.worktree('/tmp/new_worktree', 'branch1').add
455
- repo.worktree('/tmp/new_worktree').remove
456
- repo.worktrees.prune
174
+ # Repository config
175
+ repo = Git.open('path/to/repo')
176
+ entries = repo.config_list # returns Array<Git::ConfigEntryInfo>
177
+ entry = repo.config_get('user.email') # returns Git::ConfigEntryInfo or nil
178
+ email = entry&.value # => "anotheruser@example.com" or nil
179
+ repo.config_set('user.email', 'anotheruser@example.com')
457
180
  ```
458
181
 
459
- ### Index and Tree Operations
460
-
461
- Some examples of more low-level index and tree operations
182
+ ### Full API
462
183
 
463
- ```ruby
464
- repo.with_temp_index do
465
-
466
- repo.read_tree(tree3) # calls self.index.read_tree
467
- repo.read_tree(tree1, :prefix => 'hi/')
468
-
469
- c = repo.commit_tree('message')
470
- # or #
471
- t = repo.write_tree
472
- c = repo.commit_tree(t, :message => 'message', :parents => [sha1, sha2])
184
+ Quick Start and the configuration sections above cover the most common setup. For
185
+ the complete set of operations β€” reading history, diffs, branches, remotes,
186
+ worktrees, staging, and low-level index and tree work β€” see the
187
+ [`Git::Repository`](https://rubydoc.info/gems/git/Git/Repository) reference. It
188
+ documents every method along with the object types each one returns (such as
189
+ `Git::Log`, `Git::Object::Commit`, `Git::Diff`, `Git::Branch`, and `Git::Worktree`),
190
+ so you can follow the links from a method to the full API of its result.
473
191
 
474
- repo.branch('branch_name').update_ref(c)
475
- repo.update_ref(branch, c)
476
-
477
- repo.with_temp_working do # new blank working directory
478
- repo.checkout
479
- repo.checkout(another_index)
480
- repo.commit # commits to temp_index
481
- end
482
- end
483
-
484
- repo.set_index('/path/to/index')
485
-
486
- repo.with_index(path) do
487
- # calls set_index, then switches back after
488
- end
489
-
490
- repo.with_working(dir) do
491
- # calls set_working, then switches back after
492
- end
493
-
494
- repo.with_temp_working(dir) do
495
- repo.checkout_index(:prefix => dir, :path_limiter => path)
496
- # do file work
497
- repo.commit # commits to index
498
- end
499
- ```
500
-
501
- ## Errors Raised By This Gem
192
+ ## Errors Raised by This Gem
502
193
 
503
194
  The git gem will only raise an `ArgumentError` or an error that is a subclass of
504
195
  `Git::Error`. It does not explicitly raise any other types of errors.
@@ -516,9 +207,7 @@ end
516
207
 
517
208
  See [`Git::Error`](https://rubydoc.info/gems/git/Git/Error) for more information.
518
209
 
519
- ## Specifying And Handling Timeouts
520
-
521
- The timeout feature was added in git gem version `2.0.0`.
210
+ ## Specifying and Handling Timeouts
522
211
 
523
212
  A timeout for git command line operations can be set either globally or for specific
524
213
  method calls that accept a `:timeout` parameter.
@@ -555,7 +244,7 @@ repo_url = 'https://github.com/ruby-git/ruby-git.git'
555
244
  Git.clone(repo_url) # Use the global timeout value
556
245
  Git.clone(repo_url, timeout: nil) # Also uses the global timeout value
557
246
  Git.clone(repo_url, timeout: 0) # Do not enforce a timeout
558
- Git.clone(repo_url, timeout: 10.5) # Timeout after 10.5 seconds raising Git::SignaledError
247
+ Git.clone(repo_url, timeout: 10.5) # Timeout after 10.5 seconds raising Git::TimeoutError
559
248
  ```
560
249
 
561
250
  If the command takes too long, a `Git::TimeoutError` will be raised:
@@ -608,11 +297,6 @@ needed for the upgrade.
608
297
  For the full list of deprecated methods and their replacements, see
609
298
  [UPGRADING.md](UPGRADING.md).
610
299
 
611
- ## Upgrading from v4.x to v5.0.0
612
-
613
- v5.0.0 is a major release with breaking changes. See
614
- [UPGRADING.md](UPGRADING.md) for a comprehensive migration guide.
615
-
616
300
  ## Project Policies
617
301
 
618
302
  These documents set expectations for behavior, contribution workflows, AI-assisted
@@ -663,138 +347,32 @@ gem as new git features are adopted or as maintaining backward compatibility bec
663
347
  impractical. Such changes will be clearly documented in the CHANGELOG and release
664
348
  notes.
665
349
 
666
- ## πŸ“’ Project Announcements πŸ“’
667
-
668
- ### 2026-07-13: v5.0.0.beta.5 Released
669
-
670
- We have published
671
- [`git v5.0.0.beta.5`](https://rubygems.org/gems/git/versions/5.0.0.beta.5) as our
672
- fifth pre-release.
673
-
674
- The main user-visible change is a temporary compatibility shim for users who
675
- monkeypatch `Git::Base`. In v5.0.0, `Git::Base` has been replaced by
676
- `Git::Repository`; the shim forwards methods defined on `Git::Base` to repository
677
- instances and emits deprecation warnings so applications can migrate those patches
678
- to `Git::Repository` before v6.0.0.
679
-
680
- **To try the beta**, add the pre-release version to your `Gemfile`:
681
-
682
- ```ruby
683
- gem 'git', '~> 5.0.0.beta'
684
- ```
685
-
686
- Or install it directly:
687
-
688
- ```sh
689
- gem install git --pre
690
- ```
691
-
692
- The intent is full backward compatibility with v4.x, but given the size and scope of
693
- the redesign, some incompatibilities may exist. Please give the latest beta a try and
694
- [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
695
- unexpected β€” your feedback helps us ship a solid v5.0.0.
696
-
697
- See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
698
-
699
- ### 2026-07-11: v5.0.0.beta.4 Released
700
-
701
- The architectural redesign is **feature complete** and we have published
702
- [`git v5.0.0.beta.4`](https://rubygems.org/gems/git/versions/5.0.0.beta.4) as our
703
- fourth pre-release.
704
-
705
- **To try the beta**, add the pre-release version to your `Gemfile`:
350
+ ## Project Announcements
706
351
 
707
- ```ruby
708
- gem 'git', '~> 5.0.0.beta'
709
- ```
710
-
711
- Or install it directly:
712
-
713
- ```sh
714
- gem install git --pre
715
- ```
716
-
717
- The intent is full backward compatibility with v4.x, but given the size and scope of
718
- the redesign, some incompatibilities may exist. Please give the latest beta a try and
719
- [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
720
- unexpected β€” your feedback helps us ship a solid v5.0.0.
721
-
722
- See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
723
-
724
- ### 2026-06-26: v5.0.0.beta.3 Released
725
-
726
- The architectural redesign is approximately **93% complete** and we have published
727
- [`git v5.0.0.beta.3`](https://rubygems.org/gems/git/versions/5.0.0.beta.3) as our
728
- third pre-release.
729
-
730
- **To try the beta**, add the pre-release version to your `Gemfile`:
731
-
732
- ```ruby
733
- gem 'git', '~> 5.0.0.beta'
734
- ```
735
-
736
- Or install it directly:
737
-
738
- ```sh
739
- gem install git --pre
740
- ```
741
-
742
- The intent is full backward compatibility with v4.x, but given the size and scope of
743
- the redesign, some incompatibilities may exist. Please give the latest beta a try and
744
- [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
745
- unexpected β€” your feedback helps us ship a solid v5.0.0.
746
-
747
- See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
352
+ ### 2026-07-28: v5.0.0 Released
748
353
 
749
- ### 2026-06-25: v5.0.0.beta.2 Released
354
+ We have published [`git v5.0.0`](https://rubygems.org/gems/git/versions/5.0.0) β€”
355
+ the first stable release of the v5.x series, after five public beta releases
356
+ spanning June–July 2026.
750
357
 
751
- The architectural redesign is approximately **90% complete** and we have published
752
- [`git v5.0.0.beta.2`](https://rubygems.org/gems/git/versions/5.0.0.beta.2) as our
753
- second pre-release.
358
+ **v5.0.0 is a major release with breaking changes.** See
359
+ [UPGRADING.md](UPGRADING.md) for the complete migration guide.
754
360
 
755
- **To try the beta**, add the pre-release version to your `Gemfile`:
361
+ To install:
756
362
 
757
363
  ```ruby
758
- gem 'git', '~> 5.0.0.beta'
364
+ gem 'git', '~> 5.0'
759
365
  ```
760
366
 
761
- Or install it directly:
367
+ Or:
762
368
 
763
369
  ```sh
764
- gem install git --pre
765
- ```
766
-
767
- The intent is full backward compatibility with v4.x, but given the size and scope of
768
- the redesign, some incompatibilities may exist. Please give the latest beta a try and
769
- [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
770
- unexpected β€” your feedback helps us ship a solid v5.0.0.
771
-
772
- See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
773
-
774
- ### 2026-06-04: v5.0.0.beta.1 Released
775
-
776
- The architectural redesign is approximately **65% complete** and we have published
777
- [`git v5.0.0.beta.1`](https://rubygems.org/gems/git/versions/5.0.0.beta.1) as our
778
- first pre-release.
779
-
780
- **To try the beta**, add the pre-release version to your `Gemfile`:
781
-
782
- ```ruby
783
- gem 'git', '~> 5.0.0.beta'
784
- ```
785
-
786
- Or install it directly:
787
-
788
- ```sh
789
- gem install git --pre
370
+ gem install git
790
371
  ```
791
372
 
792
- The intent is full backward compatibility with 4.x, but given the size and scope of
793
- the redesign, some incompatibilities may exist. Please give the latest beta a try and
794
- [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
795
- unexpected β€” your feedback helps us ship a solid 5.0.0.
796
-
797
- See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
373
+ Most v4.x code requires **no changes** β€” compatibility shims keep the old API
374
+ working while emitting deprecation warnings that tell you what to migrate before
375
+ v6.0.0.
798
376
 
799
377
  ### 2026-01-07: AI Policy Introduced
800
378
 
data/UPGRADING.md CHANGED
@@ -93,6 +93,32 @@ require 'git'
93
93
  `Git.open` (e.g., `repo.commit`, `repo.status`, `repo.add`) requires no
94
94
  changes.
95
95
 
96
+ **Monkeypatching `Git::Base` is deprecated:** v5.x includes a temporary
97
+ compatibility shim for applications that define instance methods on `Git::Base`.
98
+ Those methods are made available on `Git::Repository` instances, but each method
99
+ definition emits a deprecation warning and this shim will be removed in v6.0.0.
100
+
101
+ Move custom repository helpers to an application-owned extension module and
102
+ include or prepend that module into `Git::Repository` during application setup:
103
+
104
+ ```ruby
105
+ # Deprecated in v5.x and will be removed in v6.0.0
106
+ module Git::Base
107
+ def worktree_clean?
108
+ status.changed.empty?
109
+ end
110
+ end
111
+
112
+ # v5.x β€” keep the extension in application-owned code
113
+ module MyAppGitRepositoryExtensions
114
+ def worktree_clean?
115
+ status.changed.empty?
116
+ end
117
+ end
118
+
119
+ Git::Repository.include(MyAppGitRepositoryExtensions)
120
+ ```
121
+
96
122
  ---
97
123
 
98
124
  #### Return type of `Git.open`, `Git.clone`, `Git.init`, `Git.bare`
data/lib/git/branch.rb CHANGED
@@ -386,6 +386,10 @@ module Git
386
386
  # Matches full and short refnames, capturing an optional remote name and the
387
387
  # branch name. Used internally to identify remote-tracking branches.
388
388
  #
389
+ # @note This legacy string-constructor path does not resolve remote names
390
+ # containing `/`. Use {Git::Repository#branch_list} to build branch objects
391
+ # from remote-aware {Git::BranchInfo} values.
392
+ #
389
393
  # @api private
390
394
  #
391
395
  BRANCH_NAME_REGEXP = %r{
@@ -424,9 +428,9 @@ module Git
424
428
  # @return [nil]
425
429
  #
426
430
  def initialize_from_branch_info(branch_info)
427
- @full = branch_info.refname
428
431
  @name = branch_info.short_name
429
432
  @remote = branch_info.remote_name ? Git::Remote.new(@base, branch_info.remote_name) : nil
433
+ @full = @remote ? "remotes/#{@remote.name}/#{@name}" : @name
430
434
  end
431
435
 
432
436
  # Initialize from a string name (legacy path for backward compatibility)