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.
- checksums.yaml +4 -4
- data/.github/copilot-instructions.md +73 -2705
- data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +188 -0
- data/.github/pull_request_template.md +3 -1
- data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
- data/.github/skills/command-implementation/REFERENCE.md +993 -0
- data/.github/skills/command-implementation/SKILL.md +229 -0
- data/.github/skills/command-test-conventions/SKILL.md +660 -0
- data/.github/skills/command-yard-documentation/SKILL.md +426 -0
- data/.github/skills/dependency-management/SKILL.md +72 -0
- data/.github/skills/development-workflow/SKILL.md +506 -0
- data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
- data/.github/skills/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +22 -0
- data/.github/skills/extract-facade-from-base-lib/SKILL.md +600 -0
- data/.github/skills/facade-implementation/REFERENCE.md +840 -0
- data/.github/skills/facade-implementation/SKILL.md +274 -0
- data/.github/skills/facade-test-conventions/SKILL.md +394 -0
- data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
- data/.github/skills/make-skill-template/SKILL.md +176 -0
- data/.github/skills/pr-readiness-review/SKILL.md +185 -0
- data/.github/skills/project-context/SKILL.md +313 -0
- data/.github/skills/pull-request-review/SKILL.md +168 -0
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
- data/.github/skills/release-management/SKILL.md +125 -0
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
- data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
- data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
- data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
- data/.github/skills/reviewing-skills/SKILL.md +189 -0
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
- data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
- data/.github/skills/test-debugging/SKILL.md +160 -0
- data/.github/skills/yard-documentation/SKILL.md +793 -0
- data/.github/workflows/continuous_integration.yml +3 -2
- data/.github/workflows/enforce_conventional_commits.yml +1 -1
- data/.github/workflows/experimental_continuous_integration.yml +2 -2
- data/.github/workflows/release.yml +3 -4
- data/.gitignore +8 -0
- data/.husky/pre-commit +13 -0
- data/.release-please-manifest.json +1 -1
- data/.rspec +3 -0
- data/.rubocop.yml +12 -3
- data/.rubocop_todo.yml +23 -5
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -40
- data/CONTRIBUTING.md +694 -53
- data/README.md +67 -15
- data/Rakefile +61 -9
- data/UPGRADING.md +141 -0
- data/commitlint.test +4 -0
- data/git.gemspec +18 -7
- data/lib/git/args_builder.rb +0 -8
- data/lib/git/branch.rb +369 -43
- data/lib/git/branch_delete_failure.rb +31 -0
- data/lib/git/branch_delete_result.rb +63 -0
- data/lib/git/branch_info.rb +178 -0
- data/lib/git/branches.rb +122 -24
- data/lib/git/command_line/base.rb +255 -0
- data/lib/git/command_line/capturing.rb +251 -0
- data/lib/git/command_line/result.rb +96 -0
- data/lib/git/command_line/streaming.rb +196 -0
- data/lib/git/command_line.rb +43 -322
- data/lib/git/command_line_result.rb +4 -88
- data/lib/git/commands/add.rb +131 -0
- data/lib/git/commands/am/abort.rb +43 -0
- data/lib/git/commands/am/apply.rb +252 -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 +47 -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 +237 -0
- data/lib/git/commands/archive/list_formats.rb +46 -0
- data/lib/git/commands/archive.rb +140 -0
- data/lib/git/commands/arguments.rb +3510 -0
- data/lib/git/commands/base.rb +404 -0
- data/lib/git/commands/branch/copy.rb +94 -0
- data/lib/git/commands/branch/create.rb +173 -0
- data/lib/git/commands/branch/delete.rb +80 -0
- data/lib/git/commands/branch/list.rb +162 -0
- data/lib/git/commands/branch/move.rb +94 -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 +57 -0
- data/lib/git/commands/branch.rb +34 -0
- data/lib/git/commands/cat_file/batch.rb +369 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +216 -0
- data/lib/git/commands/cat_file.rb +49 -0
- data/lib/git/commands/checkout/branch.rb +151 -0
- data/lib/git/commands/checkout/files.rb +115 -0
- data/lib/git/commands/checkout.rb +38 -0
- data/lib/git/commands/checkout_index.rb +105 -0
- data/lib/git/commands/clean.rb +100 -0
- data/lib/git/commands/clone.rb +240 -0
- data/lib/git/commands/commit.rb +272 -0
- data/lib/git/commands/commit_tree.rb +100 -0
- data/lib/git/commands/config_option_syntax/add.rb +83 -0
- data/lib/git/commands/config_option_syntax/get.rb +117 -0
- data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
- data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +107 -0
- data/lib/git/commands/config_option_syntax/list.rb +107 -0
- data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
- data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
- data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
- data/lib/git/commands/config_option_syntax/set.rb +114 -0
- data/lib/git/commands/config_option_syntax/unset.rb +89 -0
- data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
- data/lib/git/commands/config_option_syntax.rb +56 -0
- data/lib/git/commands/describe.rb +155 -0
- data/lib/git/commands/diff.rb +656 -0
- data/lib/git/commands/diff_files.rb +518 -0
- data/lib/git/commands/diff_index.rb +496 -0
- data/lib/git/commands/fetch.rb +352 -0
- data/lib/git/commands/fsck.rb +136 -0
- data/lib/git/commands/gc.rb +132 -0
- data/lib/git/commands/grep.rb +338 -0
- data/lib/git/commands/init.rb +99 -0
- data/lib/git/commands/log.rb +632 -0
- data/lib/git/commands/ls_files.rb +191 -0
- data/lib/git/commands/ls_remote.rb +155 -0
- data/lib/git/commands/ls_tree.rb +131 -0
- data/lib/git/commands/maintenance/register.rb +75 -0
- data/lib/git/commands/maintenance/run.rb +104 -0
- data/lib/git/commands/maintenance/start.rb +66 -0
- data/lib/git/commands/maintenance/stop.rb +55 -0
- data/lib/git/commands/maintenance/unregister.rb +79 -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 +245 -0
- data/lib/git/commands/merge.rb +28 -0
- data/lib/git/commands/merge_base.rb +86 -0
- data/lib/git/commands/mv.rb +77 -0
- data/lib/git/commands/name_rev.rb +114 -0
- data/lib/git/commands/pull.rb +377 -0
- data/lib/git/commands/push.rb +246 -0
- data/lib/git/commands/read_tree.rb +149 -0
- data/lib/git/commands/remote/add.rb +91 -0
- data/lib/git/commands/remote/get_url.rb +66 -0
- data/lib/git/commands/remote/list.rb +54 -0
- data/lib/git/commands/remote/prune.rb +61 -0
- data/lib/git/commands/remote/remove.rb +52 -0
- data/lib/git/commands/remote/rename.rb +69 -0
- data/lib/git/commands/remote/set_branches.rb +63 -0
- data/lib/git/commands/remote/set_head.rb +82 -0
- data/lib/git/commands/remote/set_url.rb +71 -0
- data/lib/git/commands/remote/set_url_add.rb +61 -0
- data/lib/git/commands/remote/set_url_delete.rb +64 -0
- data/lib/git/commands/remote/show.rb +71 -0
- data/lib/git/commands/remote/update.rb +72 -0
- data/lib/git/commands/remote.rb +42 -0
- data/lib/git/commands/repack.rb +277 -0
- data/lib/git/commands/reset.rb +147 -0
- data/lib/git/commands/rev_parse.rb +297 -0
- data/lib/git/commands/revert/abort.rb +45 -0
- data/lib/git/commands/revert/continue.rb +57 -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 +153 -0
- data/lib/git/commands/revert.rb +29 -0
- data/lib/git/commands/rm.rb +114 -0
- data/lib/git/commands/show.rb +632 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
- data/lib/git/commands/show_ref/exists.rb +78 -0
- data/lib/git/commands/show_ref/list.rb +145 -0
- data/lib/git/commands/show_ref/verify.rb +120 -0
- data/lib/git/commands/show_ref.rb +42 -0
- data/lib/git/commands/stash/apply.rb +75 -0
- data/lib/git/commands/stash/branch.rb +65 -0
- data/lib/git/commands/stash/clear.rb +41 -0
- data/lib/git/commands/stash/create.rb +58 -0
- data/lib/git/commands/stash/drop.rb +67 -0
- data/lib/git/commands/stash/list.rb +39 -0
- data/lib/git/commands/stash/pop.rb +78 -0
- data/lib/git/commands/stash/push.rb +103 -0
- data/lib/git/commands/stash/show.rb +149 -0
- data/lib/git/commands/stash/store.rb +63 -0
- data/lib/git/commands/stash.rb +38 -0
- data/lib/git/commands/status.rb +169 -0
- data/lib/git/commands/symbolic_ref/delete.rb +68 -0
- data/lib/git/commands/symbolic_ref/read.rb +95 -0
- data/lib/git/commands/symbolic_ref/update.rb +76 -0
- data/lib/git/commands/symbolic_ref.rb +38 -0
- data/lib/git/commands/tag/create.rb +139 -0
- data/lib/git/commands/tag/delete.rb +55 -0
- data/lib/git/commands/tag/list.rb +143 -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 +140 -0
- data/lib/git/commands/update_ref/delete.rb +92 -0
- data/lib/git/commands/update_ref/update.rb +106 -0
- data/lib/git/commands/update_ref.rb +42 -0
- data/lib/git/commands/version.rb +57 -0
- data/lib/git/commands/worktree/add.rb +140 -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 +87 -0
- data/lib/git/config.rb +17 -0
- data/lib/git/config_entry_info.rb +106 -0
- data/lib/git/configuring.rb +665 -0
- data/lib/git/deprecation.rb +9 -0
- data/lib/git/detached_head_info.rb +54 -0
- data/lib/git/diff.rb +293 -7
- data/lib/git/diff_file_numstat_info.rb +29 -0
- data/lib/git/diff_file_patch_info.rb +134 -0
- data/lib/git/diff_file_raw_info.rb +127 -0
- data/lib/git/diff_info.rb +169 -0
- data/lib/git/diff_path_status.rb +67 -19
- data/lib/git/diff_result.rb +32 -0
- data/lib/git/diff_stats.rb +51 -14
- data/lib/git/dirstat_info.rb +86 -0
- data/lib/git/errors.rb +65 -2
- data/lib/git/execution_context/global.rb +31 -0
- data/lib/git/execution_context/repository.rb +136 -0
- data/lib/git/execution_context.rb +501 -0
- data/lib/git/file_ref.rb +74 -0
- data/lib/git/fsck_object.rb +9 -9
- data/lib/git/fsck_result.rb +1 -1
- data/lib/git/log.rb +9 -2
- data/lib/git/object.rb +90 -27
- data/lib/git/parsers/branch.rb +224 -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 +585 -0
- data/lib/git/parsers/fsck.rb +133 -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/stash.rb +208 -0
- data/lib/git/parsers/tag.rb +257 -0
- data/lib/git/remote.rb +120 -9
- data/lib/git/repository/branching.rb +743 -0
- data/lib/git/repository/committing.rb +187 -0
- data/lib/git/repository/configuring.rb +351 -0
- data/lib/git/repository/context_helpers.rb +264 -0
- data/lib/git/repository/diffing.rb +775 -0
- data/lib/git/repository/factories.rb +682 -0
- data/lib/git/repository/inspecting.rb +252 -0
- data/lib/git/repository/logging.rb +247 -0
- data/lib/git/repository/maintenance.rb +65 -0
- data/lib/git/repository/merging.rb +357 -0
- data/lib/git/repository/object_operations.rb +1199 -0
- data/lib/git/repository/path_resolver.rb +207 -0
- data/lib/git/repository/remote_operations.rb +898 -0
- data/lib/git/repository/shared_private.rb +51 -0
- data/lib/git/repository/staging.rb +554 -0
- data/lib/git/repository/stashing.rb +143 -0
- data/lib/git/repository/status_operations.rb +201 -0
- data/lib/git/repository/worktree_operations.rb +159 -0
- data/lib/git/repository.rb +203 -1
- data/lib/git/stash.rb +78 -4
- data/lib/git/stash_info.rb +104 -0
- data/lib/git/stashes.rb +125 -13
- data/lib/git/status.rb +215 -18
- data/lib/git/tag_delete_failure.rb +31 -0
- data/lib/git/tag_delete_result.rb +63 -0
- data/lib/git/tag_info.rb +105 -0
- data/lib/git/version.rb +109 -2
- data/lib/git/version_constraint.rb +81 -0
- data/lib/git/worktree.rb +108 -6
- data/lib/git/worktrees.rb +94 -7
- data/lib/git.rb +260 -61
- data/redesign/1_architecture_existing.md +54 -18
- data/redesign/2_architecture_redesign.md +365 -46
- data/redesign/3_architecture_implementation.md +1497 -63
- data/redesign/Phase 4 - Step A.md +360 -0
- data/redesign/beta_release.md +107 -0
- data/redesign/c1c2_audit.md +566 -0
- data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
- data/redesign/config_design.rb +501 -0
- data/tasks/gem_tasks.rake +4 -0
- data/tasks/npm_tasks.rake +7 -0
- data/tasks/rspec.rake +48 -0
- data/tasks/test.rake +13 -1
- data/tasks/yard.rake +34 -7
- metadata +365 -22
- data/lib/git/base.rb +0 -1128
- data/lib/git/index.rb +0 -6
- data/lib/git/lib.rb +0 -2277
- data/lib/git/path.rb +0 -38
- data/lib/git/working_directory.rb +0 -6
- /data/{release-please-config.json → .release-please-config.json} +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/commands/stash'
|
|
4
|
+
require 'git/parsers/stash'
|
|
5
|
+
|
|
6
|
+
module Git
|
|
7
|
+
class Repository
|
|
8
|
+
# Facade methods for stash operations
|
|
9
|
+
#
|
|
10
|
+
# Included by {Git::Repository}.
|
|
11
|
+
#
|
|
12
|
+
# @api public
|
|
13
|
+
#
|
|
14
|
+
module Stashing
|
|
15
|
+
# Returns all stash entries as an array of index and message pairs
|
|
16
|
+
#
|
|
17
|
+
# Lists all stash entries in the repository ordered from oldest to newest.
|
|
18
|
+
# The index is a sequential number starting from 0 for the oldest stash. The
|
|
19
|
+
# message is the stash description with the leading branch prefix (e.g.
|
|
20
|
+
# `"On main:"` or `"WIP on main:"`) stripped.
|
|
21
|
+
#
|
|
22
|
+
# @note The sequential index returned here is **not** the same as git's
|
|
23
|
+
# `stash@{N}` reference used by {#stash_apply}. In git, `stash@{0}` is the
|
|
24
|
+
# **most recent** stash, while index `0` here is the **oldest**. To apply a
|
|
25
|
+
# specific stash from this list, convert the entry's position to a git
|
|
26
|
+
# reference: `'stash@{%d}' % (total - 1 - index)`, or pass the string
|
|
27
|
+
# reference directly to {#stash_apply}.
|
|
28
|
+
#
|
|
29
|
+
# @example List all stashes (oldest first)
|
|
30
|
+
# repo.stashes_all #=> [[0, "Fix bug"], [1, "Add feature"]]
|
|
31
|
+
#
|
|
32
|
+
# @return [Array<Array(Integer, String)>] array of `[index, message]` pairs
|
|
33
|
+
# where index is the sequential position (0 is oldest) and message is the
|
|
34
|
+
# stash description with the branch prefix stripped
|
|
35
|
+
#
|
|
36
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
37
|
+
#
|
|
38
|
+
# @see https://git-scm.com/docs/git-stash git-stash documentation
|
|
39
|
+
#
|
|
40
|
+
def stashes_all
|
|
41
|
+
result = Git::Commands::Stash::List.new(@execution_context).call
|
|
42
|
+
stashes = Git::Parsers::Stash.parse_list(result.stdout)
|
|
43
|
+
stashes.reverse.each_with_index.map do |info, i|
|
|
44
|
+
message = info.message.sub(/^(?:WIP on|On)\s+[^:]+:\s*/, '')
|
|
45
|
+
[i, message]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Returns stash entries as a formatted string matching `git stash list` output
|
|
50
|
+
#
|
|
51
|
+
# @deprecated Use {#stashes_all} instead.
|
|
52
|
+
#
|
|
53
|
+
# @example List stashes as a formatted string
|
|
54
|
+
# repo.stash_list #=> "stash@{0}: On main: WIP\nstash@{1}: On feature: Fix bug"
|
|
55
|
+
#
|
|
56
|
+
# @return [String] newline-joined `"stash@{n}: <full message>"` entries, or an
|
|
57
|
+
# empty string when there are no stashes; the format matches `git stash list`
|
|
58
|
+
# output
|
|
59
|
+
#
|
|
60
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
61
|
+
#
|
|
62
|
+
# @see #stashes_all
|
|
63
|
+
#
|
|
64
|
+
# @see https://git-scm.com/docs/git-stash git-stash documentation
|
|
65
|
+
#
|
|
66
|
+
def stash_list
|
|
67
|
+
Git::Deprecation.warn(
|
|
68
|
+
'Git::Repository#stash_list is deprecated and will be removed in a future version. ' \
|
|
69
|
+
'Use Git::Repository#stashes_all instead.'
|
|
70
|
+
)
|
|
71
|
+
result = Git::Commands::Stash::List.new(@execution_context).call
|
|
72
|
+
stashes = Git::Parsers::Stash.parse_list(result.stdout)
|
|
73
|
+
stashes.map { |info| "#{info.name}: #{info.message}" }.join("\n")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Save the current working directory and index state to a new stash
|
|
77
|
+
#
|
|
78
|
+
# @param message [String] the stash message
|
|
79
|
+
#
|
|
80
|
+
# @return [Boolean] true if changes were stashed, false if there were no
|
|
81
|
+
# local changes to save
|
|
82
|
+
#
|
|
83
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
84
|
+
#
|
|
85
|
+
# @example Save current changes
|
|
86
|
+
# repo.stash_save('WIP: feature work')
|
|
87
|
+
#
|
|
88
|
+
# @see https://git-scm.com/docs/git-stash git-stash documentation
|
|
89
|
+
#
|
|
90
|
+
def stash_save(message) # rubocop:disable Naming/PredicateMethod
|
|
91
|
+
result = Git::Commands::Stash::Push.new(@execution_context).call(message: message)
|
|
92
|
+
!result.stdout.include?('No local changes to save')
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Apply a stash to the working directory
|
|
96
|
+
#
|
|
97
|
+
# Applies the changes recorded in a stash entry to the working directory
|
|
98
|
+
# without removing the entry from the stash list. Unlike `git stash pop`,
|
|
99
|
+
# the stash entry is preserved after applying.
|
|
100
|
+
#
|
|
101
|
+
# @example Apply the most recent stash
|
|
102
|
+
# repo.stash_apply #=> "HEAD is now at abc1234 Initial commit"
|
|
103
|
+
#
|
|
104
|
+
# @example Apply a specific stash entry by reference
|
|
105
|
+
# repo.stash_apply('stash@{1}') #=> "HEAD is now at abc1234 Initial commit"
|
|
106
|
+
#
|
|
107
|
+
# @param id [String, Integer, nil] the stash identifier (e.g., `'stash@{0}'`,
|
|
108
|
+
# `0`) or `nil` to apply the most recent stash entry. When an Integer is
|
|
109
|
+
# given it is passed directly to git as `stash@{N}`, where `0` is the
|
|
110
|
+
# **most recent** stash — the opposite order from {#stashes_all}'s
|
|
111
|
+
# sequential indices, where `0` is the **oldest** stash.
|
|
112
|
+
#
|
|
113
|
+
# @return [String] the output from the git stash apply command
|
|
114
|
+
#
|
|
115
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
116
|
+
#
|
|
117
|
+
# @see https://git-scm.com/docs/git-stash git-stash documentation
|
|
118
|
+
#
|
|
119
|
+
def stash_apply(id = nil)
|
|
120
|
+
Git::Commands::Stash::Apply.new(@execution_context).call(id).stdout
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Remove all stash entries
|
|
124
|
+
#
|
|
125
|
+
# Removes all entries from the stash list. Use with caution as this
|
|
126
|
+
# operation cannot be undone.
|
|
127
|
+
#
|
|
128
|
+
# @return [String] the output from the git stash clear command
|
|
129
|
+
# (typically empty)
|
|
130
|
+
#
|
|
131
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
132
|
+
#
|
|
133
|
+
# @example Clear all stashes
|
|
134
|
+
# repo.stash_clear #=> ""
|
|
135
|
+
#
|
|
136
|
+
# @see https://git-scm.com/docs/git-stash git-stash documentation
|
|
137
|
+
#
|
|
138
|
+
def stash_clear
|
|
139
|
+
Git::Commands::Stash::Clear.new(@execution_context).call.stdout
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/commands/ls_files'
|
|
4
|
+
require 'git/commands/rev_parse'
|
|
5
|
+
require 'git/escaped_path'
|
|
6
|
+
require 'git/status'
|
|
7
|
+
|
|
8
|
+
module Git
|
|
9
|
+
class Repository
|
|
10
|
+
# Facade methods for repository-status operations
|
|
11
|
+
#
|
|
12
|
+
# Provides methods for querying the state of the repository: checking
|
|
13
|
+
# whether any commits exist, listing untracked working-tree files, and
|
|
14
|
+
# listing files tracked in the index.
|
|
15
|
+
#
|
|
16
|
+
# Included by {Git::Repository}.
|
|
17
|
+
#
|
|
18
|
+
# @api public
|
|
19
|
+
#
|
|
20
|
+
module StatusOperations
|
|
21
|
+
# Returns `true` if the repository has no commits yet
|
|
22
|
+
#
|
|
23
|
+
# Checks whether `HEAD` can be resolved to a commit object. A brand-new
|
|
24
|
+
# repository (or one created with `git checkout --orphan`) where no commit
|
|
25
|
+
# has been made yet will have no commits.
|
|
26
|
+
#
|
|
27
|
+
# @example Check whether a repository is empty
|
|
28
|
+
# repo.no_commits? #=> true # freshly initialized, no commits yet
|
|
29
|
+
# repo.no_commits? #=> false # at least one commit exists
|
|
30
|
+
#
|
|
31
|
+
# @return [Boolean] `true` when the repository has no commits, `false` otherwise
|
|
32
|
+
#
|
|
33
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status other
|
|
34
|
+
# than when the repository has no commits
|
|
35
|
+
#
|
|
36
|
+
def no_commits?
|
|
37
|
+
Git::Commands::RevParse.new(@execution_context).call('HEAD', verify: true)
|
|
38
|
+
false
|
|
39
|
+
rescue Git::FailedError => e
|
|
40
|
+
raise unless e.result.status.exitstatus == 128 &&
|
|
41
|
+
e.result.stderr == 'fatal: Needed a single revision'
|
|
42
|
+
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns `true` if the repository has no commits yet
|
|
47
|
+
#
|
|
48
|
+
# @example Check whether a repository is empty
|
|
49
|
+
# repo.empty? #=> true # freshly initialized, no commits yet
|
|
50
|
+
# repo.empty? #=> false # at least one commit exists
|
|
51
|
+
#
|
|
52
|
+
# @return [Boolean] `true` when the repository has no commits, `false` otherwise
|
|
53
|
+
#
|
|
54
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status other
|
|
55
|
+
# than when the repository has no commits
|
|
56
|
+
#
|
|
57
|
+
# @deprecated Use {#no_commits?} instead
|
|
58
|
+
#
|
|
59
|
+
def empty?
|
|
60
|
+
Git::Deprecation.warn(
|
|
61
|
+
'Git::Repository#empty? is deprecated and will be removed in a future version. ' \
|
|
62
|
+
'Use Git::Repository#no_commits? instead.'
|
|
63
|
+
)
|
|
64
|
+
no_commits?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# List all files in the working tree that are not tracked by git
|
|
68
|
+
#
|
|
69
|
+
# Runs `git ls-files --others --exclude-standard` from the working tree
|
|
70
|
+
# root and returns an array of repository-relative file paths. Files that
|
|
71
|
+
# match `.gitignore` or other standard exclusion rules are omitted.
|
|
72
|
+
#
|
|
73
|
+
# @example Get untracked files
|
|
74
|
+
# repo.untracked_files #=> ["new_feature.rb", "tmp/debug.log"]
|
|
75
|
+
#
|
|
76
|
+
# @example No untracked files
|
|
77
|
+
# repo.untracked_files #=> []
|
|
78
|
+
#
|
|
79
|
+
# @return [Array<String>] repository-relative paths of untracked,
|
|
80
|
+
# non-ignored files; empty when there are none
|
|
81
|
+
#
|
|
82
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
83
|
+
#
|
|
84
|
+
def untracked_files
|
|
85
|
+
Git::Commands::LsFiles.new(@execution_context).call(
|
|
86
|
+
others: true, exclude_standard: true, chdir: @execution_context.git_work_dir
|
|
87
|
+
).stdout.split("\n").map { |f| Private.unescape_quoted_path(f) }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Returns a {Git::Status} object describing the working tree and index state
|
|
91
|
+
#
|
|
92
|
+
# Constructs a {Git::Status} for this repository by collecting information from
|
|
93
|
+
# `git ls-files --stage`, `git ls-files --others`, `git diff-files`, and
|
|
94
|
+
# `git diff-index HEAD` (the last only when at least one commit exists). The
|
|
95
|
+
# result identifies which files have been modified, added, deleted, or are
|
|
96
|
+
# untracked.
|
|
97
|
+
#
|
|
98
|
+
# @example Check which files are modified
|
|
99
|
+
# repo.status.changed #=> { "lib/foo.rb" => <Git::Status::StatusFile ...> }
|
|
100
|
+
#
|
|
101
|
+
# @example Check for untracked files
|
|
102
|
+
# repo.status.untracked #=> { "new_file.rb" => <Git::Status::StatusFile ...> }
|
|
103
|
+
#
|
|
104
|
+
# @example Iterate over all status files
|
|
105
|
+
# repo.status.each { |file| puts "#{file.path}: #{file.type}" }
|
|
106
|
+
#
|
|
107
|
+
# @return [Git::Status] the status of the repository
|
|
108
|
+
#
|
|
109
|
+
# @raise [Git::FailedError] if any underlying git command exits with a
|
|
110
|
+
# non-zero exit status
|
|
111
|
+
#
|
|
112
|
+
def status
|
|
113
|
+
Git::Status.new(self)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# List all files tracked in the index
|
|
117
|
+
#
|
|
118
|
+
# Runs `git ls-files --stage` under the given `location` and returns a
|
|
119
|
+
# hash keyed by file path with per-file index metadata.
|
|
120
|
+
#
|
|
121
|
+
# @example List all indexed files in the working tree
|
|
122
|
+
# repo.ls_files
|
|
123
|
+
# #=> { "README.md" => { path: "README.md", mode_index: "100644",
|
|
124
|
+
# #=> sha_index: "abc123...", stage: "0" }, ... }
|
|
125
|
+
#
|
|
126
|
+
# @example List indexed files under a specific directory
|
|
127
|
+
# repo.ls_files('lib/')
|
|
128
|
+
# #=> { "lib/git.rb" => { path: "lib/git.rb", ... }, ... }
|
|
129
|
+
#
|
|
130
|
+
# @param location [String, nil] the path to restrict the listing to;
|
|
131
|
+
# defaults to `'.'` (all tracked files) when `nil`
|
|
132
|
+
#
|
|
133
|
+
# @return [Hash{String => Hash}] a hash of index entries keyed by file path
|
|
134
|
+
#
|
|
135
|
+
# Each value is a Hash with the following keys:
|
|
136
|
+
# * `:path` [String] the file path
|
|
137
|
+
# * `:mode_index` [String] the file's index mode (e.g. `"100644"`)
|
|
138
|
+
# * `:sha_index` [String] the file's index SHA
|
|
139
|
+
# * `:stage` [String] the merge stage (`"0"` for normal entries)
|
|
140
|
+
#
|
|
141
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
142
|
+
#
|
|
143
|
+
def ls_files(location = nil)
|
|
144
|
+
location ||= '.'
|
|
145
|
+
{}.tap do |files|
|
|
146
|
+
Git::Commands::LsFiles.new(@execution_context).call(location, stage: true).stdout.split("\n").each do |line|
|
|
147
|
+
info, file = Private.split_status_line(line)
|
|
148
|
+
mode, sha, stage = info.split
|
|
149
|
+
files[file] = { path: file, mode_index: mode, sha_index: sha, stage: stage }
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Private helpers local to {Git::Repository::StatusOperations}
|
|
155
|
+
#
|
|
156
|
+
# @api private
|
|
157
|
+
#
|
|
158
|
+
module Private
|
|
159
|
+
module_function
|
|
160
|
+
|
|
161
|
+
# Split a tab-delimited status line from `git ls-files --stage` output
|
|
162
|
+
#
|
|
163
|
+
# The output format is `<mode> <sha> <stage>\t<file>`. Quoted file paths
|
|
164
|
+
# (which git uses when the path contains non-ASCII or special characters)
|
|
165
|
+
# are unescaped before being returned. `line` is assumed to be non-empty
|
|
166
|
+
# because `git ls-files --stage` never emits blank lines.
|
|
167
|
+
#
|
|
168
|
+
# @param line [String] a single line of git ls-files output
|
|
169
|
+
#
|
|
170
|
+
# @return [Array<String>] the tab-delimited parts with the last part
|
|
171
|
+
# unescaped when it was git-quoted
|
|
172
|
+
#
|
|
173
|
+
def split_status_line(line)
|
|
174
|
+
parts = line.split("\t")
|
|
175
|
+
parts[-1] = unescape_quoted_path(parts[-1])
|
|
176
|
+
parts
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Unescape a git-quoted path
|
|
180
|
+
#
|
|
181
|
+
# Git wraps paths containing non-ASCII or special characters in
|
|
182
|
+
# double-quotes and octal-escapes each byte. This method strips the
|
|
183
|
+
# surrounding quotes and delegates unescaping to {Git::EscapedPath}.
|
|
184
|
+
#
|
|
185
|
+
# @param path [String] the path as it appears in git output
|
|
186
|
+
#
|
|
187
|
+
# @return [String] the unescaped path
|
|
188
|
+
#
|
|
189
|
+
def unescape_quoted_path(path)
|
|
190
|
+
if path.start_with?('"') && path.end_with?('"')
|
|
191
|
+
Git::EscapedPath.new(path[1..-2]).unescape
|
|
192
|
+
else
|
|
193
|
+
path
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
private_constant :Private
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/commands/worktree'
|
|
4
|
+
require 'git/worktree'
|
|
5
|
+
require 'git/worktrees'
|
|
6
|
+
|
|
7
|
+
module Git
|
|
8
|
+
class Repository
|
|
9
|
+
# Facade methods for worktree operations
|
|
10
|
+
#
|
|
11
|
+
# Included by {Git::Repository}.
|
|
12
|
+
#
|
|
13
|
+
# @api public
|
|
14
|
+
#
|
|
15
|
+
module WorktreeOperations
|
|
16
|
+
# Returns all worktrees as an array of directory and SHA pairs
|
|
17
|
+
#
|
|
18
|
+
# Lists all worktrees attached to the repository, including the main
|
|
19
|
+
# worktree and all linked worktrees.
|
|
20
|
+
#
|
|
21
|
+
# @example List all worktrees
|
|
22
|
+
# repo.worktrees_all
|
|
23
|
+
# #=> [["/path/to/main", "4bef5ab..."], ["/tmp/worktree-1", "b8c6320..."]]
|
|
24
|
+
#
|
|
25
|
+
# @return [Array<Array(String, String)>] array of `[directory, sha]` pairs
|
|
26
|
+
#
|
|
27
|
+
# `directory` is the worktree path reported by git (absolute or relative,
|
|
28
|
+
# depending on repository configuration); `sha` is the full SHA of the
|
|
29
|
+
# checked-out HEAD commit
|
|
30
|
+
#
|
|
31
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
32
|
+
#
|
|
33
|
+
# @see https://git-scm.com/docs/git-worktree git-worktree documentation
|
|
34
|
+
#
|
|
35
|
+
def worktrees_all
|
|
36
|
+
worktree_entries = []
|
|
37
|
+
current_directory = ''
|
|
38
|
+
command_output = Git::Commands::Worktree::List.new(@execution_context).call(porcelain: true).stdout
|
|
39
|
+
|
|
40
|
+
command_output.each_line(chomp: true) do |line|
|
|
41
|
+
key, value = line.split(' ', 2)
|
|
42
|
+
current_directory = value if key == 'worktree'
|
|
43
|
+
worktree_entries << [current_directory, value] if key == 'HEAD'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
worktree_entries
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Create a new linked worktree at the given directory
|
|
50
|
+
#
|
|
51
|
+
# @example Create a worktree at a path (auto-creates a branch)
|
|
52
|
+
# repo.worktree_add('/tmp/feature')
|
|
53
|
+
#
|
|
54
|
+
# @example Create a worktree and check out an existing commitish
|
|
55
|
+
# repo.worktree_add('/tmp/hotfix', 'main')
|
|
56
|
+
#
|
|
57
|
+
# @param dir [String] filesystem path for the new worktree
|
|
58
|
+
#
|
|
59
|
+
# @param commitish [String, nil] branch, tag, or commit to check out
|
|
60
|
+
#
|
|
61
|
+
# When `nil`, git creates a new branch named after the final path component
|
|
62
|
+
#
|
|
63
|
+
# @return [String] the output from the git worktree add command
|
|
64
|
+
#
|
|
65
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
66
|
+
#
|
|
67
|
+
# @see https://git-scm.com/docs/git-worktree git-worktree documentation
|
|
68
|
+
#
|
|
69
|
+
def worktree_add(dir, commitish = nil)
|
|
70
|
+
args = [dir]
|
|
71
|
+
args << commitish unless commitish.nil?
|
|
72
|
+
|
|
73
|
+
Git::Commands::Worktree::Add.new(@execution_context).call(*args).stdout
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Remove a linked worktree
|
|
77
|
+
#
|
|
78
|
+
# @example Remove a worktree
|
|
79
|
+
# repo.worktree_remove('/tmp/feature')
|
|
80
|
+
#
|
|
81
|
+
# @param dir [String] filesystem path of the worktree to remove
|
|
82
|
+
#
|
|
83
|
+
# @return [String] the output from the git worktree remove command
|
|
84
|
+
# (typically empty)
|
|
85
|
+
#
|
|
86
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
87
|
+
#
|
|
88
|
+
# @see https://git-scm.com/docs/git-worktree git-worktree documentation
|
|
89
|
+
#
|
|
90
|
+
def worktree_remove(dir)
|
|
91
|
+
Git::Commands::Worktree::Remove.new(@execution_context).call(dir).stdout
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Prune stale worktree administrative files
|
|
95
|
+
#
|
|
96
|
+
# Removes stale administrative files from `$GIT_DIR/worktrees`. A
|
|
97
|
+
# worktree becomes stale when its directory no longer exists on disk.
|
|
98
|
+
#
|
|
99
|
+
# @example Prune stale worktrees
|
|
100
|
+
# repo.worktree_prune
|
|
101
|
+
#
|
|
102
|
+
# @return [String] the output from the git worktree prune command
|
|
103
|
+
# (typically empty)
|
|
104
|
+
#
|
|
105
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
106
|
+
#
|
|
107
|
+
# @see https://git-scm.com/docs/git-worktree git-worktree documentation
|
|
108
|
+
#
|
|
109
|
+
def worktree_prune
|
|
110
|
+
Git::Commands::Worktree::Prune.new(@execution_context).call.stdout
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Return a {Git::Worktree} object for the given directory and optional commitish
|
|
114
|
+
#
|
|
115
|
+
# This is a factory method — it constructs the domain object but does not
|
|
116
|
+
# immediately execute any git commands.
|
|
117
|
+
#
|
|
118
|
+
# @example Get a worktree object for a new path
|
|
119
|
+
# wt = repo.worktree('/tmp/feature')
|
|
120
|
+
#
|
|
121
|
+
# @example Get a worktree object for a specific branch or commit
|
|
122
|
+
# wt = repo.worktree('/tmp/hotfix', 'main')
|
|
123
|
+
#
|
|
124
|
+
# @param dir [String] filesystem path for the worktree
|
|
125
|
+
#
|
|
126
|
+
# @param commitish [String, nil] branch, tag, or commit to associate with
|
|
127
|
+
# the worktree; `nil` means no commitish is specified
|
|
128
|
+
#
|
|
129
|
+
# @return [Git::Worktree] a worktree domain object for the given path
|
|
130
|
+
#
|
|
131
|
+
def worktree(dir, commitish = nil)
|
|
132
|
+
Git::Worktree.new(self, dir, commitish)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Return a {Git::Worktrees} collection of all worktrees (main and linked)
|
|
136
|
+
#
|
|
137
|
+
# The collection is populated eagerly when this method is called (git runs
|
|
138
|
+
# at construction time). It is enumerable and supports indexed access by
|
|
139
|
+
# worktree path.
|
|
140
|
+
#
|
|
141
|
+
# @example Iterate over all worktrees
|
|
142
|
+
# repo.worktrees.each { |wt| puts wt.dir }
|
|
143
|
+
#
|
|
144
|
+
# @example Count worktrees
|
|
145
|
+
# repo.worktrees.size
|
|
146
|
+
#
|
|
147
|
+
# @example Access a specific worktree by path
|
|
148
|
+
# repo.worktrees['/tmp/feature']
|
|
149
|
+
#
|
|
150
|
+
# @return [Git::Worktrees] an enumerable collection of all worktrees
|
|
151
|
+
#
|
|
152
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
153
|
+
#
|
|
154
|
+
def worktrees
|
|
155
|
+
Git::Worktrees.new(self)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|