git 1.19.1 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +5 -1
- data/AI_POLICY.md +24 -0
- data/CHANGELOG.md +689 -0
- data/CODE_OF_CONDUCT.md +25 -0
- data/CONTRIBUTING.md +1175 -97
- data/GOVERNANCE.md +106 -0
- data/LICENSE +1 -1
- data/MAINTAINERS.md +17 -4
- data/README.md +476 -320
- data/UPGRADING.md +1138 -0
- data/git.gemspec +124 -36
- data/lib/git/author.rb +39 -7
- data/lib/git/author_info.rb +66 -0
- data/lib/git/branch.rb +615 -65
- data/lib/git/branch_delete_failure.rb +34 -0
- data/lib/git/branch_delete_result.rb +66 -0
- data/lib/git/branch_info.rb +237 -0
- data/lib/git/branches.rb +167 -44
- data/lib/git/command_line/base.rb +247 -0
- data/lib/git/command_line/capturing.rb +308 -0
- data/lib/git/command_line/result.rb +88 -0
- data/lib/git/command_line/streaming.rb +236 -0
- data/lib/git/command_line.rb +52 -0
- data/lib/git/commands/add.rb +139 -0
- data/lib/git/commands/am/abort.rb +43 -0
- data/lib/git/commands/am/apply.rb +263 -0
- data/lib/git/commands/am/continue.rb +43 -0
- data/lib/git/commands/am/quit.rb +43 -0
- data/lib/git/commands/am/retry.rb +49 -0
- data/lib/git/commands/am/show_current_patch.rb +64 -0
- data/lib/git/commands/am/skip.rb +42 -0
- data/lib/git/commands/am.rb +33 -0
- data/lib/git/commands/apply.rb +242 -0
- data/lib/git/commands/archive/list_formats.rb +46 -0
- data/lib/git/commands/archive.rb +145 -0
- data/lib/git/commands/arguments.rb +4521 -0
- data/lib/git/commands/base.rb +502 -0
- data/lib/git/commands/branch/copy.rb +102 -0
- data/lib/git/commands/branch/create.rb +177 -0
- data/lib/git/commands/branch/delete.rb +88 -0
- data/lib/git/commands/branch/list.rb +178 -0
- data/lib/git/commands/branch/move.rb +102 -0
- data/lib/git/commands/branch/set_upstream.rb +86 -0
- data/lib/git/commands/branch/show_current.rb +49 -0
- data/lib/git/commands/branch/unset_upstream.rb +53 -0
- data/lib/git/commands/branch.rb +34 -0
- data/lib/git/commands/cat_file/batch.rb +385 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +271 -0
- data/lib/git/commands/cat_file.rb +49 -0
- data/lib/git/commands/checkout/branch.rb +153 -0
- data/lib/git/commands/checkout/files.rb +116 -0
- data/lib/git/commands/checkout.rb +38 -0
- data/lib/git/commands/checkout_index.rb +106 -0
- data/lib/git/commands/clean.rb +102 -0
- data/lib/git/commands/clone.rb +241 -0
- data/lib/git/commands/commit.rb +273 -0
- data/lib/git/commands/commit_tree.rb +101 -0
- data/lib/git/commands/config_option_syntax/add.rb +86 -0
- data/lib/git/commands/config_option_syntax/get.rb +121 -0
- data/lib/git/commands/config_option_syntax/get_all.rb +118 -0
- data/lib/git/commands/config_option_syntax/get_color.rb +95 -0
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +96 -0
- data/lib/git/commands/config_option_syntax/get_regexp.rb +119 -0
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +111 -0
- data/lib/git/commands/config_option_syntax/list.rb +111 -0
- data/lib/git/commands/config_option_syntax/remove_section.rb +79 -0
- data/lib/git/commands/config_option_syntax/rename_section.rb +83 -0
- data/lib/git/commands/config_option_syntax/replace_all.rb +109 -0
- data/lib/git/commands/config_option_syntax/set.rb +119 -0
- data/lib/git/commands/config_option_syntax/unset.rb +92 -0
- data/lib/git/commands/config_option_syntax/unset_all.rb +94 -0
- data/lib/git/commands/config_option_syntax.rb +56 -0
- data/lib/git/commands/describe.rb +156 -0
- data/lib/git/commands/diff.rb +657 -0
- data/lib/git/commands/diff_files.rb +519 -0
- data/lib/git/commands/diff_index.rb +499 -0
- data/lib/git/commands/fetch.rb +354 -0
- data/lib/git/commands/fsck.rb +138 -0
- data/lib/git/commands/gc.rb +134 -0
- data/lib/git/commands/grep.rb +339 -0
- data/lib/git/commands/init.rb +101 -0
- data/lib/git/commands/log.rb +634 -0
- data/lib/git/commands/ls_files.rb +195 -0
- data/lib/git/commands/ls_remote.rb +161 -0
- data/lib/git/commands/ls_tree.rb +135 -0
- data/lib/git/commands/maintenance/register.rb +77 -0
- data/lib/git/commands/maintenance/run.rb +109 -0
- data/lib/git/commands/maintenance/start.rb +71 -0
- data/lib/git/commands/maintenance/stop.rb +60 -0
- data/lib/git/commands/maintenance/unregister.rb +84 -0
- data/lib/git/commands/maintenance.rb +31 -0
- data/lib/git/commands/merge/abort.rb +44 -0
- data/lib/git/commands/merge/continue.rb +44 -0
- data/lib/git/commands/merge/quit.rb +46 -0
- data/lib/git/commands/merge/start.rb +250 -0
- data/lib/git/commands/merge.rb +28 -0
- data/lib/git/commands/merge_base.rb +91 -0
- data/lib/git/commands/mv.rb +82 -0
- data/lib/git/commands/name_rev.rb +119 -0
- data/lib/git/commands/pull.rb +382 -0
- data/lib/git/commands/push.rb +251 -0
- data/lib/git/commands/read_tree.rb +154 -0
- data/lib/git/commands/remote/add.rb +96 -0
- data/lib/git/commands/remote/get_url.rb +68 -0
- data/lib/git/commands/remote/list.rb +56 -0
- data/lib/git/commands/remote/prune.rb +63 -0
- data/lib/git/commands/remote/remove.rb +52 -0
- data/lib/git/commands/remote/rename.rb +76 -0
- data/lib/git/commands/remote/set_branches.rb +70 -0
- data/lib/git/commands/remote/set_head.rb +89 -0
- data/lib/git/commands/remote/set_url.rb +78 -0
- data/lib/git/commands/remote/set_url_add.rb +70 -0
- data/lib/git/commands/remote/set_url_delete.rb +71 -0
- data/lib/git/commands/remote/show.rb +77 -0
- data/lib/git/commands/remote/update.rb +79 -0
- data/lib/git/commands/remote.rb +42 -0
- data/lib/git/commands/repack.rb +281 -0
- data/lib/git/commands/reset.rb +154 -0
- data/lib/git/commands/rev_parse.rb +304 -0
- data/lib/git/commands/revert/abort.rb +45 -0
- data/lib/git/commands/revert/continue.rb +62 -0
- data/lib/git/commands/revert/quit.rb +47 -0
- data/lib/git/commands/revert/skip.rb +44 -0
- data/lib/git/commands/revert/start.rb +158 -0
- data/lib/git/commands/revert.rb +29 -0
- data/lib/git/commands/rm.rb +113 -0
- data/lib/git/commands/show.rb +632 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +119 -0
- data/lib/git/commands/show_ref/exists.rb +80 -0
- data/lib/git/commands/show_ref/list.rb +149 -0
- data/lib/git/commands/show_ref/verify.rb +122 -0
- data/lib/git/commands/show_ref.rb +42 -0
- data/lib/git/commands/stash/apply.rb +81 -0
- data/lib/git/commands/stash/branch.rb +67 -0
- data/lib/git/commands/stash/clear.rb +43 -0
- data/lib/git/commands/stash/create.rb +60 -0
- data/lib/git/commands/stash/drop.rb +73 -0
- data/lib/git/commands/stash/list.rb +43 -0
- data/lib/git/commands/stash/pop.rb +87 -0
- data/lib/git/commands/stash/push.rb +112 -0
- data/lib/git/commands/stash/show.rb +158 -0
- data/lib/git/commands/stash/store.rb +72 -0
- data/lib/git/commands/stash.rb +38 -0
- data/lib/git/commands/status.rb +174 -0
- data/lib/git/commands/symbolic_ref/delete.rb +72 -0
- data/lib/git/commands/symbolic_ref/read.rb +99 -0
- data/lib/git/commands/symbolic_ref/update.rb +79 -0
- data/lib/git/commands/symbolic_ref.rb +38 -0
- data/lib/git/commands/tag/create.rb +142 -0
- data/lib/git/commands/tag/delete.rb +57 -0
- data/lib/git/commands/tag/list.rb +146 -0
- data/lib/git/commands/tag/verify.rb +71 -0
- data/lib/git/commands/tag.rb +26 -0
- data/lib/git/commands/update_ref/batch.rb +145 -0
- data/lib/git/commands/update_ref/delete.rb +90 -0
- data/lib/git/commands/update_ref/update.rb +103 -0
- data/lib/git/commands/update_ref.rb +42 -0
- data/lib/git/commands/version.rb +60 -0
- data/lib/git/commands/worktree/add.rb +139 -0
- data/lib/git/commands/worktree/list.rb +64 -0
- data/lib/git/commands/worktree/lock.rb +58 -0
- data/lib/git/commands/worktree/management_base.rb +51 -0
- data/lib/git/commands/worktree/move.rb +66 -0
- data/lib/git/commands/worktree/prune.rb +67 -0
- data/lib/git/commands/worktree/remove.rb +63 -0
- data/lib/git/commands/worktree/repair.rb +76 -0
- data/lib/git/commands/worktree/unlock.rb +47 -0
- data/lib/git/commands/worktree.rb +43 -0
- data/lib/git/commands/write_tree.rb +68 -0
- data/lib/git/commands.rb +88 -0
- data/lib/git/config.rb +72 -5
- data/lib/git/config_entry_info.rb +106 -0
- data/lib/git/configuring.rb +795 -0
- data/lib/git/detached_head_info.rb +57 -0
- data/lib/git/diff.rb +437 -86
- data/lib/git/diff_file_numstat_info.rb +31 -0
- data/lib/git/diff_file_patch_info.rb +136 -0
- data/lib/git/diff_file_raw_info.rb +129 -0
- data/lib/git/diff_info.rb +162 -0
- data/lib/git/diff_path_status.rb +107 -0
- data/lib/git/diff_result.rb +34 -0
- data/lib/git/diff_stats.rb +111 -0
- data/lib/git/dirstat_info.rb +102 -0
- data/lib/git/encoding_utils.rb +32 -1
- data/lib/git/errors.rb +285 -0
- data/lib/git/escaped_path.rb +57 -5
- data/lib/git/execution_context/global.rb +31 -0
- data/lib/git/execution_context/repository.rb +151 -0
- data/lib/git/execution_context.rb +559 -0
- data/lib/git/factories.rb +813 -0
- data/lib/git/file_ref.rb +77 -0
- data/lib/git/fsck_object.rb +56 -0
- data/lib/git/fsck_result.rb +132 -0
- data/lib/git/log.rb +306 -90
- data/lib/git/object.rb +563 -141
- data/lib/git/parsers/branch.rb +240 -0
- data/lib/git/parsers/cat_file.rb +111 -0
- data/lib/git/parsers/config_entry.rb +110 -0
- data/lib/git/parsers/diff.rb +792 -0
- data/lib/git/parsers/fsck.rb +144 -0
- data/lib/git/parsers/grep.rb +42 -0
- data/lib/git/parsers/ls_remote.rb +79 -0
- data/lib/git/parsers/ls_tree.rb +58 -0
- data/lib/git/parsers/remote.rb +162 -0
- data/lib/git/parsers/stash.rb +292 -0
- data/lib/git/parsers/status.rb +251 -0
- data/lib/git/parsers/tag.rb +341 -0
- data/lib/git/parsers/worktree.rb +185 -0
- data/lib/git/path_resolver.rb +206 -0
- data/lib/git/remote.rb +165 -12
- data/lib/git/remote_info.rb +203 -0
- data/lib/git/repository/branching.rb +964 -0
- data/lib/git/repository/committing.rb +246 -0
- data/lib/git/repository/context_helpers.rb +293 -0
- data/lib/git/repository/diffing.rb +785 -0
- data/lib/git/repository/inspecting.rb +252 -0
- data/lib/git/repository/logging.rb +410 -0
- data/lib/git/repository/maintenance.rb +65 -0
- data/lib/git/repository/merging.rb +451 -0
- data/lib/git/repository/object_operations.rb +1551 -0
- data/lib/git/repository/remote_operations.rb +984 -0
- data/lib/git/repository/shared_private.rb +120 -0
- data/lib/git/repository/staging.rb +587 -0
- data/lib/git/repository/stashing.rb +623 -0
- data/lib/git/repository/status_operations.rb +249 -0
- data/lib/git/repository/worktree_operations.rb +339 -0
- data/lib/git/repository.rb +484 -2
- data/lib/git/stash.rb +109 -12
- data/lib/git/stash_info.rb +102 -0
- data/lib/git/stashes.rb +169 -26
- data/lib/git/status.rb +308 -122
- data/lib/git/status_file_info.rb +258 -0
- data/lib/git/status_info.rb +189 -0
- data/lib/git/tag_delete_failure.rb +34 -0
- data/lib/git/tag_delete_result.rb +66 -0
- data/lib/git/tag_info.rb +99 -0
- data/lib/git/url.rb +15 -8
- data/lib/git/version.rb +113 -2
- data/lib/git/version_constraint.rb +85 -0
- data/lib/git/worktree.rb +150 -8
- data/lib/git/worktree_info.rb +128 -0
- data/lib/git/worktrees.rb +118 -13
- data/lib/git.rb +632 -234
- metadata +369 -54
- data/.github/stale.yml +0 -25
- data/.github/workflows/continuous_integration.yml +0 -49
- data/.gitignore +0 -10
- data/Dockerfile.changelog-rs +0 -12
- data/Gemfile +0 -5
- data/ISSUE_TEMPLATE.md +0 -15
- data/PULL_REQUEST_TEMPLATE.md +0 -9
- data/RELEASING.md +0 -70
- data/Rakefile +0 -60
- data/lib/git/base/factory.rb +0 -99
- data/lib/git/base.rb +0 -711
- data/lib/git/command_line_result.rb +0 -86
- data/lib/git/failed_error.rb +0 -53
- data/lib/git/git_execute_error.rb +0 -7
- data/lib/git/index.rb +0 -5
- data/lib/git/lib.rb +0 -1328
- data/lib/git/path.rb +0 -31
- data/lib/git/signaled_error.rb +0 -50
- data/lib/git/working_directory.rb +0 -4
data/README.md
CHANGED
|
@@ -3,425 +3,581 @@
|
|
|
3
3
|
# @title README
|
|
4
4
|
-->
|
|
5
5
|
|
|
6
|
-
# The
|
|
6
|
+
# The git gem
|
|
7
7
|
|
|
8
8
|
[](https://badge.fury.io/rb/git)
|
|
9
|
+
[](https://github.com/ruby-git/ruby-git/actions/workflows/continuous_integration.yml)
|
|
9
10
|
[](https://rubydoc.info/gems/git/)
|
|
10
|
-
[](https://rubydoc.info/gems/git/file/CHANGELOG.md)
|
|
13
|
+
[](https://conventionalcommits.org)
|
|
15
|
+
[](AI_POLICY.md)
|
|
16
|
+
[](LICENSE)
|
|
17
|
+
|
|
18
|
+
> **v5.0.0 is here.** This is a major release with a redesigned internal
|
|
19
|
+
> architecture, but most v4.x code runs unchanged thanks to compatibility
|
|
20
|
+
> shims. See [UPGRADING.md](UPGRADING.md) for the migration guide and
|
|
21
|
+
> [CHANGELOG.md](CHANGELOG.md) for full release notes.
|
|
22
|
+
|
|
23
|
+
- [Summary](#summary)
|
|
24
|
+
- [Install](#install)
|
|
25
|
+
- [Quick start](#quick-start)
|
|
26
|
+
- [Examples](#examples)
|
|
27
|
+
- [Gem configuration](#gem-configuration)
|
|
28
|
+
- [Git configuration](#git-configuration)
|
|
29
|
+
- [Full API](#full-api)
|
|
30
|
+
- [Errors raised by this gem](#errors-raised-by-this-gem)
|
|
31
|
+
- [Specifying and handling timeouts](#specifying-and-handling-timeouts)
|
|
32
|
+
- [Deprecations](#deprecations)
|
|
33
|
+
- [Platform limitations](#platform-limitations)
|
|
34
|
+
- [Regex metacharacters on Git for Windows](#regex-metacharacters-on-git-for-windows)
|
|
35
|
+
- [Project policies](#project-policies)
|
|
36
|
+
- [Ruby version support policy](#ruby-version-support-policy)
|
|
37
|
+
- [Git version support policy](#git-version-support-policy)
|
|
38
|
+
- [Deprecation policy](#deprecation-policy)
|
|
39
|
+
- [Release support policy](#release-support-policy)
|
|
40
|
+
- [Project announcements](#project-announcements)
|
|
41
|
+
- [2026-08-23: v5.x deprecations and the v6.0.0 roadmap](#2026-08-23-v5x-deprecations-and-the-v600-roadmap)
|
|
42
|
+
- [2026-07-28: v5.0.0 released](#2026-07-28-v500-released)
|
|
43
|
+
- [2026-01-07: AI policy introduced](#2026-01-07-ai-policy-introduced)
|
|
44
|
+
- [2025-07-09: Architectural redesign](#2025-07-09-architectural-redesign)
|
|
45
|
+
- [2025-07-07: We now use RuboCop](#2025-07-07-we-now-use-rubocop)
|
|
46
|
+
- [2025-06-06: Default branch rename](#2025-06-06-default-branch-rename)
|
|
47
|
+
- [2025-05-15: We've switched to Conventional Commits](#2025-05-15-weve-switched-to-conventional-commits)
|
|
48
|
+
|
|
49
|
+
## Summary
|
|
50
|
+
|
|
51
|
+
The [git gem](https://rubygems.org/gems/git) provides a Ruby interface to the `git`
|
|
52
|
+
command line.
|
|
53
|
+
|
|
54
|
+
Get a repository object by:
|
|
55
|
+
|
|
56
|
+
- opening an existing working copy with
|
|
57
|
+
[Git.open](https://rubydoc.info/gems/git/Git#open-class_method)
|
|
58
|
+
- initializing a new repository with
|
|
59
|
+
[Git.init](https://rubydoc.info/gems/git/Git#init-class_method)
|
|
60
|
+
- cloning a repository with
|
|
61
|
+
[Git.clone](https://rubydoc.info/gems/git/Git#clone-class_method)
|
|
62
|
+
|
|
63
|
+
[Git::Repository](https://rubydoc.info/gems/git/Git/Repository) documents the
|
|
64
|
+
methods you can call on a repository object.
|
|
13
65
|
|
|
14
|
-
|
|
15
|
-
create, read, and manipulate Git repositories by wrapping system calls to the `git`
|
|
16
|
-
command line. The API can be used for working with Git in complex interactions
|
|
17
|
-
including branching and merging, object inspection and manipulation, history, patch
|
|
18
|
-
generation and more.
|
|
66
|
+
## Install
|
|
19
67
|
|
|
20
|
-
|
|
68
|
+
This gem is a wrapper around the `git` command line, so a `git` executable (version
|
|
69
|
+
2.28.0 or greater) must be installed and on your `PATH`. See the [Git version support
|
|
70
|
+
policy](#git-version-support-policy) for details.
|
|
21
71
|
|
|
22
|
-
|
|
72
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
23
73
|
|
|
24
|
-
|
|
25
|
-
|
|
74
|
+
```shell
|
|
75
|
+
bundle add git
|
|
76
|
+
```
|
|
26
77
|
|
|
27
|
-
|
|
78
|
+
If you are not using bundler to manage dependencies, install the gem by executing:
|
|
28
79
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* Update the required Git command line version to at least 2.28
|
|
33
|
-
* Update how CLI commands are called to use the [process_executer](https://github.com/main-branch/process_executer)
|
|
34
|
-
gem which is built on top of [Kernel.spawn](https://ruby-doc.org/3.3.0/Kernel.html#method-i-spawn).
|
|
35
|
-
See [PR #617](https://github.com/ruby-git/ruby-git/pull/617) for more details
|
|
36
|
-
on the motivation for this implementation.
|
|
80
|
+
```shell
|
|
81
|
+
gem install git
|
|
82
|
+
```
|
|
37
83
|
|
|
38
|
-
|
|
39
|
-
the feedback received during the pre-release period.
|
|
84
|
+
## Quick start
|
|
40
85
|
|
|
41
|
-
|
|
42
|
-
|
|
86
|
+
All functionality for this gem starts with the top-level
|
|
87
|
+
[`Git`](https://rubydoc.info/gems/git/Git) module. Use this module to run non-repo
|
|
88
|
+
scoped `git` commands such as `config`.
|
|
43
89
|
|
|
44
|
-
|
|
90
|
+
The `Git` module also has factory methods such as `open`, `clone`, and `init` which
|
|
91
|
+
return a [`Git::Repository`](https://rubydoc.info/gems/git/Git/Repository) object. Use
|
|
92
|
+
the `Git::Repository` object to run repo-specific `git` commands such as `add`,
|
|
93
|
+
`commit`, `push`, and `log`.
|
|
45
94
|
|
|
46
|
-
|
|
95
|
+
Clone, read status, and log:
|
|
47
96
|
|
|
48
|
-
|
|
97
|
+
```ruby
|
|
98
|
+
require 'git'
|
|
49
99
|
|
|
50
|
-
|
|
100
|
+
repo = Git.clone('https://github.com/ruby-git/ruby-git.git', 'ruby-git')
|
|
101
|
+
repo.status_info.changed.each_key { |path| puts "changed: #{path}" }
|
|
102
|
+
repo.log(5).execute.each { |c| puts c.message }
|
|
103
|
+
```
|
|
51
104
|
|
|
52
|
-
|
|
105
|
+
Open an existing repo and commit:
|
|
53
106
|
|
|
54
|
-
|
|
107
|
+
```ruby
|
|
108
|
+
require 'git'
|
|
55
109
|
|
|
56
|
-
|
|
110
|
+
repo = Git.open('/path/to/repo')
|
|
111
|
+
repo.add(all: true)
|
|
112
|
+
repo.commit('chore: update files')
|
|
113
|
+
repo.push
|
|
114
|
+
```
|
|
57
115
|
|
|
58
|
-
|
|
59
|
-
* initializing a new repository with [Git.init](https://rubydoc.info/gems/git/Git#init-class_method)
|
|
60
|
-
* cloning a repository with [Git.clone](https://rubydoc.info/gems/git/Git#clone-class_method)
|
|
116
|
+
Initialize a new repo and make the first commit:
|
|
61
117
|
|
|
62
|
-
|
|
118
|
+
```ruby
|
|
119
|
+
require 'git'
|
|
63
120
|
|
|
64
|
-
|
|
121
|
+
repo = Git.init('my_project')
|
|
122
|
+
repo.add(all: true)
|
|
123
|
+
repo.commit('initial commit')
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Examples
|
|
127
|
+
|
|
128
|
+
These examples cover configuring the gem and git itself. For the full set of
|
|
129
|
+
repository operations, see [Full API](#full-api) below.
|
|
130
|
+
|
|
131
|
+
### Gem configuration
|
|
132
|
+
|
|
133
|
+
Configure the git gem:
|
|
65
134
|
|
|
66
|
-
|
|
135
|
+
```ruby
|
|
136
|
+
Git.configure do |config|
|
|
137
|
+
config.binary_path = '/usr/local/bin/git'
|
|
138
|
+
config.git_ssh = 'ssh -i ~/.ssh/id_rsa'
|
|
139
|
+
end
|
|
67
140
|
|
|
141
|
+
# or
|
|
142
|
+
|
|
143
|
+
Git.config.binary_path = '/usr/local/bin/git'
|
|
144
|
+
Git.config.git_ssh = 'ssh -i ~/.ssh/id_rsa'
|
|
68
145
|
```
|
|
69
|
-
|
|
146
|
+
|
|
147
|
+
How SSH configuration is determined:
|
|
148
|
+
|
|
149
|
+
- If `git_ssh` is not specified in the API call, the global config (`Git.configure {
|
|
150
|
+
|c| c.git_ssh = ... }`) is used.
|
|
151
|
+
- If `git_ssh: nil` is specified, SSH is disabled for that instance (no SSH key or
|
|
152
|
+
script will be used).
|
|
153
|
+
- If `git_ssh` is a non-empty string, it is used for that instance (overriding the
|
|
154
|
+
global config).
|
|
155
|
+
|
|
156
|
+
You can also specify a custom SSH script on a per-repository basis:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
# Use a specific SSH key for a single repository
|
|
160
|
+
git = Git.open('/path/to/repo', git_ssh: 'ssh -i /path/to/private_key')
|
|
161
|
+
|
|
162
|
+
# Or when cloning
|
|
163
|
+
git = Git.clone('git@github.com:user/repo.git', 'local-dir',
|
|
164
|
+
git_ssh: 'ssh -i /path/to/private_key')
|
|
165
|
+
|
|
166
|
+
# Or when initializing
|
|
167
|
+
git = Git.init('new-repo', git_ssh: 'ssh -i /path/to/private_key')
|
|
70
168
|
```
|
|
71
169
|
|
|
72
|
-
|
|
170
|
+
This is especially useful in multi-threaded applications where different repositories
|
|
171
|
+
require different SSH credentials.
|
|
172
|
+
|
|
173
|
+
### Git configuration
|
|
73
174
|
|
|
175
|
+
Read and set `git` configuration values (via `git config`):
|
|
74
176
|
|
|
75
|
-
|
|
177
|
+
```ruby
|
|
178
|
+
# Global config (in ~/.gitconfig)
|
|
179
|
+
entries = Git.config_list(global: true) # returns Array<Git::ConfigEntryInfo>
|
|
180
|
+
entry = Git.config_get('user.email', global: true) # returns Git::ConfigEntryInfo or nil
|
|
181
|
+
email = entry&.value # => "user@example.com" or nil
|
|
182
|
+
Git.config_set('user.email', 'user@example.com', global: true)
|
|
183
|
+
|
|
184
|
+
# Repository config
|
|
185
|
+
repo = Git.open('path/to/repo')
|
|
186
|
+
entries = repo.config_list # returns Array<Git::ConfigEntryInfo>
|
|
187
|
+
entry = repo.config_get('user.email') # returns Git::ConfigEntryInfo or nil
|
|
188
|
+
email = entry&.value # => "anotheruser@example.com" or nil
|
|
189
|
+
repo.config_set('user.email', 'anotheruser@example.com')
|
|
190
|
+
```
|
|
76
191
|
|
|
77
|
-
|
|
192
|
+
### Full API
|
|
78
193
|
|
|
79
|
-
|
|
194
|
+
The quick start and the configuration sections above cover the most common setup.
|
|
195
|
+
The [`Git::Repository`](https://rubydoc.info/gems/git/Git/Repository) reference
|
|
196
|
+
covers everything else: reading history, diffs, branches, remotes, worktrees,
|
|
197
|
+
staging, and low-level index and tree work. It documents every method and the object
|
|
198
|
+
type each one returns (such as `Git::Log`, `Git::Object::Commit`, `Git::Diff`,
|
|
199
|
+
`Git::Branch`, and `Git::Worktree`), so you can follow the links from a method to
|
|
200
|
+
the full API of its result.
|
|
80
201
|
|
|
81
|
-
|
|
202
|
+
## Errors raised by this gem
|
|
82
203
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
directory, in the index and in the repository. Similar to running 'git status' on the command line to determine untracked and changed files.
|
|
204
|
+
The git gem raises only `ArgumentError` or errors that subclass `Git::Error`. It
|
|
205
|
+
does not explicitly raise any other types of errors.
|
|
86
206
|
|
|
87
|
-
|
|
207
|
+
Rescue `Git::Error` to catch any runtime error raised by this gem, unless you need
|
|
208
|
+
more specific error handling.
|
|
88
209
|
|
|
89
|
-
|
|
210
|
+
```ruby
|
|
211
|
+
begin
|
|
212
|
+
# some git operation
|
|
213
|
+
rescue Git::Error => e
|
|
214
|
+
puts "An error occurred: #{e.message}"
|
|
215
|
+
end
|
|
216
|
+
```
|
|
90
217
|
|
|
91
|
-
|
|
92
|
-
like:
|
|
218
|
+
See [`Git::Error`](https://rubydoc.info/gems/git/Git/Error) for more information.
|
|
93
219
|
|
|
94
|
-
|
|
220
|
+
## Specifying and handling timeouts
|
|
95
221
|
|
|
96
|
-
|
|
222
|
+
Set a timeout for git command line operations either globally or per method call for
|
|
223
|
+
methods that accept a `:timeout` parameter.
|
|
97
224
|
|
|
98
|
-
|
|
225
|
+
The timeout value must be a real, non-negative `Numeric` value that specifies the
|
|
226
|
+
number of seconds a `git` command is given to complete before being sent a KILL
|
|
227
|
+
signal. This library may hang if the `git` command does not terminate after
|
|
228
|
+
receiving the KILL signal.
|
|
99
229
|
|
|
100
|
-
|
|
230
|
+
When a command times out, the gem kills it with the `SIGKILL` signal and raises a
|
|
231
|
+
`Git::TimeoutError`. This error derives from `Git::SignaledError` and `Git::Error`.
|
|
101
232
|
|
|
102
|
-
|
|
233
|
+
If the timeout value is `0` or `nil`, no timeout is enforced.
|
|
103
234
|
|
|
104
|
-
|
|
235
|
+
If a method accepts a `:timeout` parameter and receives a non-nil value, that value
|
|
236
|
+
overrides the global timeout. In this context, a value of `nil`, which is usually
|
|
237
|
+
the default, uses the global timeout value, and a value of `0` turns off timeout
|
|
238
|
+
enforcement for that method call no matter what the global value is.
|
|
105
239
|
|
|
106
|
-
|
|
240
|
+
To set a global timeout, use the `Git.config` object:
|
|
107
241
|
|
|
108
242
|
```ruby
|
|
109
|
-
|
|
243
|
+
Git.config.timeout = nil # a value of nil or 0 means no timeout is enforced
|
|
244
|
+
Git.config.timeout = 1.5 # can be any real, non-negative Numeric interpreted as number of seconds
|
|
110
245
|
```
|
|
111
246
|
|
|
112
|
-
|
|
247
|
+
The global timeout can be overridden for a specific method if the method accepts a
|
|
248
|
+
`:timeout` parameter:
|
|
249
|
+
|
|
113
250
|
```ruby
|
|
114
|
-
|
|
251
|
+
repo_url = 'https://github.com/ruby-git/ruby-git.git'
|
|
252
|
+
Git.clone(repo_url) # Use the global timeout value
|
|
253
|
+
Git.clone(repo_url, timeout: nil) # Also uses the global timeout value
|
|
254
|
+
Git.clone(repo_url, timeout: 0) # Do not enforce a timeout
|
|
255
|
+
Git.clone(repo_url, timeout: 10.5) # Timeout after 10.5 seconds raising Git::TimeoutError
|
|
115
256
|
```
|
|
116
257
|
|
|
117
|
-
|
|
258
|
+
If the command takes too long, the gem raises `Git::TimeoutError`:
|
|
118
259
|
|
|
119
260
|
```ruby
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
261
|
+
begin
|
|
262
|
+
Git.clone(repo_url, timeout: 10)
|
|
263
|
+
rescue Git::TimeoutError => e
|
|
264
|
+
e.result.tap do |r|
|
|
265
|
+
r.class #=> Git::CommandLineResult
|
|
266
|
+
r.status #=> #<Process::Status: pid 62173 SIGKILL (signal 9)>
|
|
267
|
+
r.status.timeout? #=> true
|
|
268
|
+
r.git_cmd # The git command ran as an array of strings
|
|
269
|
+
r.stdout # The command's output to stdout until it was terminated
|
|
270
|
+
r.stderr # The command's output to stderr until it was terminated
|
|
271
|
+
end
|
|
126
272
|
end
|
|
127
273
|
```
|
|
128
274
|
|
|
129
|
-
|
|
275
|
+
## Deprecations
|
|
276
|
+
|
|
277
|
+
This gem uses ActiveSupport's deprecation mechanism to report deprecation warnings.
|
|
130
278
|
|
|
131
|
-
|
|
279
|
+
You can silence deprecation warnings by adding this line to your source code:
|
|
132
280
|
|
|
133
281
|
```ruby
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
g.index
|
|
137
|
-
g.index.readable?
|
|
138
|
-
g.index.writable?
|
|
139
|
-
g.repo
|
|
140
|
-
g.dir
|
|
141
|
-
|
|
142
|
-
g.log # returns a Git::Log object, which is an Enumerator of Git::Commit objects
|
|
143
|
-
g.log(200)
|
|
144
|
-
g.log.since('2 weeks ago')
|
|
145
|
-
g.log.between('v2.5', 'v2.6')
|
|
146
|
-
g.log.each {|l| puts l.sha }
|
|
147
|
-
g.gblob('v2.5:Makefile').log.since('2 weeks ago')
|
|
148
|
-
|
|
149
|
-
g.object('HEAD^').to_s # git show / git rev-parse
|
|
150
|
-
g.object('HEAD^').contents
|
|
151
|
-
g.object('v2.5:Makefile').size
|
|
152
|
-
g.object('v2.5:Makefile').sha
|
|
153
|
-
|
|
154
|
-
g.gtree(treeish)
|
|
155
|
-
g.gblob(treeish)
|
|
156
|
-
g.gcommit(treeish)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
commit = g.gcommit('1cc8667014381')
|
|
160
|
-
|
|
161
|
-
commit.gtree
|
|
162
|
-
commit.parent.sha
|
|
163
|
-
commit.parents.size
|
|
164
|
-
commit.author.name
|
|
165
|
-
commit.author.email
|
|
166
|
-
commit.author.date.strftime("%m-%d-%y")
|
|
167
|
-
commit.committer.name
|
|
168
|
-
commit.date.strftime("%m-%d-%y")
|
|
169
|
-
commit.message
|
|
170
|
-
|
|
171
|
-
tree = g.gtree("HEAD^{tree}")
|
|
172
|
-
|
|
173
|
-
tree.blobs
|
|
174
|
-
tree.subtrees
|
|
175
|
-
tree.children # blobs and subtrees
|
|
176
|
-
|
|
177
|
-
g.revparse('v2.5:Makefile')
|
|
178
|
-
|
|
179
|
-
g.branches # returns Git::Branch objects
|
|
180
|
-
g.branches.local
|
|
181
|
-
g.current_branch
|
|
182
|
-
g.branches.remote
|
|
183
|
-
g.branches[:master].gcommit
|
|
184
|
-
g.branches['origin/master'].gcommit
|
|
185
|
-
|
|
186
|
-
g.grep('hello') # implies HEAD
|
|
187
|
-
g.blob('v2.5:Makefile').grep('hello')
|
|
188
|
-
g.tag('v2.5').grep('hello', 'docs/')
|
|
189
|
-
g.describe()
|
|
190
|
-
g.describe('0djf2aa')
|
|
191
|
-
g.describe('HEAD', {:all => true, :tags => true})
|
|
192
|
-
|
|
193
|
-
g.diff(commit1, commit2).size
|
|
194
|
-
g.diff(commit1, commit2).stats
|
|
195
|
-
g.diff(commit1, commit2).name_status
|
|
196
|
-
g.gtree('v2.5').diff('v2.6').insertions
|
|
197
|
-
g.diff('gitsearch1', 'v2.5').path('lib/')
|
|
198
|
-
g.diff('gitsearch1', @git.gtree('v2.5'))
|
|
199
|
-
g.diff('gitsearch1', 'v2.5').path('docs/').patch
|
|
200
|
-
g.gtree('v2.5').diff('v2.6').patch
|
|
201
|
-
|
|
202
|
-
g.gtree('v2.5').diff('v2.6').each do |file_diff|
|
|
203
|
-
puts file_diff.path
|
|
204
|
-
puts file_diff.patch
|
|
205
|
-
puts file_diff.blob(:src).contents
|
|
206
|
-
end
|
|
282
|
+
Git::Deprecation.behavior = :silence
|
|
283
|
+
```
|
|
207
284
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
285
|
+
Or by setting this environment variable before loading the gem:
|
|
286
|
+
|
|
287
|
+
```sh
|
|
288
|
+
GIT_DEPRECATION_BEHAVIOR=silence
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Accepted environment variable values are the behavior names supported by your
|
|
292
|
+
installed ActiveSupport version.
|
|
215
293
|
|
|
216
|
-
|
|
217
|
-
|
|
294
|
+
If `GIT_DEPRECATION_BEHAVIOR` is set to an unsupported value, loading the gem
|
|
295
|
+
raises `ArgumentError` with the accepted behavior names.
|
|
218
296
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
#
|
|
223
|
-
g = Git.clone(
|
|
224
|
-
git_uri, destination_path,
|
|
225
|
-
:config => [
|
|
226
|
-
'core.sshCommand=ssh -i /home/user/.ssh/id_rsa',
|
|
227
|
-
'submodule.recurse=true'
|
|
228
|
-
]
|
|
229
|
-
)
|
|
297
|
+
See [the Active Support Deprecation
|
|
298
|
+
documentation](https://api.rubyonrails.org/classes/ActiveSupport/Deprecation.html)
|
|
299
|
+
for more details.
|
|
230
300
|
|
|
231
|
-
|
|
301
|
+
Before upgrading the git gem to the next major version, follow the upgrade procedure
|
|
302
|
+
in [UPGRADING.md](UPGRADING.md#upgrading-to-v600). It turns the warnings into errors so
|
|
303
|
+
that you cannot miss one.
|
|
232
304
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
g.show('v2.8', 'README.md')
|
|
305
|
+
For the full list of deprecated methods and their replacements, see
|
|
306
|
+
[UPGRADING.md](UPGRADING.md).
|
|
236
307
|
|
|
237
|
-
|
|
238
|
-
Git.ls_remote('/path/to/local/repo')
|
|
239
|
-
Git.ls_remote() # same as Git.ls_remote('.')
|
|
308
|
+
## Platform limitations
|
|
240
309
|
|
|
241
|
-
Git
|
|
310
|
+
### Regex metacharacters on Git for Windows
|
|
311
|
+
|
|
312
|
+
On Git for Windows, git's regex engine matches **bytes** rather than characters. A
|
|
313
|
+
metacharacter such as `.`, or a POSIX character class such as `[[:alpha:]]`, therefore
|
|
314
|
+
never matches a whole multi-byte character. The same call matches on Linux and macOS.
|
|
315
|
+
|
|
316
|
+
The failure is silent. Nothing raises, and the result is indistinguishable from a
|
|
317
|
+
pattern that genuinely does not occur:
|
|
318
|
+
|
|
319
|
+
```ruby
|
|
320
|
+
# File content, commit message, and config value are all 'ÄPFEL sind gut'.
|
|
321
|
+
# 'Ä' is two bytes in UTF-8 (C3 84), so '.' has to match both to match the character.
|
|
322
|
+
|
|
323
|
+
repo.grep('^.PFEL') # => {} on Windows, matches elsewhere
|
|
324
|
+
repo.log.grep('^.PFEL').execute.size # => 0 on Windows, 1 elsewhere
|
|
325
|
+
repo.config_get_all('test.desc', '^.PFEL') # => [] on Windows, matches elsewhere
|
|
242
326
|
```
|
|
243
327
|
|
|
244
|
-
|
|
328
|
+
This is a property of the regex engine git bundles on that platform, not something the
|
|
329
|
+
gem sets. It is unaffected by the locale: the behavior is identical under `en_US.UTF-8`,
|
|
330
|
+
`C.UTF-8`, `C`, and with no `LC_ALL` set at all. Literal (metacharacter-free) patterns
|
|
331
|
+
and case-insensitive matching are unaffected on every platform.
|
|
332
|
+
|
|
333
|
+
**Workaround.** Perl-compatible regular expressions do match characters on Git for
|
|
334
|
+
Windows, so the surfaces that can reach a PCRE engine accept an opt-in selector:
|
|
245
335
|
|
|
246
336
|
```ruby
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
:index => '/tmp/index'} )
|
|
252
|
-
|
|
253
|
-
# Clone from a git url
|
|
254
|
-
git_url = 'https://github.com/ruby-git/ruby-git.git'
|
|
255
|
-
# Clone into the ruby-git directory
|
|
256
|
-
g = Git.clone(git_url)
|
|
257
|
-
|
|
258
|
-
# Clone into /tmp/clone/ruby-git-clean
|
|
259
|
-
name = 'ruby-git-clean'
|
|
260
|
-
path = '/tmp/clone'
|
|
261
|
-
g = Git.clone(git_url, name, :path => path)
|
|
262
|
-
g.dir #=> /tmp/clone/ruby-git-clean
|
|
263
|
-
|
|
264
|
-
g.config('user.name', 'Scott Chacon')
|
|
265
|
-
g.config('user.email', 'email@email.com')
|
|
266
|
-
|
|
267
|
-
# Clone can take a filter to tell the serve to send a partial clone
|
|
268
|
-
g = Git.clone(git_url, name, :path => path, :filter => 'tree:0')
|
|
269
|
-
|
|
270
|
-
# Clone can take an optional logger
|
|
271
|
-
logger = Logger.new
|
|
272
|
-
g = Git.clone(git_url, NAME, :log => logger)
|
|
273
|
-
|
|
274
|
-
g.add # git add -- "."
|
|
275
|
-
g.add(:all=>true) # git add --all -- "."
|
|
276
|
-
g.add('file_path') # git add -- "file_path"
|
|
277
|
-
g.add(['file_path_1', 'file_path_2']) # git add -- "file_path_1" "file_path_2"
|
|
278
|
-
|
|
279
|
-
g.remove() # git rm -f -- "."
|
|
280
|
-
g.remove('file.txt') # git rm -f -- "file.txt"
|
|
281
|
-
g.remove(['file.txt', 'file2.txt']) # git rm -f -- "file.txt" "file2.txt"
|
|
282
|
-
g.remove('file.txt', :recursive => true) # git rm -f -r -- "file.txt"
|
|
283
|
-
g.remove('file.txt', :cached => true) # git rm -f --cached -- "file.txt"
|
|
284
|
-
|
|
285
|
-
g.commit('message')
|
|
286
|
-
g.commit_all('message')
|
|
287
|
-
|
|
288
|
-
# Sign a commit using the gpg key configured in the user.signingkey config setting
|
|
289
|
-
g.config('user.signingkey', '0A46826A')
|
|
290
|
-
g.commit('message', gpg_sign: true)
|
|
291
|
-
|
|
292
|
-
# Sign a commit using a specified gpg key
|
|
293
|
-
key_id = '0A46826A'
|
|
294
|
-
g.commit('message', gpg_sign: key_id)
|
|
295
|
-
|
|
296
|
-
# Skip signing a commit (overriding any global gpgsign setting)
|
|
297
|
-
g.commit('message', no_gpg_sign: true)
|
|
298
|
-
|
|
299
|
-
g = Git.clone(repo, 'myrepo')
|
|
300
|
-
g.chdir do
|
|
301
|
-
new_file('test-file', 'blahblahblah')
|
|
302
|
-
g.status.changed.each do |file|
|
|
303
|
-
puts file.blob(:index).contents
|
|
304
|
-
end
|
|
305
|
-
end
|
|
337
|
+
repo.grep('^.PFEL', nil, perl_regexp: true) # matches on every platform
|
|
338
|
+
repo.log.perl_regexp.grep('^.PFEL').execute # matches on every platform
|
|
339
|
+
repo.full_log_commits(grep: '^.PFEL', perl_regexp: true)
|
|
340
|
+
```
|
|
306
341
|
|
|
307
|
-
|
|
308
|
-
g.reset_hard(Git::Commit)
|
|
342
|
+
Two caveats:
|
|
309
343
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
344
|
+
- **PCRE is a different dialect.** Git's other modes are POSIX basic regular
|
|
345
|
+
expressions (the default) and POSIX extended regular expressions (selected
|
|
346
|
+
explicitly). Selecting PCRE is a deliberate choice by the caller, so the gem does
|
|
347
|
+
not substitute it automatically based on the host.
|
|
348
|
+
- **PCRE must be compiled in.** Git for Windows and the mainstream Linux and macOS
|
|
349
|
+
packages ship it, but git built without `USE_LIBPCRE` fails with `cannot use
|
|
350
|
+
Perl-compatible regexes...`.
|
|
315
351
|
|
|
316
|
-
|
|
317
|
-
|
|
352
|
+
**There is no workaround for `git config` value patterns.** They are POSIX extended
|
|
353
|
+
regular expressions with no PCRE mode, so `config_get`, `config_get_all`,
|
|
354
|
+
`config_get_regexp`, `config_replace_all`, `config_unset`, and `config_unset_all` cannot
|
|
355
|
+
match a metacharacter against a non-ASCII character on Git for Windows. Match on ASCII
|
|
356
|
+
text or an exact value instead.
|
|
318
357
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
358
|
+
`config_replace_all` deserves particular care, because there the failure is worse than
|
|
359
|
+
an empty result. When the value pattern selects nothing, `git config --replace-all`
|
|
360
|
+
*adds* the new value as an additional entry rather than replacing one, and exits zero:
|
|
322
361
|
|
|
323
|
-
|
|
324
|
-
|
|
362
|
+
```ruby
|
|
363
|
+
# Existing value of test.desc is 'ÄPFEL sind gut'
|
|
364
|
+
repo.config_replace_all('test.desc', 'NEW', '^.PFEL')
|
|
325
365
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
g.merge(g.branch('master'))
|
|
331
|
-
g.merge([branch1, branch2])
|
|
366
|
+
repo.config_get_all('test.desc').map(&:value)
|
|
367
|
+
# => ["NEW"] elsewhere, replaced as intended
|
|
368
|
+
# => ["ÄPFEL sind gut", "NEW"] on Windows, original kept and duplicate added
|
|
369
|
+
```
|
|
332
370
|
|
|
333
|
-
|
|
371
|
+
So a replace can silently leave the original value in place and add a second entry beside
|
|
372
|
+
it. Confirm with `config_get_all` when the key must end up single-valued.
|
|
373
|
+
|
|
374
|
+
## Project policies
|
|
334
375
|
|
|
335
|
-
|
|
336
|
-
|
|
376
|
+
These documents set expectations for behavior, contribution workflows, AI-assisted
|
|
377
|
+
changes, decision making, maintainer roles, and licensing. Please review them before
|
|
378
|
+
opening issues or pull requests.
|
|
379
|
+
|
|
380
|
+
| Document | Description |
|
|
381
|
+
| -------- | ----------- |
|
|
382
|
+
| [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) | We follow the Ruby community Code of Conduct; expect respectful, harassment-free participation and report concerns to maintainers. |
|
|
383
|
+
| [CONTRIBUTING](CONTRIBUTING.md) | How to report issues, submit PRs with Conventional Commits, meet coding/testing standards, and follow the Code of Conduct. |
|
|
384
|
+
| [AI_POLICY](AI_POLICY.md) | AI-assisted contributions are welcome. Contributors are expected to read and apply the AI Policy, and ensure any AI-assisted work meets our quality, security, and licensing standards. |
|
|
385
|
+
| [Ruby version support policy](#ruby-version-support-policy) | Supported Ruby runtimes and platforms; bump decisions and CI coverage expectations. |
|
|
386
|
+
| [Git version support policy](#git-version-support-policy) | Minimum supported git version and how version bumps are communicated and enforced. |
|
|
387
|
+
| [Deprecation policy](#deprecation-policy) | When an API may be removed, what a deprecation warning says, and how to upgrade across a major version. |
|
|
388
|
+
| [Release support policy](#release-support-policy) | Which branch releases what, and how long each major series is supported. |
|
|
389
|
+
| [GOVERNANCE](GOVERNANCE.md) | Principles-first governance defining maintainer/project lead roles, least-privilege access, consensus/majority decisions, and nomination/emeritus steps. |
|
|
390
|
+
| [MAINTAINERS](MAINTAINERS.md) | Lists active maintainers (Project Lead noted) and emeritus alumni with links; see governance for role scope. |
|
|
391
|
+
| [LICENSE](LICENSE) | MIT License terms for using, modifying, and redistributing this project. |
|
|
337
392
|
|
|
338
|
-
|
|
339
|
-
g.remote(name).fetch
|
|
340
|
-
g.remote(name).remove
|
|
341
|
-
g.remote(name).merge
|
|
342
|
-
g.remote(name).merge(branch)
|
|
393
|
+
### Ruby version support policy
|
|
343
394
|
|
|
344
|
-
|
|
345
|
-
g.fetch(g.remotes.first)
|
|
346
|
-
g.fetch('origin', {:ref => 'some/ref/head'} )
|
|
347
|
-
g.fetch(all: true, force: true, depth: 2)
|
|
348
|
-
g.fetch('origin', {:'update-head-ok' => true})
|
|
395
|
+
This gem is expected to function correctly on:
|
|
349
396
|
|
|
350
|
-
|
|
351
|
-
|
|
397
|
+
- All [non-EOL versions](https://www.ruby-lang.org/en/downloads/branches/) of the MRI
|
|
398
|
+
Ruby on Mac, Linux, and Windows
|
|
399
|
+
- The latest version of JRuby 9.4+ on Linux
|
|
400
|
+
- The latest version of TruffleRuby 24+ on Linux
|
|
352
401
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
402
|
+
This project intends to support the latest version of JRuby on Windows once
|
|
403
|
+
the [process_executer](https://github.com/main-branch/process_executer) gem properly
|
|
404
|
+
supports subprocess status reporting on JRuby for Windows (see
|
|
405
|
+
[main-branch/process_executer#156](https://github.com/main-branch/process_executer/issues/156)).
|
|
357
406
|
|
|
358
|
-
|
|
359
|
-
:a | :annotate
|
|
360
|
-
:d
|
|
361
|
-
:f
|
|
362
|
-
:m | :message
|
|
363
|
-
:s
|
|
407
|
+
### Git version support policy
|
|
364
408
|
|
|
365
|
-
|
|
409
|
+
This gem requires git version 2.28.0 or greater as specified in the gemspec. This
|
|
410
|
+
requirement reflects:
|
|
366
411
|
|
|
367
|
-
|
|
412
|
+
- The minimum git version necessary to support all features provided by this gem
|
|
413
|
+
- A reasonable balance between supporting older systems and using modern git
|
|
414
|
+
capabilities
|
|
415
|
+
- The practical limitations of testing across multiple git versions in CI
|
|
368
416
|
|
|
369
|
-
|
|
370
|
-
|
|
417
|
+
Git 2.28.0 was released on July 27, 2020. While this gem may work with earlier
|
|
418
|
+
versions of git, compatibility with versions prior to 2.28.0 is not tested or
|
|
419
|
+
guaranteed. Users on older git versions should upgrade to at least 2.28.0.
|
|
371
420
|
|
|
372
|
-
|
|
373
|
-
|
|
421
|
+
The supported git version may be increased in future major or minor releases of this
|
|
422
|
+
gem as new git features are adopted or as maintaining backward compatibility becomes
|
|
423
|
+
impractical. Such changes will be documented in the CHANGELOG and release notes.
|
|
374
424
|
|
|
375
|
-
|
|
376
|
-
g.push('origin', all: true)
|
|
425
|
+
### Deprecation policy
|
|
377
426
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
427
|
+
This gem removes an API only in a major release, and only after a normal release
|
|
428
|
+
deprecated it with a runtime warning and documented its replacement in
|
|
429
|
+
[UPGRADING.md](UPGRADING.md). A normal release is one that is not a pre-release. The
|
|
430
|
+
warning names the major release that removes the API once that is decided. Until then
|
|
431
|
+
it says the API will be removed in a future major release.
|
|
432
|
+
|
|
433
|
+
The recommended way to upgrade across a major version:
|
|
434
|
+
|
|
435
|
+
1. Upgrade to the latest release of the major series you are on.
|
|
436
|
+
2. Set `GIT_DEPRECATION_BEHAVIOR=raise` (or `Git::Deprecation.behavior = :raise`) in
|
|
437
|
+
your test suite and, if possible, staging.
|
|
438
|
+
3. Fix each deprecation using the entries in [UPGRADING.md](UPGRADING.md) until the
|
|
439
|
+
suite is clean.
|
|
440
|
+
4. Upgrade to the next major release.
|
|
441
|
+
|
|
442
|
+
Because every deprecation warning is present in the last release of a major series,
|
|
443
|
+
this procedure finds every change the next major requires. The version-specific steps
|
|
444
|
+
are in [UPGRADING.md](UPGRADING.md#upgrading-to-v600). See
|
|
445
|
+
[Deprecations](#deprecations) for how to configure the warnings.
|
|
446
|
+
|
|
447
|
+
### Release support policy
|
|
448
|
+
|
|
449
|
+
All development happens on `main`, which releases the next version of the gem,
|
|
450
|
+
including the next major version. The next release from `main` is v6.0.0. Every
|
|
451
|
+
further v5.x release is cut from `5.x`.
|
|
452
|
+
|
|
453
|
+
Each supported previous major series is maintained on a branch named for that
|
|
454
|
+
series, currently `5.x` and `4.x`. These branches receive bug fixes and security
|
|
455
|
+
fixes, and backward-compatible features at the maintainers' discretion. Fixes land on
|
|
456
|
+
`main` first and are backported, except a fix for a problem that exists only in a
|
|
457
|
+
maintenance branch, which targets that branch directly.
|
|
458
|
+
|
|
459
|
+
Support for a major series ends when the second major after it is released. v4.x is
|
|
460
|
+
supported until v6.0.0 ships, and v5.x until v7.0.0.
|
|
461
|
+
|
|
462
|
+
## Project announcements
|
|
463
|
+
|
|
464
|
+
### 2026-08-23: v5.x deprecations and the v6.0.0 roadmap
|
|
465
|
+
|
|
466
|
+
The road to v6.0.0 is now planned and public. The remaining ActiveRecord-style
|
|
467
|
+
classes (`Git::Branch`, `Git::Remote`, `Git::Stash`, `Git::Worktree`,
|
|
468
|
+
`Git::Object::Tag`, `Git::Status`, `Git::Author`, and their collections) will be
|
|
469
|
+
deprecated during the v5.x series in favor of the immutable `*Info` value-object
|
|
470
|
+
APIs. v6.0.0 will remove each deprecated class once a normal v5.x release has carried
|
|
471
|
+
its deprecation warning and UPGRADING.md entry, per the
|
|
472
|
+
[Deprecation policy](#deprecation-policy). v6.0.0 will not ship until every planned
|
|
473
|
+
deprecation has shipped that way. v6.0.0 also raises the version floors: git ≥ 2.42.0,
|
|
474
|
+
Ruby ≥ 3.4.
|
|
475
|
+
|
|
476
|
+
[Issue #1717](https://github.com/ruby-git/ruby-git/issues/1717) is the living
|
|
477
|
+
roadmap, tracking scope, sequencing, and status. If your code uses the classes
|
|
478
|
+
above, you can start migrating now. Each deprecation names its replacement, and
|
|
479
|
+
[UPGRADING.md](UPGRADING.md) carries the migration guide as releases ship.
|
|
480
|
+
|
|
481
|
+
### 2026-07-28: v5.0.0 released
|
|
482
|
+
|
|
483
|
+
We have published [`git v5.0.0`](https://rubygems.org/gems/git/versions/5.0.0), the
|
|
484
|
+
first stable release of the v5.x series, after five public beta releases in June and
|
|
485
|
+
July 2026.
|
|
383
486
|
|
|
384
|
-
|
|
487
|
+
**v5.0.0 is a major release with breaking changes.** See
|
|
488
|
+
[UPGRADING.md](UPGRADING.md) for the complete migration guide.
|
|
489
|
+
|
|
490
|
+
To install:
|
|
385
491
|
|
|
386
492
|
```ruby
|
|
387
|
-
|
|
493
|
+
gem 'git', '~> 5.0'
|
|
494
|
+
```
|
|
388
495
|
|
|
389
|
-
|
|
390
|
-
g.read_tree(tree1, :prefix => 'hi/')
|
|
496
|
+
Or:
|
|
391
497
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
c = g.commit_tree(t, :message => 'message', :parents => [sha1, sha2])
|
|
498
|
+
```sh
|
|
499
|
+
gem install git
|
|
500
|
+
```
|
|
396
501
|
|
|
397
|
-
|
|
398
|
-
|
|
502
|
+
Most v4.x code requires no changes. Compatibility shims keep the old API working
|
|
503
|
+
while emitting deprecation warnings that tell you what to migrate before v6.0.0.
|
|
399
504
|
|
|
400
|
-
|
|
401
|
-
g.checkout
|
|
402
|
-
g.checkout(another_index)
|
|
403
|
-
g.commit # commits to temp_index
|
|
404
|
-
end
|
|
405
|
-
end
|
|
505
|
+
### 2026-01-07: AI policy introduced
|
|
406
506
|
|
|
407
|
-
|
|
507
|
+
We have adopted a formal [AI Policy](AI_POLICY.md) to clarify expectations for
|
|
508
|
+
AI-assisted contributions. Please review it before opening a PR to ensure your
|
|
509
|
+
changes are fully understood, meet our quality bar, and respect licensing
|
|
510
|
+
requirements.
|
|
408
511
|
|
|
512
|
+
We chose a principles-based policy to respect contributors' time and expertise. It
|
|
513
|
+
is quick to read and easy to remember, and it still sets clear expectations.
|
|
409
514
|
|
|
410
|
-
|
|
411
|
-
# calls set_index, then switches back after
|
|
412
|
-
end
|
|
515
|
+
### 2025-07-09: Architectural redesign
|
|
413
516
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
517
|
+
On this date we announced an architectural redesign of the git gem. The architecture
|
|
518
|
+
at the time was difficult to maintain and evolve; the redesign replaced it with a
|
|
519
|
+
clearer, more testable three-layer structure of commands, parsers, and a
|
|
520
|
+
`Git::Repository` facade.
|
|
417
521
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
522
|
+
**The redesign shipped in v5.0.0 and is complete.** `Git::Base` and `Git::Lib` are
|
|
523
|
+
gone, along with the `g.lib` accessor. See [UPGRADING.md](UPGRADING.md) for what
|
|
524
|
+
changed and how to migrate.
|
|
525
|
+
|
|
526
|
+
The three documents written to plan it are kept as a historical record in
|
|
527
|
+
[`archive/v5-redesign/`](archive/v5-redesign/). They describe the state of the code
|
|
528
|
+
before and during the migration and are not current policy. The standards that apply
|
|
529
|
+
to new code live in [`.github/skills/`](.github/skills/).
|
|
530
|
+
|
|
531
|
+
1. [Analysis of the Current Architecture](archive/v5-redesign/1_architecture_existing.md):
|
|
532
|
+
a breakdown of the v4.x design and its challenges.
|
|
533
|
+
2. [The Proposed Redesign](archive/v5-redesign/2_architecture_redesign.md): an overview
|
|
534
|
+
of the three-layer architecture.
|
|
535
|
+
3. [Implementation Plan](archive/v5-redesign/3_architecture_implementation.md): the
|
|
536
|
+
step-by-step plan that was followed.
|
|
537
|
+
|
|
538
|
+
### 2025-07-07: We now use RuboCop
|
|
539
|
+
|
|
540
|
+
To improve code consistency and maintainability, the `ruby-git` project has adopted
|
|
541
|
+
[RuboCop](https://rubocop.org/) as our static code analyzer and formatter. All new
|
|
542
|
+
contributions must follow the style guidelines enforced by our RuboCop
|
|
543
|
+
configuration.
|
|
544
|
+
|
|
545
|
+
Run RuboCop from the project's Rakefile:
|
|
546
|
+
|
|
547
|
+
```shell
|
|
548
|
+
rake rubocop
|
|
423
549
|
```
|
|
424
550
|
|
|
425
|
-
|
|
551
|
+
RuboCop also runs as part of the default rake task, which our continuous integration
|
|
552
|
+
workflow runs.
|
|
553
|
+
|
|
554
|
+
PRs with RuboCop offenses will not be merged. In rare cases, it might be acceptable
|
|
555
|
+
to disable a RuboCop check for the most limited scope possible.
|
|
556
|
+
|
|
557
|
+
If you have a problem fixing a RuboCop offense, don't be afraid to ask a
|
|
558
|
+
contributor.
|
|
559
|
+
|
|
560
|
+
### 2025-06-06: Default branch rename
|
|
561
|
+
|
|
562
|
+
On June 6, 2025, we renamed the default branch from `master` to `main`.
|
|
563
|
+
|
|
564
|
+
Instructions for renaming your local or forked branch to match are in the gist
|
|
565
|
+
[Default Branch Name
|
|
566
|
+
Change](https://gist.github.com/jcouball/580a10e395f7fdfaaa4297bbe816cc7d).
|
|
567
|
+
|
|
568
|
+
### 2025-05-15: We've switched to Conventional Commits
|
|
569
|
+
|
|
570
|
+
The `ruby-git` project has adopted the [Conventional Commits
|
|
571
|
+
standard](https://www.conventionalcommits.org/en/v1.0.0/) for all commit messages.
|
|
572
|
+
This enables automated changelog generation and is a step toward continuous
|
|
573
|
+
delivery.
|
|
574
|
+
|
|
575
|
+
All commits to this repository must follow the Conventional Commits standard.
|
|
576
|
+
Commits that do not follow it will fail the CI build, and PRs that include them will
|
|
577
|
+
not be merged.
|
|
578
|
+
|
|
579
|
+
To validate your commit messages locally before pushing them to GitHub, install the
|
|
580
|
+
git `commit-msg` hook by running `bin/setup` in the project root.
|
|
426
581
|
|
|
427
|
-
|
|
582
|
+
Read more about this change in the [Commit Message Guidelines section of
|
|
583
|
+
CONTRIBUTING.md](CONTRIBUTING.md#commit-message-guidelines).
|