git 4.3.2 → 5.0.0.beta.2

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 (297) hide show
  1. checksums.yaml +4 -4
  2. data/.github/copilot-instructions.md +73 -2705
  3. data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +188 -0
  4. data/.github/pull_request_template.md +3 -1
  5. data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
  6. data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
  7. data/.github/skills/command-implementation/REFERENCE.md +993 -0
  8. data/.github/skills/command-implementation/SKILL.md +229 -0
  9. data/.github/skills/command-test-conventions/SKILL.md +660 -0
  10. data/.github/skills/command-yard-documentation/SKILL.md +426 -0
  11. data/.github/skills/dependency-management/SKILL.md +72 -0
  12. data/.github/skills/development-workflow/SKILL.md +506 -0
  13. data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
  14. data/.github/skills/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +22 -0
  15. data/.github/skills/extract-facade-from-base-lib/SKILL.md +600 -0
  16. data/.github/skills/facade-implementation/REFERENCE.md +840 -0
  17. data/.github/skills/facade-implementation/SKILL.md +274 -0
  18. data/.github/skills/facade-test-conventions/SKILL.md +394 -0
  19. data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
  20. data/.github/skills/make-skill-template/SKILL.md +176 -0
  21. data/.github/skills/pr-readiness-review/SKILL.md +185 -0
  22. data/.github/skills/project-context/SKILL.md +313 -0
  23. data/.github/skills/pull-request-review/SKILL.md +168 -0
  24. data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
  25. data/.github/skills/release-management/SKILL.md +125 -0
  26. data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
  27. data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
  28. data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
  29. data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
  30. data/.github/skills/reviewing-skills/SKILL.md +189 -0
  31. data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
  32. data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
  33. data/.github/skills/test-debugging/SKILL.md +160 -0
  34. data/.github/skills/yard-documentation/SKILL.md +793 -0
  35. data/.github/workflows/continuous_integration.yml +3 -2
  36. data/.github/workflows/enforce_conventional_commits.yml +1 -1
  37. data/.github/workflows/experimental_continuous_integration.yml +2 -2
  38. data/.github/workflows/release.yml +3 -4
  39. data/.gitignore +8 -0
  40. data/.husky/pre-commit +13 -0
  41. data/.release-please-manifest.json +1 -1
  42. data/.rspec +3 -0
  43. data/.rubocop.yml +12 -3
  44. data/.rubocop_todo.yml +23 -5
  45. data/.yardopts +1 -0
  46. data/CHANGELOG.md +0 -40
  47. data/CONTRIBUTING.md +694 -53
  48. data/README.md +67 -15
  49. data/Rakefile +61 -9
  50. data/UPGRADING.md +141 -0
  51. data/commitlint.test +4 -0
  52. data/git.gemspec +18 -7
  53. data/lib/git/args_builder.rb +0 -8
  54. data/lib/git/branch.rb +369 -43
  55. data/lib/git/branch_delete_failure.rb +31 -0
  56. data/lib/git/branch_delete_result.rb +63 -0
  57. data/lib/git/branch_info.rb +178 -0
  58. data/lib/git/branches.rb +122 -24
  59. data/lib/git/command_line/base.rb +255 -0
  60. data/lib/git/command_line/capturing.rb +251 -0
  61. data/lib/git/command_line/result.rb +96 -0
  62. data/lib/git/command_line/streaming.rb +196 -0
  63. data/lib/git/command_line.rb +43 -322
  64. data/lib/git/command_line_result.rb +4 -88
  65. data/lib/git/commands/add.rb +131 -0
  66. data/lib/git/commands/am/abort.rb +43 -0
  67. data/lib/git/commands/am/apply.rb +252 -0
  68. data/lib/git/commands/am/continue.rb +43 -0
  69. data/lib/git/commands/am/quit.rb +43 -0
  70. data/lib/git/commands/am/retry.rb +47 -0
  71. data/lib/git/commands/am/show_current_patch.rb +64 -0
  72. data/lib/git/commands/am/skip.rb +42 -0
  73. data/lib/git/commands/am.rb +33 -0
  74. data/lib/git/commands/apply.rb +237 -0
  75. data/lib/git/commands/archive/list_formats.rb +46 -0
  76. data/lib/git/commands/archive.rb +140 -0
  77. data/lib/git/commands/arguments.rb +3510 -0
  78. data/lib/git/commands/base.rb +404 -0
  79. data/lib/git/commands/branch/copy.rb +94 -0
  80. data/lib/git/commands/branch/create.rb +173 -0
  81. data/lib/git/commands/branch/delete.rb +80 -0
  82. data/lib/git/commands/branch/list.rb +162 -0
  83. data/lib/git/commands/branch/move.rb +94 -0
  84. data/lib/git/commands/branch/set_upstream.rb +86 -0
  85. data/lib/git/commands/branch/show_current.rb +49 -0
  86. data/lib/git/commands/branch/unset_upstream.rb +57 -0
  87. data/lib/git/commands/branch.rb +34 -0
  88. data/lib/git/commands/cat_file/batch.rb +369 -0
  89. data/lib/git/commands/cat_file/filtered.rb +105 -0
  90. data/lib/git/commands/cat_file/raw.rb +216 -0
  91. data/lib/git/commands/cat_file.rb +49 -0
  92. data/lib/git/commands/checkout/branch.rb +151 -0
  93. data/lib/git/commands/checkout/files.rb +115 -0
  94. data/lib/git/commands/checkout.rb +38 -0
  95. data/lib/git/commands/checkout_index.rb +105 -0
  96. data/lib/git/commands/clean.rb +100 -0
  97. data/lib/git/commands/clone.rb +240 -0
  98. data/lib/git/commands/commit.rb +272 -0
  99. data/lib/git/commands/commit_tree.rb +100 -0
  100. data/lib/git/commands/config_option_syntax/add.rb +83 -0
  101. data/lib/git/commands/config_option_syntax/get.rb +117 -0
  102. data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
  103. data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
  104. data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
  105. data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
  106. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +107 -0
  107. data/lib/git/commands/config_option_syntax/list.rb +107 -0
  108. data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
  109. data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
  110. data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
  111. data/lib/git/commands/config_option_syntax/set.rb +114 -0
  112. data/lib/git/commands/config_option_syntax/unset.rb +89 -0
  113. data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
  114. data/lib/git/commands/config_option_syntax.rb +56 -0
  115. data/lib/git/commands/describe.rb +155 -0
  116. data/lib/git/commands/diff.rb +656 -0
  117. data/lib/git/commands/diff_files.rb +518 -0
  118. data/lib/git/commands/diff_index.rb +496 -0
  119. data/lib/git/commands/fetch.rb +352 -0
  120. data/lib/git/commands/fsck.rb +136 -0
  121. data/lib/git/commands/gc.rb +132 -0
  122. data/lib/git/commands/grep.rb +338 -0
  123. data/lib/git/commands/init.rb +99 -0
  124. data/lib/git/commands/log.rb +632 -0
  125. data/lib/git/commands/ls_files.rb +191 -0
  126. data/lib/git/commands/ls_remote.rb +155 -0
  127. data/lib/git/commands/ls_tree.rb +131 -0
  128. data/lib/git/commands/maintenance/register.rb +75 -0
  129. data/lib/git/commands/maintenance/run.rb +104 -0
  130. data/lib/git/commands/maintenance/start.rb +66 -0
  131. data/lib/git/commands/maintenance/stop.rb +55 -0
  132. data/lib/git/commands/maintenance/unregister.rb +79 -0
  133. data/lib/git/commands/maintenance.rb +31 -0
  134. data/lib/git/commands/merge/abort.rb +44 -0
  135. data/lib/git/commands/merge/continue.rb +44 -0
  136. data/lib/git/commands/merge/quit.rb +46 -0
  137. data/lib/git/commands/merge/start.rb +245 -0
  138. data/lib/git/commands/merge.rb +28 -0
  139. data/lib/git/commands/merge_base.rb +86 -0
  140. data/lib/git/commands/mv.rb +77 -0
  141. data/lib/git/commands/name_rev.rb +114 -0
  142. data/lib/git/commands/pull.rb +377 -0
  143. data/lib/git/commands/push.rb +246 -0
  144. data/lib/git/commands/read_tree.rb +149 -0
  145. data/lib/git/commands/remote/add.rb +91 -0
  146. data/lib/git/commands/remote/get_url.rb +66 -0
  147. data/lib/git/commands/remote/list.rb +54 -0
  148. data/lib/git/commands/remote/prune.rb +61 -0
  149. data/lib/git/commands/remote/remove.rb +52 -0
  150. data/lib/git/commands/remote/rename.rb +69 -0
  151. data/lib/git/commands/remote/set_branches.rb +63 -0
  152. data/lib/git/commands/remote/set_head.rb +82 -0
  153. data/lib/git/commands/remote/set_url.rb +71 -0
  154. data/lib/git/commands/remote/set_url_add.rb +61 -0
  155. data/lib/git/commands/remote/set_url_delete.rb +64 -0
  156. data/lib/git/commands/remote/show.rb +71 -0
  157. data/lib/git/commands/remote/update.rb +72 -0
  158. data/lib/git/commands/remote.rb +42 -0
  159. data/lib/git/commands/repack.rb +277 -0
  160. data/lib/git/commands/reset.rb +147 -0
  161. data/lib/git/commands/rev_parse.rb +297 -0
  162. data/lib/git/commands/revert/abort.rb +45 -0
  163. data/lib/git/commands/revert/continue.rb +57 -0
  164. data/lib/git/commands/revert/quit.rb +47 -0
  165. data/lib/git/commands/revert/skip.rb +44 -0
  166. data/lib/git/commands/revert/start.rb +153 -0
  167. data/lib/git/commands/revert.rb +29 -0
  168. data/lib/git/commands/rm.rb +114 -0
  169. data/lib/git/commands/show.rb +632 -0
  170. data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
  171. data/lib/git/commands/show_ref/exists.rb +78 -0
  172. data/lib/git/commands/show_ref/list.rb +145 -0
  173. data/lib/git/commands/show_ref/verify.rb +120 -0
  174. data/lib/git/commands/show_ref.rb +42 -0
  175. data/lib/git/commands/stash/apply.rb +75 -0
  176. data/lib/git/commands/stash/branch.rb +65 -0
  177. data/lib/git/commands/stash/clear.rb +41 -0
  178. data/lib/git/commands/stash/create.rb +58 -0
  179. data/lib/git/commands/stash/drop.rb +67 -0
  180. data/lib/git/commands/stash/list.rb +39 -0
  181. data/lib/git/commands/stash/pop.rb +78 -0
  182. data/lib/git/commands/stash/push.rb +103 -0
  183. data/lib/git/commands/stash/show.rb +149 -0
  184. data/lib/git/commands/stash/store.rb +63 -0
  185. data/lib/git/commands/stash.rb +38 -0
  186. data/lib/git/commands/status.rb +169 -0
  187. data/lib/git/commands/symbolic_ref/delete.rb +68 -0
  188. data/lib/git/commands/symbolic_ref/read.rb +95 -0
  189. data/lib/git/commands/symbolic_ref/update.rb +76 -0
  190. data/lib/git/commands/symbolic_ref.rb +38 -0
  191. data/lib/git/commands/tag/create.rb +139 -0
  192. data/lib/git/commands/tag/delete.rb +55 -0
  193. data/lib/git/commands/tag/list.rb +143 -0
  194. data/lib/git/commands/tag/verify.rb +71 -0
  195. data/lib/git/commands/tag.rb +26 -0
  196. data/lib/git/commands/update_ref/batch.rb +140 -0
  197. data/lib/git/commands/update_ref/delete.rb +92 -0
  198. data/lib/git/commands/update_ref/update.rb +106 -0
  199. data/lib/git/commands/update_ref.rb +42 -0
  200. data/lib/git/commands/version.rb +57 -0
  201. data/lib/git/commands/worktree/add.rb +140 -0
  202. data/lib/git/commands/worktree/list.rb +64 -0
  203. data/lib/git/commands/worktree/lock.rb +58 -0
  204. data/lib/git/commands/worktree/management_base.rb +51 -0
  205. data/lib/git/commands/worktree/move.rb +66 -0
  206. data/lib/git/commands/worktree/prune.rb +67 -0
  207. data/lib/git/commands/worktree/remove.rb +63 -0
  208. data/lib/git/commands/worktree/repair.rb +76 -0
  209. data/lib/git/commands/worktree/unlock.rb +47 -0
  210. data/lib/git/commands/worktree.rb +43 -0
  211. data/lib/git/commands/write_tree.rb +68 -0
  212. data/lib/git/commands.rb +87 -0
  213. data/lib/git/config.rb +17 -0
  214. data/lib/git/config_entry_info.rb +106 -0
  215. data/lib/git/configuring.rb +665 -0
  216. data/lib/git/deprecation.rb +9 -0
  217. data/lib/git/detached_head_info.rb +54 -0
  218. data/lib/git/diff.rb +293 -7
  219. data/lib/git/diff_file_numstat_info.rb +29 -0
  220. data/lib/git/diff_file_patch_info.rb +134 -0
  221. data/lib/git/diff_file_raw_info.rb +127 -0
  222. data/lib/git/diff_info.rb +169 -0
  223. data/lib/git/diff_path_status.rb +67 -19
  224. data/lib/git/diff_result.rb +32 -0
  225. data/lib/git/diff_stats.rb +51 -14
  226. data/lib/git/dirstat_info.rb +86 -0
  227. data/lib/git/errors.rb +65 -2
  228. data/lib/git/execution_context/global.rb +31 -0
  229. data/lib/git/execution_context/repository.rb +136 -0
  230. data/lib/git/execution_context.rb +501 -0
  231. data/lib/git/file_ref.rb +74 -0
  232. data/lib/git/fsck_object.rb +9 -9
  233. data/lib/git/fsck_result.rb +1 -1
  234. data/lib/git/log.rb +9 -2
  235. data/lib/git/object.rb +90 -27
  236. data/lib/git/parsers/branch.rb +224 -0
  237. data/lib/git/parsers/cat_file.rb +111 -0
  238. data/lib/git/parsers/config_entry.rb +110 -0
  239. data/lib/git/parsers/diff.rb +585 -0
  240. data/lib/git/parsers/fsck.rb +133 -0
  241. data/lib/git/parsers/grep.rb +42 -0
  242. data/lib/git/parsers/ls_remote.rb +79 -0
  243. data/lib/git/parsers/ls_tree.rb +58 -0
  244. data/lib/git/parsers/stash.rb +208 -0
  245. data/lib/git/parsers/tag.rb +257 -0
  246. data/lib/git/remote.rb +120 -9
  247. data/lib/git/repository/branching.rb +743 -0
  248. data/lib/git/repository/committing.rb +187 -0
  249. data/lib/git/repository/configuring.rb +351 -0
  250. data/lib/git/repository/context_helpers.rb +264 -0
  251. data/lib/git/repository/diffing.rb +775 -0
  252. data/lib/git/repository/factories.rb +682 -0
  253. data/lib/git/repository/inspecting.rb +252 -0
  254. data/lib/git/repository/logging.rb +247 -0
  255. data/lib/git/repository/maintenance.rb +65 -0
  256. data/lib/git/repository/merging.rb +357 -0
  257. data/lib/git/repository/object_operations.rb +1199 -0
  258. data/lib/git/repository/path_resolver.rb +207 -0
  259. data/lib/git/repository/remote_operations.rb +898 -0
  260. data/lib/git/repository/shared_private.rb +51 -0
  261. data/lib/git/repository/staging.rb +554 -0
  262. data/lib/git/repository/stashing.rb +143 -0
  263. data/lib/git/repository/status_operations.rb +201 -0
  264. data/lib/git/repository/worktree_operations.rb +159 -0
  265. data/lib/git/repository.rb +203 -1
  266. data/lib/git/stash.rb +78 -4
  267. data/lib/git/stash_info.rb +104 -0
  268. data/lib/git/stashes.rb +125 -13
  269. data/lib/git/status.rb +215 -18
  270. data/lib/git/tag_delete_failure.rb +31 -0
  271. data/lib/git/tag_delete_result.rb +63 -0
  272. data/lib/git/tag_info.rb +105 -0
  273. data/lib/git/version.rb +109 -2
  274. data/lib/git/version_constraint.rb +81 -0
  275. data/lib/git/worktree.rb +108 -6
  276. data/lib/git/worktrees.rb +94 -7
  277. data/lib/git.rb +260 -61
  278. data/redesign/1_architecture_existing.md +54 -18
  279. data/redesign/2_architecture_redesign.md +365 -46
  280. data/redesign/3_architecture_implementation.md +1497 -63
  281. data/redesign/Phase 4 - Step A.md +360 -0
  282. data/redesign/beta_release.md +107 -0
  283. data/redesign/c1c2_audit.md +566 -0
  284. data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
  285. data/redesign/config_design.rb +501 -0
  286. data/tasks/gem_tasks.rake +4 -0
  287. data/tasks/npm_tasks.rake +7 -0
  288. data/tasks/rspec.rake +48 -0
  289. data/tasks/test.rake +13 -1
  290. data/tasks/yard.rake +34 -7
  291. metadata +365 -22
  292. data/lib/git/base.rb +0 -1128
  293. data/lib/git/index.rb +0 -6
  294. data/lib/git/lib.rb +0 -2277
  295. data/lib/git/path.rb +0 -38
  296. data/lib/git/working_directory.rb +0 -6
  297. /data/{release-please-config.json → .release-please-config.json} +0 -0
@@ -0,0 +1,264 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'pathname'
5
+ require 'tmpdir'
6
+ require 'git/execution_context/repository'
7
+
8
+ module Git
9
+ class Repository
10
+ # Facade methods for block-based directory and index context helpers
11
+ #
12
+ # These helpers allow callers to temporarily change the working directory,
13
+ # the git index, or both, restoring the original state unconditionally when
14
+ # the block exits — even if the block raises an exception.
15
+ #
16
+ # Included by {Git::Repository}.
17
+ #
18
+ # @api public
19
+ #
20
+ module ContextHelpers
21
+ # Changes the current working directory to the repository working directory
22
+ # for the duration of the block
23
+ #
24
+ # @example Write a file inside the repository working directory
25
+ # repo.chdir do |dir|
26
+ # File.write('hello.txt', 'Hello, world!')
27
+ # repo.add('hello.txt')
28
+ # end
29
+ #
30
+ # @yield [dir] the repository working directory
31
+ #
32
+ # @yieldparam dir [Pathname] the working directory path
33
+ #
34
+ # @yieldreturn [Object] returned as the method's return value
35
+ #
36
+ # @return [Object] the value returned by the block
37
+ #
38
+ # @raise [ArgumentError] if the repository has no working directory (bare
39
+ # repository)
40
+ #
41
+ def chdir
42
+ raise ArgumentError, 'cannot chdir: repository has no working directory (bare repository)' if dir.nil?
43
+
44
+ Dir.chdir(dir.to_s) { yield dir }
45
+ end
46
+
47
+ # Temporarily switches the git index to `new_index` for the duration of
48
+ # the block
49
+ #
50
+ # Rebuilds the repository execution context to point to the new index file,
51
+ # yields `self`, then unconditionally restores the original execution
52
+ # context — even if the block raises an exception.
53
+ #
54
+ # @example Read a tree into a custom index
55
+ # repo.with_index('/tmp/custom.index') do
56
+ # repo.read_tree('HEAD')
57
+ # end
58
+ #
59
+ # @param new_index [String, Pathname] path to the replacement index file
60
+ #
61
+ # @yield [repo] the repository instance with the new index active
62
+ #
63
+ # @yieldparam repo [Git::Repository] `self`
64
+ #
65
+ # @yieldreturn [Object] returned as the method's return value
66
+ #
67
+ # @return [Object] the value returned by the block
68
+ #
69
+ def with_index(new_index) # :yields: self
70
+ old_context = @execution_context
71
+ set_index(new_index, must_exist: false)
72
+ yield self
73
+ ensure
74
+ @execution_context = old_context
75
+ end
76
+
77
+ # Temporarily switches the git index to a new temporary file for the
78
+ # duration of the block, then removes the file
79
+ #
80
+ # The temporary index file does not exist until git creates it on first
81
+ # write. A unique temporary directory is created to hold the index path,
82
+ # avoiding the risk of presenting an empty file to git (which git would
83
+ # reject as a corrupt index). The directory — and any files inside it —
84
+ # are removed unconditionally after the block exits, even if the block
85
+ # raises an exception.
86
+ #
87
+ # @example Stage changes using a temporary index
88
+ # repo.with_temp_index do
89
+ # repo.read_tree('HEAD')
90
+ # repo.write_tree
91
+ # end
92
+ #
93
+ # @yield [repo] the repository instance with the temporary index active
94
+ #
95
+ # @yieldparam repo [Git::Repository] `self`
96
+ #
97
+ # @yieldreturn [Object] returned as the method's return value
98
+ #
99
+ # @return [Object] the value returned by the block
100
+ #
101
+ def with_temp_index(&) # :yields: self
102
+ # Use a unique temp directory so the index file path is collision-free
103
+ # and does not exist until git writes it. An existing empty file would
104
+ # be treated as a corrupt index by git.
105
+ temp_dir = Dir.mktmpdir('git-temp-index-')
106
+ begin
107
+ with_index(File.join(temp_dir, 'index'), &)
108
+ ensure
109
+ FileUtils.remove_entry(temp_dir, true)
110
+ end
111
+ end
112
+
113
+ # Temporarily switches the git working directory to `work_dir` for the
114
+ # duration of the block
115
+ #
116
+ # Rebuilds the repository execution context to point to the new working
117
+ # directory, changes the process working directory via `Dir.chdir`, yields
118
+ # `self`, then unconditionally restores the original execution context —
119
+ # even if the block raises an exception.
120
+ #
121
+ # @example Commit changes from a different worktree path
122
+ # repo.with_working('/path/to/worktree') do
123
+ # repo.add('.')
124
+ # repo.commit('chore: automated update')
125
+ # end
126
+ #
127
+ # @param work_dir [String, Pathname] path to the replacement working
128
+ # directory
129
+ #
130
+ # @yield [repo] the repository instance with the new working directory
131
+ # active
132
+ #
133
+ # @yieldparam repo [Git::Repository] `self`
134
+ #
135
+ # @yieldreturn [Object] returned as the method's return value
136
+ #
137
+ # @return [Object] the value returned by the block
138
+ #
139
+ # @raise [ArgumentError] if `work_dir` does not exist on disk
140
+ #
141
+ def with_working(work_dir) # :yields: self
142
+ old_context = @execution_context
143
+ set_working(work_dir)
144
+ Dir.chdir(dir.to_s) { yield self }
145
+ ensure
146
+ @execution_context = old_context
147
+ end
148
+
149
+ # Temporarily switches the git working directory to a new temporary
150
+ # directory for the duration of the block, then removes the directory and
151
+ # its contents
152
+ #
153
+ # The temporary directory is removed unconditionally after the block
154
+ # exits, even if the block raises an exception.
155
+ #
156
+ # @example Write files in an isolated temporary working directory
157
+ # repo.with_temp_working do
158
+ # File.write('scratch.txt', 'temporary content')
159
+ # end
160
+ #
161
+ # @yield [repo] the repository instance with the temporary working
162
+ # directory active
163
+ #
164
+ # @yieldparam repo [Git::Repository] `self`
165
+ #
166
+ # @yieldreturn [Object] returned as the method's return value
167
+ #
168
+ # @return [Object] the value returned by the block
169
+ #
170
+ def with_temp_working(&block) # :yields: self
171
+ Dir.mktmpdir('temp-workdir') { |temp_dir| with_working(temp_dir, &block) }
172
+ end
173
+
174
+ # Sets the git index to `index_file` and rebuilds the execution context
175
+ #
176
+ # By default raises if `index_file` does not exist. Pass `must_exist:
177
+ # false` to skip the existence check (useful when the index will be
178
+ # created by git later).
179
+ #
180
+ # @example Set the index to a custom path
181
+ # repo.set_index('/path/to/custom.index')
182
+ #
183
+ # @param index_file [String, Pathname] path to the new index file
184
+ #
185
+ # @param check [Boolean, nil] deprecated positional argument — use
186
+ # `must_exist:` instead; emits a deprecation warning when non-`nil`
187
+ #
188
+ # @param must_exist [Boolean, nil] when `true` (the default), raises
189
+ # `ArgumentError` if `index_file` does not exist on disk
190
+ #
191
+ # @return [void]
192
+ #
193
+ # @raise [ArgumentError] if `must_exist: true` (the default) and
194
+ # `index_file` does not exist
195
+ #
196
+ def set_index(index_file, check = nil, must_exist: nil)
197
+ must_exist = context_helpers_deprecate_check_argument(check, must_exist)
198
+ new_path = context_helpers_validate_path(index_file, must_exist)
199
+ context_helpers_rebuild_context(git_index_file: new_path.to_s)
200
+ nil
201
+ end
202
+
203
+ # Sets the git working directory to `work_dir` and rebuilds the execution
204
+ # context
205
+ #
206
+ # By default raises if `work_dir` does not exist. Pass `must_exist:
207
+ # false` to skip the existence check.
208
+ #
209
+ # @example Set the working directory to a custom path
210
+ # repo.set_working('/path/to/working')
211
+ #
212
+ # @param work_dir [String, Pathname] path to the new working directory
213
+ #
214
+ # @param check [Boolean, nil] deprecated positional argument — use
215
+ # `must_exist:` instead; emits a deprecation warning when non-`nil`
216
+ #
217
+ # @param must_exist [Boolean, nil] when `true` (the default), raises
218
+ # `ArgumentError` if `work_dir` does not exist on disk
219
+ #
220
+ # @return [void]
221
+ #
222
+ # @raise [ArgumentError] if `must_exist: true` (the default) and
223
+ # `work_dir` does not exist
224
+ #
225
+ def set_working(work_dir, check = nil, must_exist: nil)
226
+ must_exist = context_helpers_deprecate_check_argument(check, must_exist)
227
+ new_path = context_helpers_validate_path(work_dir, must_exist)
228
+ context_helpers_rebuild_context(git_work_dir: new_path.to_s)
229
+ nil
230
+ end
231
+
232
+ private
233
+
234
+ def context_helpers_deprecate_check_argument(check, must_exist)
235
+ if !check.nil? && defined?(Git::Deprecation)
236
+ Git::Deprecation.warn(
237
+ 'The "check" argument is deprecated and will be removed in a future version. ' \
238
+ 'Use "must_exist:" instead.'
239
+ )
240
+ end
241
+ # Preserve the original Git::Base semantics: when both the deprecated
242
+ # positional `check` and the new `must_exist:` keyword are given, OR
243
+ # them so the more restrictive value wins.
244
+ #
245
+ # NilClass#| is defined in Ruby: nil | false → false, nil | true → true.
246
+ # This means single-argument callers (check only, or must_exist: only)
247
+ # are handled correctly without any nil-special-casing.
248
+ return true if must_exist.nil? && check.nil?
249
+
250
+ must_exist | check
251
+ end
252
+
253
+ def context_helpers_validate_path(path, must_exist)
254
+ Pathname.new(File.expand_path(path.to_s)).tap do |expanded_path|
255
+ raise ArgumentError, "path does not exist: #{expanded_path}" if must_exist && !expanded_path.exist?
256
+ end
257
+ end
258
+
259
+ def context_helpers_rebuild_context(**overrides)
260
+ @execution_context = @execution_context.dup_with(**overrides)
261
+ end
262
+ end
263
+ end
264
+ end