git 4.3.2 → 5.0.0.beta.1

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 (280) hide show
  1. checksums.yaml +4 -4
  2. data/.github/copilot-instructions.md +67 -2705
  3. data/.github/pull_request_template.md +3 -1
  4. data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
  5. data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
  6. data/.github/skills/command-implementation/REFERENCE.md +993 -0
  7. data/.github/skills/command-implementation/SKILL.md +229 -0
  8. data/.github/skills/command-test-conventions/SKILL.md +660 -0
  9. data/.github/skills/command-yard-documentation/SKILL.md +426 -0
  10. data/.github/skills/dependency-management/SKILL.md +72 -0
  11. data/.github/skills/development-workflow/SKILL.md +506 -0
  12. data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
  13. data/.github/skills/extract-facade-from-base-lib/SKILL.md +586 -0
  14. data/.github/skills/facade-implementation/REFERENCE.md +840 -0
  15. data/.github/skills/facade-implementation/SKILL.md +260 -0
  16. data/.github/skills/facade-test-conventions/SKILL.md +380 -0
  17. data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
  18. data/.github/skills/make-skill-template/SKILL.md +176 -0
  19. data/.github/skills/pr-readiness-review/SKILL.md +185 -0
  20. data/.github/skills/project-context/SKILL.md +313 -0
  21. data/.github/skills/pull-request-review/SKILL.md +168 -0
  22. data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
  23. data/.github/skills/release-management/SKILL.md +125 -0
  24. data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
  25. data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
  26. data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
  27. data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
  28. data/.github/skills/reviewing-skills/SKILL.md +189 -0
  29. data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
  30. data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
  31. data/.github/skills/test-debugging/SKILL.md +160 -0
  32. data/.github/skills/yard-documentation/SKILL.md +793 -0
  33. data/.github/workflows/continuous_integration.yml +3 -2
  34. data/.github/workflows/enforce_conventional_commits.yml +1 -1
  35. data/.github/workflows/experimental_continuous_integration.yml +2 -2
  36. data/.github/workflows/release.yml +3 -4
  37. data/.gitignore +8 -0
  38. data/.husky/pre-commit +13 -0
  39. data/.release-please-manifest.json +1 -1
  40. data/.rspec +3 -0
  41. data/.rubocop.yml +7 -3
  42. data/.rubocop_todo.yml +23 -5
  43. data/.yardopts +1 -0
  44. data/CHANGELOG.md +0 -40
  45. data/CONTRIBUTING.md +694 -53
  46. data/README.md +17 -5
  47. data/Rakefile +61 -9
  48. data/commitlint.test +4 -0
  49. data/git.gemspec +14 -8
  50. data/lib/git/args_builder.rb +0 -8
  51. data/lib/git/base.rb +486 -410
  52. data/lib/git/branch.rb +380 -43
  53. data/lib/git/branch_delete_failure.rb +31 -0
  54. data/lib/git/branch_delete_result.rb +63 -0
  55. data/lib/git/branch_info.rb +178 -0
  56. data/lib/git/branches.rb +130 -24
  57. data/lib/git/command_line/base.rb +245 -0
  58. data/lib/git/command_line/capturing.rb +249 -0
  59. data/lib/git/command_line/result.rb +96 -0
  60. data/lib/git/command_line/streaming.rb +194 -0
  61. data/lib/git/command_line.rb +43 -322
  62. data/lib/git/command_line_result.rb +4 -88
  63. data/lib/git/commands/add.rb +131 -0
  64. data/lib/git/commands/am/abort.rb +43 -0
  65. data/lib/git/commands/am/apply.rb +252 -0
  66. data/lib/git/commands/am/continue.rb +43 -0
  67. data/lib/git/commands/am/quit.rb +43 -0
  68. data/lib/git/commands/am/retry.rb +47 -0
  69. data/lib/git/commands/am/show_current_patch.rb +64 -0
  70. data/lib/git/commands/am/skip.rb +42 -0
  71. data/lib/git/commands/am.rb +33 -0
  72. data/lib/git/commands/apply.rb +237 -0
  73. data/lib/git/commands/archive/list_formats.rb +46 -0
  74. data/lib/git/commands/archive.rb +140 -0
  75. data/lib/git/commands/arguments.rb +3510 -0
  76. data/lib/git/commands/base.rb +403 -0
  77. data/lib/git/commands/branch/copy.rb +94 -0
  78. data/lib/git/commands/branch/create.rb +173 -0
  79. data/lib/git/commands/branch/delete.rb +80 -0
  80. data/lib/git/commands/branch/list.rb +162 -0
  81. data/lib/git/commands/branch/move.rb +94 -0
  82. data/lib/git/commands/branch/set_upstream.rb +86 -0
  83. data/lib/git/commands/branch/show_current.rb +49 -0
  84. data/lib/git/commands/branch/unset_upstream.rb +57 -0
  85. data/lib/git/commands/branch.rb +34 -0
  86. data/lib/git/commands/cat_file/batch.rb +364 -0
  87. data/lib/git/commands/cat_file/filtered.rb +105 -0
  88. data/lib/git/commands/cat_file/raw.rb +210 -0
  89. data/lib/git/commands/cat_file.rb +49 -0
  90. data/lib/git/commands/checkout/branch.rb +151 -0
  91. data/lib/git/commands/checkout/files.rb +115 -0
  92. data/lib/git/commands/checkout.rb +38 -0
  93. data/lib/git/commands/checkout_index.rb +105 -0
  94. data/lib/git/commands/clean.rb +100 -0
  95. data/lib/git/commands/clone.rb +240 -0
  96. data/lib/git/commands/commit.rb +272 -0
  97. data/lib/git/commands/commit_tree.rb +100 -0
  98. data/lib/git/commands/config_option_syntax/add.rb +83 -0
  99. data/lib/git/commands/config_option_syntax/get.rb +117 -0
  100. data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
  101. data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
  102. data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
  103. data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
  104. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +102 -0
  105. data/lib/git/commands/config_option_syntax/list.rb +107 -0
  106. data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
  107. data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
  108. data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
  109. data/lib/git/commands/config_option_syntax/set.rb +114 -0
  110. data/lib/git/commands/config_option_syntax/unset.rb +89 -0
  111. data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
  112. data/lib/git/commands/config_option_syntax.rb +56 -0
  113. data/lib/git/commands/describe.rb +155 -0
  114. data/lib/git/commands/diff.rb +656 -0
  115. data/lib/git/commands/diff_files.rb +518 -0
  116. data/lib/git/commands/diff_index.rb +496 -0
  117. data/lib/git/commands/fetch.rb +352 -0
  118. data/lib/git/commands/fsck.rb +136 -0
  119. data/lib/git/commands/gc.rb +132 -0
  120. data/lib/git/commands/grep.rb +338 -0
  121. data/lib/git/commands/init.rb +99 -0
  122. data/lib/git/commands/log.rb +632 -0
  123. data/lib/git/commands/ls_files.rb +191 -0
  124. data/lib/git/commands/ls_remote.rb +155 -0
  125. data/lib/git/commands/ls_tree.rb +131 -0
  126. data/lib/git/commands/maintenance/register.rb +75 -0
  127. data/lib/git/commands/maintenance/run.rb +104 -0
  128. data/lib/git/commands/maintenance/start.rb +66 -0
  129. data/lib/git/commands/maintenance/stop.rb +55 -0
  130. data/lib/git/commands/maintenance/unregister.rb +79 -0
  131. data/lib/git/commands/maintenance.rb +31 -0
  132. data/lib/git/commands/merge/abort.rb +44 -0
  133. data/lib/git/commands/merge/continue.rb +44 -0
  134. data/lib/git/commands/merge/quit.rb +46 -0
  135. data/lib/git/commands/merge/start.rb +245 -0
  136. data/lib/git/commands/merge.rb +28 -0
  137. data/lib/git/commands/merge_base.rb +86 -0
  138. data/lib/git/commands/mv.rb +77 -0
  139. data/lib/git/commands/name_rev.rb +114 -0
  140. data/lib/git/commands/pull.rb +377 -0
  141. data/lib/git/commands/push.rb +246 -0
  142. data/lib/git/commands/read_tree.rb +149 -0
  143. data/lib/git/commands/remote/add.rb +91 -0
  144. data/lib/git/commands/remote/get_url.rb +66 -0
  145. data/lib/git/commands/remote/list.rb +54 -0
  146. data/lib/git/commands/remote/prune.rb +61 -0
  147. data/lib/git/commands/remote/remove.rb +52 -0
  148. data/lib/git/commands/remote/rename.rb +69 -0
  149. data/lib/git/commands/remote/set_branches.rb +63 -0
  150. data/lib/git/commands/remote/set_head.rb +82 -0
  151. data/lib/git/commands/remote/set_url.rb +71 -0
  152. data/lib/git/commands/remote/set_url_add.rb +61 -0
  153. data/lib/git/commands/remote/set_url_delete.rb +64 -0
  154. data/lib/git/commands/remote/show.rb +71 -0
  155. data/lib/git/commands/remote/update.rb +72 -0
  156. data/lib/git/commands/remote.rb +42 -0
  157. data/lib/git/commands/repack.rb +277 -0
  158. data/lib/git/commands/reset.rb +147 -0
  159. data/lib/git/commands/rev_parse.rb +297 -0
  160. data/lib/git/commands/revert/abort.rb +45 -0
  161. data/lib/git/commands/revert/continue.rb +57 -0
  162. data/lib/git/commands/revert/quit.rb +47 -0
  163. data/lib/git/commands/revert/skip.rb +44 -0
  164. data/lib/git/commands/revert/start.rb +153 -0
  165. data/lib/git/commands/revert.rb +29 -0
  166. data/lib/git/commands/rm.rb +114 -0
  167. data/lib/git/commands/show.rb +632 -0
  168. data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
  169. data/lib/git/commands/show_ref/exists.rb +78 -0
  170. data/lib/git/commands/show_ref/list.rb +145 -0
  171. data/lib/git/commands/show_ref/verify.rb +120 -0
  172. data/lib/git/commands/show_ref.rb +42 -0
  173. data/lib/git/commands/stash/apply.rb +75 -0
  174. data/lib/git/commands/stash/branch.rb +65 -0
  175. data/lib/git/commands/stash/clear.rb +41 -0
  176. data/lib/git/commands/stash/create.rb +58 -0
  177. data/lib/git/commands/stash/drop.rb +67 -0
  178. data/lib/git/commands/stash/list.rb +39 -0
  179. data/lib/git/commands/stash/pop.rb +78 -0
  180. data/lib/git/commands/stash/push.rb +103 -0
  181. data/lib/git/commands/stash/show.rb +149 -0
  182. data/lib/git/commands/stash/store.rb +63 -0
  183. data/lib/git/commands/stash.rb +38 -0
  184. data/lib/git/commands/status.rb +169 -0
  185. data/lib/git/commands/symbolic_ref/delete.rb +68 -0
  186. data/lib/git/commands/symbolic_ref/read.rb +95 -0
  187. data/lib/git/commands/symbolic_ref/update.rb +76 -0
  188. data/lib/git/commands/symbolic_ref.rb +38 -0
  189. data/lib/git/commands/tag/create.rb +139 -0
  190. data/lib/git/commands/tag/delete.rb +55 -0
  191. data/lib/git/commands/tag/list.rb +143 -0
  192. data/lib/git/commands/tag/verify.rb +71 -0
  193. data/lib/git/commands/tag.rb +26 -0
  194. data/lib/git/commands/update_ref/batch.rb +140 -0
  195. data/lib/git/commands/update_ref/delete.rb +92 -0
  196. data/lib/git/commands/update_ref/update.rb +106 -0
  197. data/lib/git/commands/update_ref.rb +42 -0
  198. data/lib/git/commands/version.rb +52 -0
  199. data/lib/git/commands/worktree/add.rb +140 -0
  200. data/lib/git/commands/worktree/list.rb +64 -0
  201. data/lib/git/commands/worktree/lock.rb +58 -0
  202. data/lib/git/commands/worktree/management_base.rb +51 -0
  203. data/lib/git/commands/worktree/move.rb +66 -0
  204. data/lib/git/commands/worktree/prune.rb +67 -0
  205. data/lib/git/commands/worktree/remove.rb +63 -0
  206. data/lib/git/commands/worktree/repair.rb +76 -0
  207. data/lib/git/commands/worktree/unlock.rb +47 -0
  208. data/lib/git/commands/worktree.rb +43 -0
  209. data/lib/git/commands/write_tree.rb +68 -0
  210. data/lib/git/commands.rb +89 -0
  211. data/lib/git/detached_head_info.rb +54 -0
  212. data/lib/git/diff.rb +297 -7
  213. data/lib/git/diff_file_numstat_info.rb +29 -0
  214. data/lib/git/diff_file_patch_info.rb +134 -0
  215. data/lib/git/diff_file_raw_info.rb +127 -0
  216. data/lib/git/diff_info.rb +169 -0
  217. data/lib/git/diff_path_status.rb +78 -19
  218. data/lib/git/diff_result.rb +32 -0
  219. data/lib/git/diff_stats.rb +59 -14
  220. data/lib/git/dirstat_info.rb +86 -0
  221. data/lib/git/errors.rb +65 -2
  222. data/lib/git/execution_context/global.rb +56 -0
  223. data/lib/git/execution_context/repository.rb +147 -0
  224. data/lib/git/execution_context.rb +482 -0
  225. data/lib/git/file_ref.rb +74 -0
  226. data/lib/git/fsck_object.rb +9 -9
  227. data/lib/git/fsck_result.rb +1 -1
  228. data/lib/git/lib.rb +1606 -1028
  229. data/lib/git/log.rb +15 -2
  230. data/lib/git/object.rb +92 -22
  231. data/lib/git/parsers/branch.rb +224 -0
  232. data/lib/git/parsers/cat_file.rb +111 -0
  233. data/lib/git/parsers/diff.rb +585 -0
  234. data/lib/git/parsers/fsck.rb +133 -0
  235. data/lib/git/parsers/grep.rb +42 -0
  236. data/lib/git/parsers/ls_tree.rb +58 -0
  237. data/lib/git/parsers/stash.rb +208 -0
  238. data/lib/git/parsers/tag.rb +257 -0
  239. data/lib/git/remote.rb +133 -9
  240. data/lib/git/repository/branching.rb +572 -0
  241. data/lib/git/repository/committing.rb +191 -0
  242. data/lib/git/repository/configuring.rb +156 -0
  243. data/lib/git/repository/diffing.rb +775 -0
  244. data/lib/git/repository/inspecting.rb +153 -0
  245. data/lib/git/repository/logging.rb +247 -0
  246. data/lib/git/repository/merging.rb +295 -0
  247. data/lib/git/repository/object_operations.rb +1101 -0
  248. data/lib/git/repository/path_resolver.rb +207 -0
  249. data/lib/git/repository/remote_operations.rb +753 -0
  250. data/lib/git/repository/shared_private.rb +51 -0
  251. data/lib/git/repository/staging.rb +390 -0
  252. data/lib/git/repository/stashing.rb +107 -0
  253. data/lib/git/repository/status_operations.rb +180 -0
  254. data/lib/git/repository/worktree_operations.rb +159 -0
  255. data/lib/git/repository.rb +264 -1
  256. data/lib/git/stash.rb +85 -4
  257. data/lib/git/stash_info.rb +104 -0
  258. data/lib/git/stashes.rb +130 -13
  259. data/lib/git/status.rb +224 -18
  260. data/lib/git/tag_delete_failure.rb +31 -0
  261. data/lib/git/tag_delete_result.rb +63 -0
  262. data/lib/git/tag_info.rb +105 -0
  263. data/lib/git/version.rb +109 -2
  264. data/lib/git/version_constraint.rb +81 -0
  265. data/lib/git/worktree.rb +120 -5
  266. data/lib/git/worktrees.rb +107 -7
  267. data/lib/git.rb +114 -18
  268. data/redesign/1_architecture_existing.md +54 -18
  269. data/redesign/2_architecture_redesign.md +365 -46
  270. data/redesign/3_architecture_implementation.md +1451 -54
  271. data/tasks/gem_tasks.rake +4 -0
  272. data/tasks/npm_tasks.rake +7 -0
  273. data/tasks/rspec.rake +48 -0
  274. data/tasks/test.rake +13 -1
  275. data/tasks/yard.rake +34 -7
  276. metadata +349 -20
  277. data/lib/git/index.rb +0 -6
  278. data/lib/git/path.rb +0 -38
  279. data/lib/git/working_directory.rb +0 -6
  280. /data/{release-please-config.json → .release-please-config.json} +0 -0
@@ -1,330 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'git/base'
4
- require 'git/command_line_result'
5
- require 'git/errors'
6
- require 'stringio'
7
-
8
3
  module Git
9
- # Runs a git command and returns the result
4
+ # Namespace module for git command-line execution strategies
5
+ #
6
+ # This module groups the classes responsible for invoking git subprocesses
7
+ # and handling their output. Choose a concrete class based on your buffering
8
+ # needs:
9
+ #
10
+ # * {Git::CommandLine::Capturing} — buffers stdout and stderr in memory.
11
+ # Use this for the vast majority of git commands whose output fits in memory.
12
+ #
13
+ # * {Git::CommandLine::Streaming} — streams stdout to a caller-supplied IO.
14
+ # Use this for commands (e.g. `cat-file -p <blob>`) whose output may be
15
+ # too large to buffer.
16
+ #
17
+ # Both classes inherit from {Git::CommandLine::Base} and are instantiated
18
+ # via factory helpers in {Git::Lib}: {Git::Lib#command_capturing} and
19
+ # {Git::Lib#command_streaming}.
20
+ #
21
+ # Results are returned as {Git::CommandLine::Result} objects (also accessible
22
+ # as {Git::CommandLineResult} for backward compatibility).
10
23
  #
11
24
  # @api public
12
25
  #
13
- class CommandLine
14
- # Create a Git::CommandLine object
15
- #
16
- # @example
17
- # env = { 'GIT_DIR' => '/path/to/git/dir' }
18
- # binary_path = '/usr/bin/git'
19
- # global_opts = %w[--git-dir /path/to/git/dir]
20
- # logger = Logger.new(STDOUT)
21
- # cli = CommandLine.new(env, binary_path, global_opts, logger)
22
- # cli.run('version') #=> #<Git::CommandLineResult:0x00007f9b0c0b0e00
23
- #
24
- # @param env [Hash<String, String>] environment variables to set
25
- # @param global_opts [Array<String>] global options to pass to git
26
- # @param logger [Logger] the logger to use
27
- #
28
- def initialize(env, binary_path, global_opts, logger)
29
- @env = env
30
- @binary_path = binary_path
31
- @global_opts = global_opts
32
- @logger = logger
33
- end
34
-
35
- # @attribute [r] env
36
- #
37
- # Variables to set (or unset) in the git command's environment
38
- #
39
- # @example
40
- # env = { 'GIT_DIR' => '/path/to/git/dir' }
41
- # command_line = Git::CommandLine.new(env, '/usr/bin/git', [], Logger.new(STDOUT))
42
- # command_line.env #=> { 'GIT_DIR' => '/path/to/git/dir' }
43
- #
44
- # @return [Hash<String, String>]
45
- #
46
- # @see https://ruby-doc.org/3.2.1/Process.html#method-c-spawn Process.spawn
47
- # for details on how to set environment variables using the `env` parameter
48
- #
49
- attr_reader :env
50
-
51
- # @attribute [r] binary_path
52
- #
53
- # The path to the command line binary to run
54
- #
55
- # @example
56
- # binary_path = '/usr/bin/git'
57
- # command_line = Git::CommandLine.new({}, binary_path, ['version'], Logger.new(STDOUT))
58
- # command_line.binary_path #=> '/usr/bin/git'
59
- #
60
- # @return [String]
61
- #
62
- attr_reader :binary_path
63
-
64
- # @attribute [r] global_opts
65
- #
66
- # The global options to pass to git
67
- #
68
- # These are options that are passed to git before the command name and
69
- # arguments. For example, in `git --git-dir /path/to/git/dir version`, the
70
- # global options are %w[--git-dir /path/to/git/dir].
71
- #
72
- # @example
73
- # env = {}
74
- # global_opts = %w[--git-dir /path/to/git/dir]
75
- # logger = Logger.new(nil)
76
- # cli = CommandLine.new(env, '/usr/bin/git', global_opts, logger)
77
- # cli.global_opts #=> %w[--git-dir /path/to/git/dir]
78
- #
79
- # @return [Array<String>]
80
- #
81
- attr_reader :global_opts
82
-
83
- # @attribute [r] logger
84
- #
85
- # The logger to use for logging git commands and results
86
- #
87
- # @example
88
- # env = {}
89
- # global_opts = %w[]
90
- # logger = Logger.new(STDOUT)
91
- # cli = CommandLine.new(env, '/usr/bin/git', global_opts, logger)
92
- # cli.logger == logger #=> true
93
- #
94
- # @return [Logger]
95
- #
96
- attr_reader :logger
97
-
98
- # Execute a git command, wait for it to finish, and return the result
99
- #
100
- # Non-option the command line arguements to pass to git. If you collect
101
- # the command line arguments in an array, make sure you splat the array
102
- # into the parameter list.
103
- #
104
- # NORMALIZATION
105
- #
106
- # The command output is returned as a Unicde string containing the binary output
107
- # from the command. If the binary output is not valid UTF-8, the output will
108
- # cause problems because the encoding will be invalid.
109
- #
110
- # Normalization is a process that trys to convert the binary output to a valid
111
- # UTF-8 string. It uses the `rchardet` gem to detect the encoding of the binary
112
- # output and then converts it to UTF-8.
113
- #
114
- # Normalization is not enabled by default. Pass `normalize: true` to Git::CommandLine#run
115
- # to enable it. Normalization will only be performed on stdout and only if the `out:`` option
116
- # is nil or is a StringIO object. If the out: option is set to a file or other IO object,
117
- # the normalize option will be ignored.
118
- #
119
- # @example Run a command and return the output
120
- # cli.run('version') #=> "git version 2.39.1\n"
121
- #
122
- # @example The args array should be splatted into the parameter list
123
- # args = %w[log -n 1 --oneline]
124
- # cli.run(*args) #=> "f5baa11 beginning of Ruby/Git project\n"
125
- #
126
- # @example Run a command and return the chomped output
127
- # cli.run('version', chomp: true) #=> "git version 2.39.1"
128
- #
129
- # @example Run a command and without normalizing the output
130
- # cli.run('version', normalize: false) #=> "git version 2.39.1\n"
131
- #
132
- # @example Capture stdout in a temporary file
133
- # require 'tempfile'
134
- # tempfile = Tempfile.create('git') do |file|
135
- # cli.run('version', out: file)
136
- # file.rewind
137
- # file.read #=> "git version 2.39.1\n"
138
- # end
139
- #
140
- # @example Capture stderr in a StringIO object
141
- # require 'stringio'
142
- # stderr = StringIO.new
143
- # begin
144
- # cli.run('log', 'nonexistent-branch', err: stderr)
145
- # rescue Git::FailedError => e
146
- # stderr.string #=> "unknown revision or path not in the working tree.\n"
147
- # end
148
- #
149
- # @param options_hash [Hash] the options to pass to the command
150
- #
151
- # @option options_hash [#write, nil] :out the object to write stdout to or nil to ignore stdout
152
- #
153
- # If this is a 'StringIO' object, then `stdout_writer.string` will be returned.
154
- #
155
- # In general, only specify a `stdout_writer` object when you want to redirect
156
- # stdout to a file or some other object that responds to `#write`. The default
157
- # behavior will return the output of the command.
158
- #
159
- # @option options_hash [#write, nil] :err the object to write stderr to or nil to ignore stderr
160
- #
161
- # If this is a 'StringIO' object and `merged_output` is `true`, then
162
- # `stderr_writer.string` will be merged into the output returned by this method.
163
- #
164
- # @option options_hash [Boolean] :normalize whether to normalize the output of stdout and stderr
165
- #
166
- # @option options_hash [Boolean] :chomp whether to chomp both stdout and stderr output
167
- #
168
- # @option options_hash [Boolean] :merge whether to merge stdout and stderr in the string returned
169
- #
170
- # @option options_hash [String, nil] :chdir the directory to run the command in
171
- #
172
- # @option options_hash [Numeric, nil] :timeout the maximum seconds to wait for the command to complete
173
- #
174
- # If timeout is zero, the timeout will not be enforced.
175
- #
176
- # If the command times out, it is killed via a `SIGKILL` signal and `Git::TimeoutError` is raised.
177
- #
178
- # If the command does not respond to SIGKILL, it will hang this method.
179
- #
180
- # @return [Git::CommandLineResult] the output of the command
181
- #
182
- # This result of running the command.
183
- #
184
- # @raise [ArgumentError] if `args` is not an array of strings
185
- #
186
- # @raise [Git::SignaledError] if the command was terminated because of an uncaught signal
187
- #
188
- # @raise [Git::FailedError] if the command returned a non-zero exitstatus
189
- #
190
- # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
191
- #
192
- # @raise [Git::TimeoutError] if the command times out
193
- #
194
- def run(*, **options_hash)
195
- options_hash = RUN_ARGS.merge(options_hash)
196
- extra_options = options_hash.keys - RUN_ARGS.keys
197
- raise ArgumentError, "Unknown options: #{extra_options.join(', ')}" if extra_options.any?
198
-
199
- result = run_with_capture(*, **options_hash)
200
- process_result(result, options_hash[:normalize], options_hash[:chomp], options_hash[:timeout])
201
- end
202
-
203
- # @return [Git::CommandLineResult] the result of running the command
204
- #
205
- # @api private
206
- #
207
- def run_with_capture(*args, **options_hash)
208
- git_cmd = build_git_cmd(args)
209
- options = run_with_capture_options(**options_hash)
210
- ProcessExecuter.run_with_capture(env, *git_cmd, **options)
211
- rescue ProcessExecuter::ProcessIOError => e
212
- raise Git::ProcessIOError.new(e.message), cause: e.exception.cause
213
- end
214
-
215
- def run_with_capture_options(**options_hash)
216
- chdir = options_hash[:chdir] || :not_set
217
- timeout_after = options_hash[:timeout]
218
- out = options_hash[:out]
219
- err = options_hash[:err]
220
- merge_output = options_hash[:merge] || false
221
-
222
- { chdir:, timeout_after:, merge_output:, raise_errors: false }.tap do |options|
223
- options[:out] = out unless out.nil?
224
- options[:err] = err unless err.nil?
225
- end
226
- end
227
-
228
- RUN_ARGS = {
229
- normalize: false,
230
- chomp: false,
231
- merge: false,
232
- out: nil,
233
- err: nil,
234
- chdir: nil,
235
- timeout: nil
236
- }.freeze
237
-
238
- private
239
-
240
- # Build the git command line from the available sources to send to `Process.spawn`
241
- # @return [Array<String>]
242
- # @api private
243
- #
244
- def build_git_cmd(args)
245
- raise ArgumentError, 'The args array can not contain an array' if args.any?(Array)
246
-
247
- [binary_path, *global_opts, *args].map(&:to_s)
248
- end
249
-
250
- # Process the result of the command and return a Git::CommandLineResult
251
- #
252
- # Post process output, log the command and result, and raise an error if the
253
- # command failed.
254
- #
255
- # @param result [ProcessExecuter::Command::Result] the result it is a
256
- # Process::Status and include command, stdout, and stderr
257
- #
258
- # @param normalize [Boolean] whether to normalize the output of each writer
259
- #
260
- # @param chomp [Boolean] whether to chomp the output of each writer
261
- #
262
- # @param timeout [Numeric, nil] the maximum seconds to wait for the command to
263
- # complete
264
- #
265
- # @return [Git::CommandLineResult] the result of the command to return to the
266
- # caller
267
- #
268
- # @raise [Git::FailedError] if the command failed
269
- #
270
- # @raise [Git::SignaledError] if the command was signaled
271
- #
272
- # @raise [Git::TimeoutError] if the command times out
273
- #
274
- # @raise [Git::ProcessIOError] if an exception was raised while collecting
275
- # subprocess output
276
- #
277
- # @api private
278
- #
279
- def process_result(result, normalize, chomp, timeout)
280
- command = result.command
281
- processed_out, processed_err = post_process_output(result, normalize, chomp)
282
- log_result(result, command, processed_out, processed_err)
283
- command_line_result(command, result, processed_out, processed_err, timeout)
284
- end
285
-
286
- def log_result(result, command, processed_out, processed_err)
287
- logger.info { "#{command} exited with status #{result}" }
288
- logger.debug { "stdout:\n#{processed_out.inspect}\nstderr:\n#{processed_err.inspect}" }
289
- end
290
-
291
- def command_line_result(command, result, processed_out, processed_err, timeout)
292
- Git::CommandLineResult.new(command, result, processed_out, processed_err).tap do |processed_result|
293
- raise Git::TimeoutError.new(processed_result, timeout) if result.timeout?
294
-
295
- raise Git::SignaledError, processed_result if result.signaled?
296
-
297
- raise Git::FailedError, processed_result unless result.success?
298
- end
299
- end
300
-
301
- # Post-process and return an array of raw output strings
302
- #
303
- # For each raw output string:
304
- #
305
- # * If normalize: is true, normalize the encoding by transcoding each line from
306
- # the detected encoding to UTF-8.
307
- # * If chomp: is true chomp the output after normalization.
308
- #
309
- # Even if no post-processing is done based on the options, the strings returned
310
- # are a copy of the raw output strings. The raw output strings are not modified.
311
- #
312
- # @param result [ProcessExecuter::ResultWithCapture] the command's output to post-process
313
- #
314
- # @param normalize [Boolean] whether to normalize the output of each writer
315
- # @param chomp [Boolean] whether to chomp the output of each writer
316
- #
317
- # @return [Array<String>]
318
- #
319
- # @api private
320
- #
321
- def post_process_output(result, normalize, chomp)
322
- [result.stdout, result.stderr].map do |raw_output|
323
- output = raw_output.dup
324
- output = output.lines.map { |l| Git::EncodingUtils.normalize_encoding(l) }.join if normalize
325
- output.chomp! if chomp
326
- output
327
- end
328
- end
26
+ # @example Buffered command via Git::CommandLine::Capturing
27
+ # cli = Git::CommandLine::Capturing.new(
28
+ # {}, '/usr/bin/git', [], Logger.new(nil)
29
+ # )
30
+ # result = cli.run('version')
31
+ # result.stdout #=> "git version 2.39.1\n"
32
+ #
33
+ # @example Streaming command via Git::CommandLine::Streaming
34
+ # cli = Git::CommandLine::Streaming.new(
35
+ # {}, '/usr/bin/git', [], Logger.new(nil)
36
+ # )
37
+ # File.open('/tmp/blob', 'wb') do |f|
38
+ # cli.run('cat-file', 'blob', sha, out: f)
39
+ # end
40
+ #
41
+ # @see Git::CommandLine::Base
42
+ # @see Git::CommandLine::Result
43
+ #
44
+ module CommandLine
329
45
  end
330
46
  end
47
+
48
+ require 'git/command_line/result'
49
+ require 'git/command_line/base'
50
+ require 'git/command_line/capturing'
51
+ require 'git/command_line/streaming'
@@ -1,92 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Git
4
- # The result of running a git command
5
- #
6
- # This object stores the Git command executed and its status, stdout, and stderr.
7
- #
8
- # @api public
9
- #
10
- class CommandLineResult
11
- # Create a CommandLineResult object
12
- #
13
- # @example
14
- # `true`
15
- # git_cmd = %w[git version]
16
- # status = $?
17
- # stdout = "git version 2.39.1\n"
18
- # stderr = ""
19
- # result = Git::CommandLineResult.new(git_cmd, status, stdout, stderr)
20
- #
21
- # @param git_cmd [Array<String>] the git command that was executed
22
- # @param status [ProcessExecuter::ResultWithCapture] the status of the process
23
- # @param stdout [String] the processed stdout of the process
24
- # @param stderr [String] the processed stderr of the process
25
- #
26
- def initialize(git_cmd, status, stdout, stderr)
27
- @git_cmd = git_cmd
28
- @status = status
29
- @stdout = stdout
30
- @stderr = stderr
31
-
32
- # ProcessExecuter::ResultWithCapture changed the timeout? method to timed_out?
33
- # in version 4.x. This is a compatibility layer to maintain the old method name
34
- # for backward compatibility.
35
- #
36
- status.define_singleton_method(:timeout?) { timed_out? }
37
- end
38
-
39
- # @attribute [r] git_cmd
40
- #
41
- # The git command that was executed
42
- #
43
- # @example
44
- # git_cmd = %w[git version]
45
- # result = Git::CommandLineResult.new(git_cmd, $?, "", "")
46
- # result.git_cmd #=> ["git", "version"]
47
- #
48
- # @return [Array<String>]
49
- #
50
- attr_reader :git_cmd
3
+ require 'git/command_line/result'
51
4
 
52
- # @attribute [r] status
53
- #
54
- # The status of the process
55
- #
56
- # @example
57
- # `true`
58
- # status = $?
59
- # result = Git::CommandLineResult.new(status, "", "")
60
- # result.status #=> #<Process::Status: pid 87859 exit 0>
61
- #
62
- # @return [Process::Status]
63
- #
64
- attr_reader :status
65
-
66
- # @attribute [r] stdout
67
- #
68
- # The output of the process
69
- #
70
- # @example
71
- # stdout = "git version 2.39.1\n"
72
- # result = Git::CommandLineResult.new($?, stdout, "")
73
- # result.stdout #=> "git version 2.39.1\n"
74
- #
75
- # @return [String]
76
- #
77
- attr_reader :stdout
78
-
79
- # @attribute [r] stderr
80
- #
81
- # The error output of the process
82
- #
83
- # @example
84
- # stderr = "Tag not found\n"
85
- # result = Git::CommandLineResult.new($?, "", stderr)
86
- # result.stderr #=> "Tag not found\n"
87
- #
88
- # @return [String]
89
- #
90
- attr_reader :stderr
91
- end
5
+ module Git
6
+ # Backward-compatible alias for {Git::CommandLine::Result}
7
+ CommandLineResult = Git::CommandLine::Result
92
8
  end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git/commands/base'
4
+
5
+ module Git
6
+ module Commands
7
+ # Implements the `git add` command
8
+ #
9
+ # This command updates the index using the current content found in the working tree,
10
+ # to prepare the content staged for the next commit.
11
+ #
12
+ # @note `arguments` block audited against https://git-scm.com/docs/git-add/2.53.0
13
+ #
14
+ # @see https://git-scm.com/docs/git-add git-add
15
+ #
16
+ # @see Git::Commands
17
+ #
18
+ # @api private
19
+ #
20
+ # @example Basic usage
21
+ # add = Git::Commands::Add.new(execution_context)
22
+ # add.call('path/to/file')
23
+ # add.call('file1.rb', 'file2.rb')
24
+ # add.call(all: true)
25
+ #
26
+ class Add < Git::Commands::Base
27
+ arguments do
28
+ literal 'add'
29
+ flag_option %i[verbose v]
30
+ flag_option %i[dry_run n]
31
+ flag_option %i[force f]
32
+ flag_option %i[all A], negatable: true
33
+ flag_option :ignore_removal, negatable: true
34
+ flag_option %i[update u]
35
+ flag_option :sparse
36
+ flag_option %i[intent_to_add N]
37
+ flag_option :refresh
38
+ flag_option :ignore_errors
39
+ flag_option :ignore_missing
40
+ flag_option :renormalize
41
+ flag_option :no_warn_embedded_repo
42
+ value_option :chmod, inline: true
43
+ value_option :pathspec_from_file, inline: true
44
+ flag_option :pathspec_file_nul
45
+ end_of_options
46
+ operand :pathspec, repeatable: true
47
+ end
48
+
49
+ # @!method call(*, **)
50
+ #
51
+ # @overload call(*pathspec, **options)
52
+ #
53
+ # Execute the `git add` command
54
+ #
55
+ # @param pathspec [Array<String>] files to be added to the repository
56
+ # (relative to the worktree root)
57
+ #
58
+ # @param options [Hash] command options
59
+ #
60
+ # @option options [Boolean, nil] :verbose (nil) be verbose
61
+ #
62
+ # Alias: :v
63
+ #
64
+ # @option options [Boolean, nil] :dry_run (nil) don't actually add files; show what would be added
65
+ #
66
+ # Alias: :n
67
+ #
68
+ # @option options [Boolean, nil] :force (nil) allow adding otherwise ignored files
69
+ #
70
+ # Alias: :f
71
+ #
72
+ # @option options [Boolean, nil] :all (nil) add, modify, and remove index entries to
73
+ # match the worktree (--all)
74
+ #
75
+ # Alias: :A
76
+ #
77
+ # @option options [Boolean, nil] :no_all (nil) add and modify index entries without staging
78
+ # removals (--no-all)
79
+ #
80
+ # @option options [Boolean, nil] :ignore_removal (nil) add and modify files; ignore removals
81
+ # (--ignore-removal)
82
+ #
83
+ # @option options [Boolean, nil] :no_ignore_removal (nil) include file removals (--no-ignore-removal)
84
+ #
85
+ # @option options [Boolean, nil] :update (nil) update tracked files only; does not add new files
86
+ #
87
+ # Alias: :u
88
+ #
89
+ # @option options [Boolean, nil] :sparse (nil) allow updating index entries outside the
90
+ # sparse-checkout cone
91
+ #
92
+ # @option options [Boolean, nil] :intent_to_add (nil) record that the path will be added later,
93
+ # placing an empty entry in the index
94
+ #
95
+ # Alias: :N
96
+ #
97
+ # @option options [Boolean, nil] :refresh (nil) refresh stat() information in the index without
98
+ # adding files
99
+ #
100
+ # @option options [Boolean, nil] :ignore_errors (nil) continue adding other files if some files
101
+ # cannot be added due to indexing errors
102
+ #
103
+ # @option options [Boolean, nil] :ignore_missing (nil) check whether any given files would be
104
+ # ignored
105
+ #
106
+ # @option options [Boolean, nil] :renormalize (nil) apply the "clean" process freshly to all tracked
107
+ # files to forcibly re-add them with correct line endings
108
+ #
109
+ # @option options [Boolean, nil] :no_warn_embedded_repo (nil) suppress warning when adding an
110
+ # embedded repository without using `git submodule add`
111
+ #
112
+ # @option options [String] :chmod (nil) override the executable bit of added files in the index
113
+ #
114
+ # Value must be `'+x'` or `'-x'`
115
+ #
116
+ # @option options [String] :pathspec_from_file (nil) read pathspec from the given file
117
+ # (use `'-'` for stdin)
118
+ #
119
+ # @option options [Boolean, nil] :pathspec_file_nul (nil) separate pathspec elements with NUL
120
+ # when reading from a file
121
+ #
122
+ # @return [Git::CommandLineResult] the result of calling `git add`
123
+ #
124
+ # @raise [ArgumentError] if unsupported options are provided
125
+ #
126
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
127
+ #
128
+ # @api public
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git/commands/base'
4
+
5
+ module Git
6
+ module Commands
7
+ module Am
8
+ # Implements `git am --abort` to abort an in-progress am session
9
+ #
10
+ # Aborts the in-progress patch application and restores the branch to
11
+ # the state it was in before the `git am` session started.
12
+ #
13
+ # @example Abort an am session
14
+ # abort_cmd = Git::Commands::Am::Abort.new(execution_context)
15
+ # abort_cmd.call
16
+ #
17
+ # @note `arguments` block audited against https://git-scm.com/docs/git-am/2.53.0
18
+ #
19
+ # @see Git::Commands::Am
20
+ #
21
+ # @see https://git-scm.com/docs/git-am git-am
22
+ #
23
+ # @api private
24
+ #
25
+ class Abort < Git::Commands::Base
26
+ arguments do
27
+ literal 'am'
28
+ literal '--abort'
29
+ end
30
+
31
+ # @!method call(*, **)
32
+ #
33
+ # @overload call()
34
+ #
35
+ # Abort the in-progress am session and restore the branch
36
+ #
37
+ # @return [Git::CommandLineResult] the result of calling `git am --abort`
38
+ #
39
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
40
+ end
41
+ end
42
+ end
43
+ end