README.md in git-2.0.0.pre1 vs README.md in git-2.0.0.pre2

- old
+ new

@@ -9,10 +9,22 @@ [![Documentation](https://img.shields.io/badge/Documentation-Latest-green)](https://rubydoc.info/gems/git/) [![Change Log](https://img.shields.io/badge/CHANGELOG-Latest-green)](https://rubydoc.info/gems/git/file/CHANGELOG.md) [![Build Status](https://github.com/ruby-git/ruby-git/workflows/CI/badge.svg?branch=master)](https://github.com/ruby-git/ruby-git/actions?query=workflow%3ACI) [![Code Climate](https://codeclimate.com/github/ruby-git/ruby-git.png)](https://codeclimate.com/github/ruby-git/ruby-git) +* [Summary](#summary) +* [v2.0.0 pre-release](#v200-pre-release) +* [Install](#install) +* [Major Objects](#major-objects) +* [Errors Raised By This Gem](#errors-raised-by-this-gem) +* [Specifying And Handling Timeouts](#specifying-and-handling-timeouts) +* [Examples](#examples) +* [Ruby version support policy](#ruby-version-support-policy) +* [License](#license) + +## Summary + The [git gem](https://rubygems.org/gems/git) provides an API that can be used to create, read, and manipulate Git repositories by wrapping system calls to the `git` command line. The API can be used for working with Git in complex interactions including branching and merging, object inspection and manipulation, history, patch generation and more. @@ -88,15 +100,123 @@ `@git.log.all.each { |commit| [block] }` **Git::Worktrees** - Enumerable object that holds `Git::Worktree objects`. +## Errors Raised By This Gem + +This gem raises custom errors that derive from `Git::Error`. These errors are +arranged in the following class heirarchy: + +Error heirarchy: + +```text +Error +└── CommandLineError + ├── FailedError + └── SignaledError + └── TimeoutError +``` + +Other standard errors may also be raised like `ArgumentError`. Each method should +document the errors it may raise. + +Description of each Error class: + +* `Error`: This catch-all error serves as the base class for other custom errors in this + gem. Errors of this class are raised when no more approriate specific error to + raise. +* `CommandLineError`: This error is raised when there's a problem executing the git + command line. This gem will raise a more specific error depending on how the + command line failed. +* `FailedError`: This error is raised when the git command line exits with a non-zero + status code that is not expected by the git gem. +* `SignaledError`: This error is raised when the git command line is terminated as a + result of receiving a signal. This could happen if the process is forcibly + terminated or if there is a serious system error. +* `TimeoutError`: This is a specific type of `SignaledError` that is raised when the + git command line operation times out and is killed via the SIGKILL signal. This + happens if the operation takes longer than the timeout duration configured in + `Git.config.timeout` or via the `:timeout` parameter given in git methods that + support this parameter. + +`Git::GitExecuteError` remains as an alias for `Git::Error`. It is considered +deprecated as of git-2.0.0. + +Here is an example of catching errors when using the git gem: + +```ruby +begin + timeout_duration = 0.001 # seconds + repo = Git.clone('https://github.com/ruby-git/ruby-git', 'ruby-git-temp', timeout: timeout_duration) +rescue Git::TimeoutError => e # Catch the more specific error first! + puts "Git clone took too long and timed out #{e}" +rescue Git::Error => e + puts "Received the following error: #{e}" +``` + +## Specifying And Handling Timeouts + +The timeout feature was added in git gem version `2.0.0`. + +A timeout for git operations can be set either globally or for specific method calls +that accept a `:timeout` parameter. + +The timeout value must be a real, non-negative `Numeric` value that specifies a +number of seconds a `git` command will be given to complete before being sent a KILL +signal. This library may hang if the `git` command does not terminate after receiving +the KILL signal. + +When a command times out, a `Git::TimeoutError` is raised. + +If the timeout value is `0` or `nil`, no timeout will be enforced. + +If a method accepts a `:timeout` parameter and a receives a non-nil value, it will +override the global timeout value. In this context, a value of `nil` (which is +usually the default) will use the global timeout value and a value of `0` will turn +off timeout enforcement for that method call no matter what the global value is. + +To set a global timeout, use the `Git.config` object: + +```ruby +Git.config.timeout = nil # a value of nil or 0 means no timeout is enforced +Git.config.timeout = 1.5 # can be any real, non-negative Numeric interpreted as number of seconds +``` + +The global timeout can be overridden for a specific method if the method accepts a +`:timeout` parameter: + +```ruby +repo_url = 'https://github.com/ruby-git/ruby-git.git' +Git.clone(repo_url) # Use the global timeout value +Git.clone(repo_url, timeout: nil) # Also uses the global timeout value +Git.clone(repo_url, timeout: 0) # Do not enforce a timeout +Git.clone(repo_url, timeout: 10.5) # Timeout after 10.5 seconds raising Git::SignaledError +``` + +If the command takes too long, a `Git::SignaledError` will be raised: + +```ruby +begin + Git.clone(repo_url, timeout: 10) +rescue Git::TimeoutError => e + result = e.result + result.class #=> Git::CommandLineResult + result.status #=> #<Process::Status: pid 62173 SIGKILL (signal 9)> + result.status.timeout? #=> true + result.git_cmd # The git command ran as an array of strings + result.stdout # The command's output to stdout until it was terminated + result.stderr # The command's output to stderr until it was terminated +end +``` + ## Examples Here are a bunch of examples of how to use the Ruby/Git package. Require the 'git' gem. + ```ruby require 'git' ``` Git env config @@ -259,14 +379,14 @@ g.add # git add -- "." g.add(:all=>true) # git add --all -- "." g.add('file_path') # git add -- "file_path" g.add(['file_path_1', 'file_path_2']) # git add -- "file_path_1" "file_path_2" -g.remove() # git rm -f -- "." -g.remove('file.txt') # git rm -f -- "file.txt" -g.remove(['file.txt', 'file2.txt']) # git rm -f -- "file.txt" "file2.txt" -g.remove('file.txt', :recursive => true) # git rm -f -r -- "file.txt" -g.remove('file.txt', :cached => true) # git rm -f --cached -- "file.txt" +g.remove() # git rm -f -- "." +g.remove('file.txt') # git rm -f -- "file.txt" +g.remove(['file.txt', 'file2.txt']) # git rm -f -- "file.txt" "file2.txt" +g.remove('file.txt', :recursive => true) # git rm -f -r -- "file.txt" +g.remove('file.txt', :cached => true) # git rm -f --cached -- "file.txt" g.commit('message') g.commit_all('message') # Sign a commit using the gpg key configured in the user.signingkey config setting