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
data/lib/git/base.rb
DELETED
|
@@ -1,1128 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'logger'
|
|
4
|
-
require 'open3'
|
|
5
|
-
|
|
6
|
-
module Git
|
|
7
|
-
# The main public interface for interacting with Git commands
|
|
8
|
-
#
|
|
9
|
-
# Instead of creating a Git::Base directly, obtain a Git::Base instance by
|
|
10
|
-
# calling one of the follow {Git} class methods: {Git.open}, {Git.init},
|
|
11
|
-
# {Git.clone}, or {Git.bare}.
|
|
12
|
-
#
|
|
13
|
-
# @api public
|
|
14
|
-
#
|
|
15
|
-
class Base
|
|
16
|
-
# (see Git.bare)
|
|
17
|
-
def self.bare(git_dir, options = {})
|
|
18
|
-
normalize_paths(options, default_repository: git_dir, bare: true)
|
|
19
|
-
new(options)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# (see Git.clone)
|
|
23
|
-
def self.clone(repository_url, directory, options = {})
|
|
24
|
-
lib_options = {}
|
|
25
|
-
lib_options[:git_ssh] = options[:git_ssh] if options.key?(:git_ssh)
|
|
26
|
-
new_options = Git::Lib.new(lib_options, options[:log]).clone(repository_url, directory, options)
|
|
27
|
-
normalize_paths(new_options, bare: options[:bare] || options[:mirror])
|
|
28
|
-
new(new_options)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# (see Git.default_branch)
|
|
32
|
-
def self.repository_default_branch(repository, options = {})
|
|
33
|
-
Git::Lib.new(nil, options[:log]).repository_default_branch(repository)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Returns (and initialize if needed) a Git::Config instance
|
|
37
|
-
#
|
|
38
|
-
# @return [Git::Config] the current config instance.
|
|
39
|
-
def self.config
|
|
40
|
-
@config ||= Config.new
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def self.binary_version(binary_path)
|
|
44
|
-
result, status = execute_git_version(binary_path)
|
|
45
|
-
|
|
46
|
-
raise "Failed to get git version: #{status}\n#{result}" unless status.success?
|
|
47
|
-
|
|
48
|
-
parse_version_string(result)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
private_class_method def self.execute_git_version(binary_path)
|
|
52
|
-
Open3.capture2e(
|
|
53
|
-
binary_path,
|
|
54
|
-
'-c', 'core.quotePath=true',
|
|
55
|
-
'-c', 'color.ui=false',
|
|
56
|
-
'version'
|
|
57
|
-
)
|
|
58
|
-
rescue Errno::ENOENT
|
|
59
|
-
raise "Failed to get git version: #{binary_path} not found"
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
private_class_method def self.parse_version_string(raw_string)
|
|
63
|
-
version_match = raw_string.match(/\d+(\.\d+)+/)
|
|
64
|
-
return [0, 0, 0] unless version_match
|
|
65
|
-
|
|
66
|
-
version_parts = version_match[0].split('.').map(&:to_i)
|
|
67
|
-
version_parts.fill(0, version_parts.length...3)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# (see Git.init)
|
|
71
|
-
def self.init(directory = '.', options = {})
|
|
72
|
-
normalize_paths(options, default_working_directory: directory, default_repository: directory,
|
|
73
|
-
bare: options[:bare])
|
|
74
|
-
|
|
75
|
-
init_options = {
|
|
76
|
-
bare: options[:bare],
|
|
77
|
-
initial_branch: options[:initial_branch]
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
directory = options[:bare] ? options[:repository] : options[:working_directory]
|
|
81
|
-
FileUtils.mkdir_p(directory)
|
|
82
|
-
|
|
83
|
-
# TODO: this dance seems awkward: this creates a Git::Lib so we can call
|
|
84
|
-
# init so we can create a new Git::Base which in turn (ultimately)
|
|
85
|
-
# creates another/different Git::Lib.
|
|
86
|
-
#
|
|
87
|
-
# TODO: maybe refactor so this Git::Bare.init does this:
|
|
88
|
-
# self.new(opts).init(init_opts) and move all/some of this code into
|
|
89
|
-
# Git::Bare#init. This way the init method can be called on any
|
|
90
|
-
# repository you have a Git::Base instance for. This would not
|
|
91
|
-
# change the existing interface (other than adding to it).
|
|
92
|
-
#
|
|
93
|
-
Git::Lib.new(options).init(init_options)
|
|
94
|
-
|
|
95
|
-
new(options)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def self.root_of_worktree(working_dir)
|
|
99
|
-
raise ArgumentError, "'#{working_dir}' does not exist" unless Dir.exist?(working_dir)
|
|
100
|
-
|
|
101
|
-
result, status = execute_rev_parse_toplevel(working_dir)
|
|
102
|
-
process_rev_parse_result(result, status, working_dir)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
private_class_method def self.execute_rev_parse_toplevel(working_dir)
|
|
106
|
-
Open3.capture2e(
|
|
107
|
-
Git::Base.config.binary_path,
|
|
108
|
-
'-c', 'core.quotePath=true',
|
|
109
|
-
'-c', 'color.ui=false',
|
|
110
|
-
'rev-parse', '--show-toplevel',
|
|
111
|
-
chdir: File.expand_path(working_dir)
|
|
112
|
-
)
|
|
113
|
-
rescue Errno::ENOENT
|
|
114
|
-
raise ArgumentError, 'Failed to find the root of the worktree: git binary not found'
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
private_class_method def self.process_rev_parse_result(result, status, working_dir)
|
|
118
|
-
raise ArgumentError, "'#{working_dir}' is not in a git working tree" unless status.success?
|
|
119
|
-
|
|
120
|
-
result.chomp
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# (see Git.open)
|
|
124
|
-
def self.open(working_dir, options = {})
|
|
125
|
-
raise ArgumentError, "'#{working_dir}' is not a directory" unless Dir.exist?(working_dir)
|
|
126
|
-
|
|
127
|
-
working_dir = root_of_worktree(working_dir) unless options[:repository]
|
|
128
|
-
|
|
129
|
-
normalize_paths(options, default_working_directory: working_dir)
|
|
130
|
-
|
|
131
|
-
new(options)
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# Create an object that executes Git commands in the context of a working
|
|
135
|
-
# copy or a bare repository.
|
|
136
|
-
#
|
|
137
|
-
# @param [Hash] options The options for this command (see list of valid
|
|
138
|
-
# options below)
|
|
139
|
-
#
|
|
140
|
-
# @option options [Pathname] :working_dir the path to the root of the working
|
|
141
|
-
# directory. Should be `nil` if executing commands on a bare repository.
|
|
142
|
-
#
|
|
143
|
-
# @option options [Pathname] :repository used to specify a non-standard path to
|
|
144
|
-
# the repository directory. The default is `"#{working_dir}/.git"`.
|
|
145
|
-
#
|
|
146
|
-
# @option options [Pathname] :index used to specify a non-standard path to an
|
|
147
|
-
# index file. The default is `"#{working_dir}/.git/index"`
|
|
148
|
-
#
|
|
149
|
-
# @option options [Logger] :log A logger to use for Git operations. Git
|
|
150
|
-
# commands are logged at the `:info` level. Additional logging is done
|
|
151
|
-
# at the `:debug` level.
|
|
152
|
-
#
|
|
153
|
-
# @option options [String, nil] :git_ssh Path to a custom SSH executable or script.
|
|
154
|
-
# Controls how SSH is configured for this {Git::Base} instance:
|
|
155
|
-
# - If this option is not provided, the global Git::Base.config.git_ssh setting is used.
|
|
156
|
-
# - If this option is explicitly set to nil, SSH is disabled for this instance.
|
|
157
|
-
# - If this option is a non-empty String, that value is used as the SSH command for
|
|
158
|
-
# this instance, overriding the global Git::Base.config.git_ssh setting.
|
|
159
|
-
#
|
|
160
|
-
# @return [Git::Base] an object that can execute git commands in the context
|
|
161
|
-
# of the opened working copy or bare repository
|
|
162
|
-
#
|
|
163
|
-
def initialize(options = {})
|
|
164
|
-
options = default_paths(options)
|
|
165
|
-
setup_logger(options[:log])
|
|
166
|
-
@git_ssh = options.key?(:git_ssh) ? options[:git_ssh] : :use_global_config
|
|
167
|
-
initialize_components(options)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# Update the index from the current worktree to prepare the for the next commit
|
|
171
|
-
#
|
|
172
|
-
# @example
|
|
173
|
-
# lib.add('path/to/file')
|
|
174
|
-
# lib.add(['path/to/file1','path/to/file2'])
|
|
175
|
-
# lib.add(all: true)
|
|
176
|
-
#
|
|
177
|
-
# @param [String, Array<String>] paths a file or files to be added to the repository (relative to the worktree root)
|
|
178
|
-
# @param [Hash] options
|
|
179
|
-
#
|
|
180
|
-
# @option options [Boolean] :all Add, modify, and remove index entries to match the worktree
|
|
181
|
-
# @option options [Boolean] :force Allow adding otherwise ignored files
|
|
182
|
-
#
|
|
183
|
-
def add(paths = '.', **options)
|
|
184
|
-
lib.add(paths, options)
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
# adds a new remote to this repository
|
|
188
|
-
# url can be a git url or a Git::Base object if it's a local reference
|
|
189
|
-
#
|
|
190
|
-
# @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git')
|
|
191
|
-
# @git.fetch('scotts_git')
|
|
192
|
-
# @git.merge('scotts_git/master')
|
|
193
|
-
#
|
|
194
|
-
# Options:
|
|
195
|
-
# :fetch => true
|
|
196
|
-
# :track => <branch_name>
|
|
197
|
-
def add_remote(name, url, opts = {})
|
|
198
|
-
url = url.repo.to_s if url.is_a?(Git::Base)
|
|
199
|
-
lib.remote_add(name, url, opts)
|
|
200
|
-
Git::Remote.new(self, name)
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
# changes current working directory for a block
|
|
204
|
-
# to the git working directory
|
|
205
|
-
#
|
|
206
|
-
# example
|
|
207
|
-
# @git.chdir do
|
|
208
|
-
# # write files
|
|
209
|
-
# @git.add
|
|
210
|
-
# @git.commit('message')
|
|
211
|
-
# end
|
|
212
|
-
def chdir # :yields: the Git::Path
|
|
213
|
-
Dir.chdir(dir.to_s) do
|
|
214
|
-
yield dir.to_s
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
# g.config('user.name', 'Scott Chacon') # sets value
|
|
219
|
-
# g.config('user.email', 'email@email.com') # sets value
|
|
220
|
-
# g.config('user.email', 'email@email.com', file: 'path/to/custom/config) # sets value in file
|
|
221
|
-
# g.config('user.name') # returns 'Scott Chacon'
|
|
222
|
-
# g.config # returns whole config hash
|
|
223
|
-
def config(name = nil, value = nil, options = {})
|
|
224
|
-
if name && value
|
|
225
|
-
# set value
|
|
226
|
-
lib.config_set(name, value, options)
|
|
227
|
-
elsif name
|
|
228
|
-
# return value
|
|
229
|
-
lib.config_get(name)
|
|
230
|
-
else
|
|
231
|
-
# return hash
|
|
232
|
-
lib.config_list
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
# returns a reference to the working directory
|
|
237
|
-
# @git.dir.path
|
|
238
|
-
# @git.dir.writeable?
|
|
239
|
-
def dir
|
|
240
|
-
@working_directory
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
# returns reference to the git index file
|
|
244
|
-
attr_reader :index
|
|
245
|
-
|
|
246
|
-
# returns reference to the git repository directory
|
|
247
|
-
# @git.dir.path
|
|
248
|
-
def repo
|
|
249
|
-
@repository
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
# returns the repository size in bytes
|
|
253
|
-
def repo_size
|
|
254
|
-
all_files = Dir.glob(File.join(repo.path, '**', '*'), File::FNM_DOTMATCH)
|
|
255
|
-
|
|
256
|
-
all_files.reject { |file| file.include?('..') }
|
|
257
|
-
.map { |file| File.expand_path(file) }
|
|
258
|
-
.uniq
|
|
259
|
-
.sum { |file| File.stat(file).size.to_i }
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def set_index(index_file, check = nil, must_exist: nil)
|
|
263
|
-
unless check.nil?
|
|
264
|
-
Git::Deprecation.warn(
|
|
265
|
-
'The "check" argument is deprecated and will be removed in a future version. ' \
|
|
266
|
-
'Use "must_exist:" instead.'
|
|
267
|
-
)
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
# default is true
|
|
271
|
-
must_exist = must_exist.nil? && check.nil? ? true : must_exist | check
|
|
272
|
-
|
|
273
|
-
@lib = nil
|
|
274
|
-
@index = Git::Index.new(index_file.to_s, must_exist:)
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
def set_working(work_dir, check = nil, must_exist: nil)
|
|
278
|
-
unless check.nil?
|
|
279
|
-
Git::Deprecation.warn(
|
|
280
|
-
'The "check" argument is deprecated and will be removed in a future version. ' \
|
|
281
|
-
'Use "must_exist:" instead.'
|
|
282
|
-
)
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
# default is true
|
|
286
|
-
must_exist = must_exist.nil? && check.nil? ? true : must_exist | check
|
|
287
|
-
|
|
288
|
-
@lib = nil
|
|
289
|
-
@working_directory = Git::WorkingDirectory.new(work_dir.to_s, must_exist:)
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
# returns +true+ if the branch exists locally
|
|
293
|
-
def local_branch?(branch)
|
|
294
|
-
branch_names = branches.local.map(&:name)
|
|
295
|
-
branch_names.include?(branch)
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
def is_local_branch?(branch) # rubocop:disable Naming/PredicatePrefix
|
|
299
|
-
Git::Deprecation.warn(
|
|
300
|
-
'Git::Base#is_local_branch? is deprecated and will be removed in a future version. ' \
|
|
301
|
-
'Use Git::Base#local_branch? instead.'
|
|
302
|
-
)
|
|
303
|
-
local_branch?(branch)
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
# returns +true+ if the branch exists remotely
|
|
307
|
-
def remote_branch?(branch)
|
|
308
|
-
branch_names = branches.remote.map(&:name)
|
|
309
|
-
branch_names.include?(branch)
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
def is_remote_branch?(branch) # rubocop:disable Naming/PredicatePrefix
|
|
313
|
-
Git::Deprecation.warn(
|
|
314
|
-
'Git::Base#is_remote_branch? is deprecated and will be removed in a future version. ' \
|
|
315
|
-
'Use Git::Base#remote_branch? instead.'
|
|
316
|
-
)
|
|
317
|
-
remote_branch?(branch)
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
# returns +true+ if the branch exists
|
|
321
|
-
def branch?(branch)
|
|
322
|
-
branch_names = branches.map(&:name)
|
|
323
|
-
branch_names.include?(branch)
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
def is_branch?(branch) # rubocop:disable Naming/PredicatePrefix
|
|
327
|
-
Git::Deprecation.warn(
|
|
328
|
-
'Git::Base#is_branch? is deprecated and will be removed in a future version. ' \
|
|
329
|
-
'Use Git::Base#branch? instead.'
|
|
330
|
-
)
|
|
331
|
-
branch?(branch)
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
# this is a convenience method for accessing the class that wraps all the
|
|
335
|
-
# actual 'git' forked system calls. At some point I hope to replace the Git::Lib
|
|
336
|
-
# class with one that uses native methods or libgit C bindings
|
|
337
|
-
def lib
|
|
338
|
-
@lib ||= Git::Lib.new(self, @logger)
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
# Returns the per-instance git_ssh configuration value.
|
|
342
|
-
#
|
|
343
|
-
# This may be:
|
|
344
|
-
# * a [String] path when an explicit git_ssh command has been configured
|
|
345
|
-
# * the Symbol `:use_global_config` when this instance is using the global config
|
|
346
|
-
# * `nil` when SSH has been explicitly disabled for this instance
|
|
347
|
-
#
|
|
348
|
-
# @return [String, Symbol, nil] the git_ssh configuration value for this instance
|
|
349
|
-
# @api private
|
|
350
|
-
attr_reader :git_ssh
|
|
351
|
-
|
|
352
|
-
# Run a grep for 'string' on the HEAD of the git repository
|
|
353
|
-
#
|
|
354
|
-
# @example Limit grep's scope by calling grep() from a specific object:
|
|
355
|
-
# git.object("v2.3").grep('TODO')
|
|
356
|
-
#
|
|
357
|
-
# @example Using grep results:
|
|
358
|
-
# git.grep("TODO").each do |sha, arr|
|
|
359
|
-
# puts "in blob #{sha}:"
|
|
360
|
-
# arr.each do |line_no, match_string|
|
|
361
|
-
# puts "\t line #{line_no}: '#{match_string}'"
|
|
362
|
-
# end
|
|
363
|
-
# end
|
|
364
|
-
#
|
|
365
|
-
# @param string [String] the string to search for
|
|
366
|
-
# @param path_limiter [String, Pathname, Array<String, Pathname>] a path or array
|
|
367
|
-
# of paths to limit the search to or nil for no limit
|
|
368
|
-
# @param opts [Hash] options to pass to the underlying `git grep` command
|
|
369
|
-
#
|
|
370
|
-
# @option opts [Boolean] :ignore_case (false) ignore case when matching
|
|
371
|
-
# @option opts [Boolean] :invert_match (false) select non-matching lines
|
|
372
|
-
# @option opts [Boolean] :extended_regexp (false) use extended regular expressions
|
|
373
|
-
# @option opts [String] :object (HEAD) the object to search from
|
|
374
|
-
#
|
|
375
|
-
# @return [Hash<String, Array>] a hash of arrays
|
|
376
|
-
# ```Ruby
|
|
377
|
-
# {
|
|
378
|
-
# 'tree-ish1' => [[line_no1, match_string1], ...],
|
|
379
|
-
# 'tree-ish2' => [[line_no1, match_string1], ...],
|
|
380
|
-
# ...
|
|
381
|
-
# }
|
|
382
|
-
# ```
|
|
383
|
-
#
|
|
384
|
-
def grep(string, path_limiter = nil, opts = {})
|
|
385
|
-
object('HEAD').grep(string, path_limiter, opts)
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
# List the files in the worktree that are ignored by git
|
|
389
|
-
# @return [Array<String>] the list of ignored files relative to teh root of the worktree
|
|
390
|
-
#
|
|
391
|
-
def ignored_files
|
|
392
|
-
lib.ignored_files
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
# removes file(s) from the git repository
|
|
396
|
-
def rm(path = '.', opts = {})
|
|
397
|
-
lib.rm(path, opts)
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
alias remove rm
|
|
401
|
-
|
|
402
|
-
# resets the working directory to the provided commitish
|
|
403
|
-
def reset(commitish = nil, opts = {})
|
|
404
|
-
lib.reset(commitish, opts)
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
# resets the working directory to the commitish with '--hard'
|
|
408
|
-
def reset_hard(commitish = nil, opts = {})
|
|
409
|
-
opts = { hard: true }.merge(opts)
|
|
410
|
-
lib.reset(commitish, opts)
|
|
411
|
-
end
|
|
412
|
-
|
|
413
|
-
# cleans the working directory
|
|
414
|
-
#
|
|
415
|
-
# options:
|
|
416
|
-
# :force
|
|
417
|
-
# :d
|
|
418
|
-
# :ff
|
|
419
|
-
#
|
|
420
|
-
def clean(opts = {})
|
|
421
|
-
lib.clean(opts)
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
# returns the most recent tag that is reachable from a commit
|
|
425
|
-
#
|
|
426
|
-
# options:
|
|
427
|
-
# :all
|
|
428
|
-
# :tags
|
|
429
|
-
# :contains
|
|
430
|
-
# :debug
|
|
431
|
-
# :exact_match
|
|
432
|
-
# :dirty
|
|
433
|
-
# :abbrev
|
|
434
|
-
# :candidates
|
|
435
|
-
# :long
|
|
436
|
-
# :always
|
|
437
|
-
# :match
|
|
438
|
-
#
|
|
439
|
-
def describe(committish = nil, opts = {})
|
|
440
|
-
lib.describe(committish, opts)
|
|
441
|
-
end
|
|
442
|
-
|
|
443
|
-
# reverts the working directory to the provided commitish.
|
|
444
|
-
# Accepts a range, such as comittish..HEAD
|
|
445
|
-
#
|
|
446
|
-
# options:
|
|
447
|
-
# :no_edit
|
|
448
|
-
#
|
|
449
|
-
def revert(commitish = nil, opts = {})
|
|
450
|
-
lib.revert(commitish, opts)
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
# commits all pending changes in the index file to the git repository
|
|
454
|
-
#
|
|
455
|
-
# options:
|
|
456
|
-
# :all
|
|
457
|
-
# :allow_empty
|
|
458
|
-
# :amend
|
|
459
|
-
# :author
|
|
460
|
-
#
|
|
461
|
-
def commit(message, opts = {})
|
|
462
|
-
lib.commit(message, opts)
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
# commits all pending changes in the index file to the git repository,
|
|
466
|
-
# but automatically adds all modified files without having to explicitly
|
|
467
|
-
# calling @git.add() on them.
|
|
468
|
-
def commit_all(message, opts = {})
|
|
469
|
-
opts = { add_all: true }.merge(opts)
|
|
470
|
-
lib.commit(message, opts)
|
|
471
|
-
end
|
|
472
|
-
|
|
473
|
-
# checks out a branch as the new git working directory
|
|
474
|
-
def checkout(*, **)
|
|
475
|
-
lib.checkout(*, **)
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
# checks out an old version of a file
|
|
479
|
-
def checkout_file(version, file)
|
|
480
|
-
lib.checkout_file(version, file)
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
# fetches changes from a remote branch - this does not modify the working directory,
|
|
484
|
-
# it just gets the changes from the remote if there are any
|
|
485
|
-
def fetch(remote = 'origin', opts = {})
|
|
486
|
-
if remote.is_a?(Hash)
|
|
487
|
-
opts = remote
|
|
488
|
-
remote = nil
|
|
489
|
-
end
|
|
490
|
-
lib.fetch(remote, opts)
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
# Push changes to a remote repository
|
|
494
|
-
#
|
|
495
|
-
# @overload push(remote = nil, branch = nil, options = {})
|
|
496
|
-
# @param remote [String] the remote repository to push to
|
|
497
|
-
# @param branch [String] the branch to push
|
|
498
|
-
# @param options [Hash] options to pass to the push command
|
|
499
|
-
#
|
|
500
|
-
# @option opts [Boolean] :mirror (false) Push all refs under refs/heads/, refs/tags/ and refs/remotes/
|
|
501
|
-
# @option opts [Boolean] :delete (false) Delete refs that don't exist on the remote
|
|
502
|
-
# @option opts [Boolean] :force (false) Force updates
|
|
503
|
-
# @option opts [Boolean] :tags (false) Push all refs under refs/tags/
|
|
504
|
-
# @option opts [Array, String] :push_options (nil) Push options to transmit
|
|
505
|
-
#
|
|
506
|
-
# @return [Void]
|
|
507
|
-
#
|
|
508
|
-
# @raise [Git::FailedError] if the push fails
|
|
509
|
-
# @raise [ArgumentError] if a branch is given without a remote
|
|
510
|
-
#
|
|
511
|
-
def push(*, **)
|
|
512
|
-
lib.push(*, **)
|
|
513
|
-
end
|
|
514
|
-
|
|
515
|
-
# merges one or more branches into the current working branch
|
|
516
|
-
#
|
|
517
|
-
# you can specify more than one branch to merge by passing an array of branches
|
|
518
|
-
def merge(branch, message = 'merge', opts = {})
|
|
519
|
-
lib.merge(branch, message, opts)
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
# iterates over the files which are unmerged
|
|
523
|
-
def each_conflict(&) # :yields: file, your_version, their_version
|
|
524
|
-
lib.conflicts(&)
|
|
525
|
-
end
|
|
526
|
-
|
|
527
|
-
# Pulls the given branch from the given remote into the current branch
|
|
528
|
-
#
|
|
529
|
-
# @param remote [String] the remote repository to pull from
|
|
530
|
-
# @param branch [String] the branch to pull from
|
|
531
|
-
# @param opts [Hash] options to pass to the pull command
|
|
532
|
-
#
|
|
533
|
-
# @option opts [Boolean] :allow_unrelated_histories (false) Merges histories of
|
|
534
|
-
# two projects that started their lives independently
|
|
535
|
-
# @example pulls from origin/master
|
|
536
|
-
# @git.pull
|
|
537
|
-
# @example pulls from upstream/master
|
|
538
|
-
# @git.pull('upstream')
|
|
539
|
-
# @example pulls from upstream/develop
|
|
540
|
-
# @git.pull('upstream', 'develop')
|
|
541
|
-
#
|
|
542
|
-
# @return [Void]
|
|
543
|
-
#
|
|
544
|
-
# @raise [Git::FailedError] if the pull fails
|
|
545
|
-
# @raise [ArgumentError] if a branch is given without a remote
|
|
546
|
-
def pull(remote = nil, branch = nil, opts = {})
|
|
547
|
-
lib.pull(remote, branch, opts)
|
|
548
|
-
end
|
|
549
|
-
|
|
550
|
-
# returns an array of Git:Remote objects
|
|
551
|
-
def remotes
|
|
552
|
-
lib.remotes.map { |r| Git::Remote.new(self, r) }
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
# sets the url for a remote
|
|
556
|
-
# url can be a git url or a Git::Base object if it's a local reference
|
|
557
|
-
#
|
|
558
|
-
# @git.set_remote_url('scotts_git', 'git://repo.or.cz/rubygit.git')
|
|
559
|
-
#
|
|
560
|
-
def set_remote_url(name, url)
|
|
561
|
-
url = url.repo.to_s if url.is_a?(Git::Base)
|
|
562
|
-
lib.remote_set_url(name, url)
|
|
563
|
-
Git::Remote.new(self, name)
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
# Configures which branches are fetched for a remote
|
|
567
|
-
#
|
|
568
|
-
# Uses `git remote set-branches` to set or append fetch refspecs. When the `add:`
|
|
569
|
-
# option is not given, the `--add` option is not passed to the git command
|
|
570
|
-
#
|
|
571
|
-
# @example Replace fetched branches with a single glob pattern
|
|
572
|
-
# git = Git.open('/path/to/repo')
|
|
573
|
-
# # Only fetch branches matching "feature/*" from origin
|
|
574
|
-
# git.remote_set_branches('origin', 'feature/*')
|
|
575
|
-
#
|
|
576
|
-
# @example Append a glob pattern to existing fetched branches
|
|
577
|
-
# git = Git.open('/path/to/repo')
|
|
578
|
-
# # Keep existing fetch refspecs and add all release branches
|
|
579
|
-
# git.remote_set_branches('origin', 'release/*', add: true)
|
|
580
|
-
#
|
|
581
|
-
# @example Configure multiple explicit branches
|
|
582
|
-
# git = Git.open('/path/to/repo')
|
|
583
|
-
# git.remote_set_branches('origin', 'main', 'development', 'hotfix')
|
|
584
|
-
#
|
|
585
|
-
# @param name [String] the remote name (for example, "origin")
|
|
586
|
-
# @param branches [Array<String>] branch names or globs (for example, '*')
|
|
587
|
-
# @param add [Boolean] when true, append to existing refspecs instead of replacing them
|
|
588
|
-
#
|
|
589
|
-
# @return [nil]
|
|
590
|
-
#
|
|
591
|
-
# @raise [ArgumentError] if no branches are provided @raise [Git::FailedError] if
|
|
592
|
-
# the underlying git command fails
|
|
593
|
-
#
|
|
594
|
-
def remote_set_branches(name, *branches, add: false)
|
|
595
|
-
branch_list = branches.flatten
|
|
596
|
-
raise ArgumentError, 'branches are required' if branch_list.empty?
|
|
597
|
-
|
|
598
|
-
lib.remote_set_branches(name, branch_list, add: add)
|
|
599
|
-
|
|
600
|
-
nil
|
|
601
|
-
end
|
|
602
|
-
|
|
603
|
-
# removes a remote from this repository
|
|
604
|
-
#
|
|
605
|
-
# @git.remove_remote('scott_git')
|
|
606
|
-
def remove_remote(name)
|
|
607
|
-
lib.remote_remove(name)
|
|
608
|
-
end
|
|
609
|
-
|
|
610
|
-
# returns an array of all Git::Tag objects for this repository
|
|
611
|
-
def tags
|
|
612
|
-
lib.tags.map { |r| tag(r) }
|
|
613
|
-
end
|
|
614
|
-
|
|
615
|
-
# Create a new git tag
|
|
616
|
-
#
|
|
617
|
-
# @example
|
|
618
|
-
# repo.add_tag('tag_name', object_reference)
|
|
619
|
-
# repo.add_tag('tag_name', object_reference, {:options => 'here'})
|
|
620
|
-
# repo.add_tag('tag_name', {:options => 'here'})
|
|
621
|
-
#
|
|
622
|
-
# @param [String] name The name of the tag to add
|
|
623
|
-
# @param [Hash] options Opstions to pass to `git tag`.
|
|
624
|
-
# See [git-tag](https://git-scm.com/docs/git-tag) for more details.
|
|
625
|
-
# @option options [boolean] :annotate Make an unsigned, annotated tag object
|
|
626
|
-
# @option options [boolean] :a An alias for the `:annotate` option
|
|
627
|
-
# @option options [boolean] :d Delete existing tag with the given names.
|
|
628
|
-
# @option options [boolean] :f Replace an existing tag with the given name (instead of failing)
|
|
629
|
-
# @option options [String] :message Use the given tag message
|
|
630
|
-
# @option options [String] :m An alias for the `:message` option
|
|
631
|
-
# @option options [boolean] :s Make a GPG-signed tag.
|
|
632
|
-
#
|
|
633
|
-
def add_tag(name, *options)
|
|
634
|
-
lib.tag(name, *options)
|
|
635
|
-
tag(name)
|
|
636
|
-
end
|
|
637
|
-
|
|
638
|
-
# deletes a tag
|
|
639
|
-
def delete_tag(name)
|
|
640
|
-
lib.tag(name, { d: true })
|
|
641
|
-
end
|
|
642
|
-
|
|
643
|
-
# creates an archive file of the given tree-ish
|
|
644
|
-
def archive(treeish, file = nil, opts = {})
|
|
645
|
-
object(treeish).archive(file, opts)
|
|
646
|
-
end
|
|
647
|
-
|
|
648
|
-
# repacks the repository
|
|
649
|
-
def repack
|
|
650
|
-
lib.repack
|
|
651
|
-
end
|
|
652
|
-
|
|
653
|
-
def gc
|
|
654
|
-
lib.gc
|
|
655
|
-
end
|
|
656
|
-
|
|
657
|
-
# Verifies the connectivity and validity of objects in the database
|
|
658
|
-
#
|
|
659
|
-
# Runs `git fsck` to check repository integrity and identify dangling,
|
|
660
|
-
# missing, or unreachable objects.
|
|
661
|
-
#
|
|
662
|
-
# @overload fsck(objects = [], options = {})
|
|
663
|
-
# @param objects [Array<String>] specific objects to treat as heads for unreachability trace.
|
|
664
|
-
# If no objects are given, git fsck defaults to using the index file, all SHA-1
|
|
665
|
-
# references in the refs namespace, and all reflogs.
|
|
666
|
-
# @param [Hash] options options to pass to the underlying `git fsck` command
|
|
667
|
-
#
|
|
668
|
-
# @option options [Boolean] :unreachable print unreachable objects
|
|
669
|
-
# @option options [Boolean] :strict enable strict checking
|
|
670
|
-
# @option options [Boolean] :connectivity_only check only connectivity (faster)
|
|
671
|
-
# @option options [Boolean] :root report root nodes
|
|
672
|
-
# @option options [Boolean] :tags report tags
|
|
673
|
-
# @option options [Boolean] :cache consider objects in the index
|
|
674
|
-
# @option options [Boolean] :no_reflogs do not consider reflogs
|
|
675
|
-
# @option options [Boolean] :lost_found write dangling objects to .git/lost-found
|
|
676
|
-
# (note: this modifies the repository by creating files)
|
|
677
|
-
# @option options [Boolean, nil] :dangling print dangling objects (true/false/nil for default)
|
|
678
|
-
# @option options [Boolean, nil] :full check objects in alternate pools (true/false/nil for default)
|
|
679
|
-
# @option options [Boolean, nil] :name_objects name objects by refs (true/false/nil for default)
|
|
680
|
-
# @option options [Boolean, nil] :references check refs database consistency (true/false/nil for default)
|
|
681
|
-
#
|
|
682
|
-
# @return [Git::FsckResult] categorized objects flagged by fsck
|
|
683
|
-
#
|
|
684
|
-
# @example Check repository integrity
|
|
685
|
-
# result = git.fsck
|
|
686
|
-
# result.dangling.each { |obj| puts "#{obj.type}: #{obj.sha}" }
|
|
687
|
-
#
|
|
688
|
-
# @example Check with strict mode and suppress dangling output
|
|
689
|
-
# result = git.fsck(strict: true, dangling: false)
|
|
690
|
-
#
|
|
691
|
-
# @example Check if repository has any issues
|
|
692
|
-
# result = git.fsck
|
|
693
|
-
# puts "Repository is clean" if result.empty?
|
|
694
|
-
#
|
|
695
|
-
# @example List root commits
|
|
696
|
-
# result = git.fsck(root: true)
|
|
697
|
-
# result.root.each { |obj| puts obj.sha }
|
|
698
|
-
#
|
|
699
|
-
# @example Check specific objects
|
|
700
|
-
# result = git.fsck('abc1234', 'def5678')
|
|
701
|
-
#
|
|
702
|
-
# rubocop:disable Style/ArgumentsForwarding
|
|
703
|
-
def fsck(*objects, **opts)
|
|
704
|
-
lib.fsck(*objects, **opts)
|
|
705
|
-
end
|
|
706
|
-
# rubocop:enable Style/ArgumentsForwarding
|
|
707
|
-
|
|
708
|
-
def apply(file)
|
|
709
|
-
return unless File.exist?(file)
|
|
710
|
-
|
|
711
|
-
lib.apply(file)
|
|
712
|
-
end
|
|
713
|
-
|
|
714
|
-
def apply_mail(file)
|
|
715
|
-
lib.apply_mail(file) if File.exist?(file)
|
|
716
|
-
end
|
|
717
|
-
|
|
718
|
-
# Shows objects
|
|
719
|
-
#
|
|
720
|
-
# @param [String|NilClass] objectish the target object reference (nil == HEAD)
|
|
721
|
-
# @param [String|NilClass] path the path of the file to be shown
|
|
722
|
-
# @return [String] the object information
|
|
723
|
-
def show(objectish = nil, path = nil)
|
|
724
|
-
lib.show(objectish, path)
|
|
725
|
-
end
|
|
726
|
-
|
|
727
|
-
## LOWER LEVEL INDEX OPERATIONS ##
|
|
728
|
-
|
|
729
|
-
def with_index(new_index) # :yields: new_index
|
|
730
|
-
old_index = @index
|
|
731
|
-
set_index(new_index, false)
|
|
732
|
-
return_value = yield @index
|
|
733
|
-
set_index(old_index)
|
|
734
|
-
return_value
|
|
735
|
-
end
|
|
736
|
-
|
|
737
|
-
def with_temp_index(&)
|
|
738
|
-
# Workaround for JRUBY, since they handle the TempFile path different.
|
|
739
|
-
# MUST be improved to be safer and OS independent.
|
|
740
|
-
if RUBY_PLATFORM == 'java'
|
|
741
|
-
temp_path = "/tmp/temp-index-#{(0...15).map { ('a'..'z').to_a[rand(26)] }.join}"
|
|
742
|
-
else
|
|
743
|
-
tempfile = Tempfile.new('temp-index')
|
|
744
|
-
temp_path = tempfile.path
|
|
745
|
-
tempfile.close
|
|
746
|
-
tempfile.unlink
|
|
747
|
-
end
|
|
748
|
-
|
|
749
|
-
with_index(temp_path, &)
|
|
750
|
-
end
|
|
751
|
-
|
|
752
|
-
def checkout_index(opts = {})
|
|
753
|
-
lib.checkout_index(opts)
|
|
754
|
-
end
|
|
755
|
-
|
|
756
|
-
def read_tree(treeish, opts = {})
|
|
757
|
-
lib.read_tree(treeish, opts)
|
|
758
|
-
end
|
|
759
|
-
|
|
760
|
-
def write_tree
|
|
761
|
-
lib.write_tree
|
|
762
|
-
end
|
|
763
|
-
|
|
764
|
-
def write_and_commit_tree(opts = {})
|
|
765
|
-
tree = write_tree
|
|
766
|
-
commit_tree(tree, opts)
|
|
767
|
-
end
|
|
768
|
-
|
|
769
|
-
def update_ref(branch, commit)
|
|
770
|
-
branch(branch).update_ref(commit)
|
|
771
|
-
end
|
|
772
|
-
|
|
773
|
-
def ls_files(location = nil)
|
|
774
|
-
lib.ls_files(location)
|
|
775
|
-
end
|
|
776
|
-
|
|
777
|
-
def with_working(work_dir) # :yields: the Git::WorkingDirectory
|
|
778
|
-
return_value = false
|
|
779
|
-
old_working = @working_directory
|
|
780
|
-
set_working(work_dir)
|
|
781
|
-
Dir.chdir work_dir do
|
|
782
|
-
return_value = yield @working_directory
|
|
783
|
-
end
|
|
784
|
-
set_working(old_working)
|
|
785
|
-
return_value
|
|
786
|
-
end
|
|
787
|
-
|
|
788
|
-
def with_temp_working(&)
|
|
789
|
-
tempfile = Tempfile.new('temp-workdir')
|
|
790
|
-
temp_dir = tempfile.path
|
|
791
|
-
tempfile.close
|
|
792
|
-
tempfile.unlink
|
|
793
|
-
Dir.mkdir(temp_dir, 0o700)
|
|
794
|
-
with_working(temp_dir, &)
|
|
795
|
-
end
|
|
796
|
-
|
|
797
|
-
# runs git rev-parse to convert the objectish to a full sha
|
|
798
|
-
#
|
|
799
|
-
# @example
|
|
800
|
-
# git.rev_parse("HEAD^^")
|
|
801
|
-
# git.rev_parse('v2.4^{tree}')
|
|
802
|
-
# git.rev_parse('v2.4:/doc/index.html')
|
|
803
|
-
#
|
|
804
|
-
def rev_parse(objectish)
|
|
805
|
-
lib.rev_parse(objectish)
|
|
806
|
-
end
|
|
807
|
-
|
|
808
|
-
# For backwards compatibility
|
|
809
|
-
alias revparse rev_parse
|
|
810
|
-
|
|
811
|
-
def ls_tree(objectish, opts = {})
|
|
812
|
-
lib.ls_tree(objectish, opts)
|
|
813
|
-
end
|
|
814
|
-
|
|
815
|
-
# Returns the contents of a git object
|
|
816
|
-
#
|
|
817
|
-
# Uses `git cat-file -p` to pretty-print the contents of the given object.
|
|
818
|
-
#
|
|
819
|
-
# @param objectish [String] a SHA, branch name, tag, or other revision reference
|
|
820
|
-
# to the git object
|
|
821
|
-
#
|
|
822
|
-
# @return [String] the contents of the object
|
|
823
|
-
#
|
|
824
|
-
# @see https://git-scm.com/docs/git-cat-file git-cat-file
|
|
825
|
-
#
|
|
826
|
-
def cat_file(objectish)
|
|
827
|
-
lib.cat_file_contents(objectish)
|
|
828
|
-
end
|
|
829
|
-
|
|
830
|
-
# The name of the branch HEAD refers to or 'HEAD' if detached
|
|
831
|
-
#
|
|
832
|
-
# Returns one of the following:
|
|
833
|
-
# * The branch name that HEAD refers to (even if it is an unborn branch)
|
|
834
|
-
# * 'HEAD' if in a detached HEAD state
|
|
835
|
-
#
|
|
836
|
-
# @return [String] the name of the branch HEAD refers to or 'HEAD' if detached
|
|
837
|
-
#
|
|
838
|
-
def current_branch
|
|
839
|
-
lib.branch_current
|
|
840
|
-
end
|
|
841
|
-
|
|
842
|
-
# @return [Git::Branch] an object for branch_name
|
|
843
|
-
def branch(branch_name = current_branch)
|
|
844
|
-
Git::Branch.new(self, branch_name)
|
|
845
|
-
end
|
|
846
|
-
|
|
847
|
-
# @return [Git::Branches] a collection of all the branches in the repository.
|
|
848
|
-
# Each branch is represented as a {Git::Branch}.
|
|
849
|
-
def branches
|
|
850
|
-
Git::Branches.new(self)
|
|
851
|
-
end
|
|
852
|
-
|
|
853
|
-
# returns a Git::Worktree object for dir, commitish
|
|
854
|
-
def worktree(dir, commitish = nil)
|
|
855
|
-
Git::Worktree.new(self, dir, commitish)
|
|
856
|
-
end
|
|
857
|
-
|
|
858
|
-
# returns a Git::worktrees object of all the Git::Worktrees
|
|
859
|
-
# objects for this repo
|
|
860
|
-
def worktrees
|
|
861
|
-
Git::Worktrees.new(self)
|
|
862
|
-
end
|
|
863
|
-
|
|
864
|
-
# @return [Git::Object::Commit] a commit object
|
|
865
|
-
def commit_tree(tree = nil, opts = {})
|
|
866
|
-
Git::Object::Commit.new(self, lib.commit_tree(tree, opts))
|
|
867
|
-
end
|
|
868
|
-
|
|
869
|
-
# @return [Git::Diff] a Git::Diff object
|
|
870
|
-
def diff(objectish = 'HEAD', obj2 = nil)
|
|
871
|
-
Git::Diff.new(self, objectish, obj2)
|
|
872
|
-
end
|
|
873
|
-
|
|
874
|
-
# @return [Git::Object] a Git object
|
|
875
|
-
def gblob(objectish)
|
|
876
|
-
Git::Object.new(self, objectish, 'blob')
|
|
877
|
-
end
|
|
878
|
-
|
|
879
|
-
# @return [Git::Object] a Git object
|
|
880
|
-
def gcommit(objectish)
|
|
881
|
-
Git::Object.new(self, objectish, 'commit')
|
|
882
|
-
end
|
|
883
|
-
|
|
884
|
-
# @return [Git::Object] a Git object
|
|
885
|
-
def gtree(objectish)
|
|
886
|
-
Git::Object.new(self, objectish, 'tree')
|
|
887
|
-
end
|
|
888
|
-
|
|
889
|
-
# @return [Git::Log] a log with the specified number of commits
|
|
890
|
-
def log(count = 30)
|
|
891
|
-
Git::Log.new(self, count)
|
|
892
|
-
end
|
|
893
|
-
|
|
894
|
-
# returns a Git::Object of the appropriate type
|
|
895
|
-
# you can also call @git.gtree('tree'), but that's
|
|
896
|
-
# just for readability. If you call @git.gtree('HEAD') it will
|
|
897
|
-
# still return a Git::Object::Commit object.
|
|
898
|
-
#
|
|
899
|
-
# object calls a method that will run a rev-parse
|
|
900
|
-
# on the objectish and determine the type of the object and return
|
|
901
|
-
# an appropriate object for that type
|
|
902
|
-
#
|
|
903
|
-
# @return [Git::Object] an instance of the appropriate type of Git::Object
|
|
904
|
-
def object(objectish)
|
|
905
|
-
Git::Object.new(self, objectish)
|
|
906
|
-
end
|
|
907
|
-
|
|
908
|
-
# @return [Git::Remote] a remote of the specified name
|
|
909
|
-
def remote(remote_name = 'origin')
|
|
910
|
-
Git::Remote.new(self, remote_name)
|
|
911
|
-
end
|
|
912
|
-
|
|
913
|
-
# @return [Git::Status] a status object
|
|
914
|
-
def status
|
|
915
|
-
Git::Status.new(self)
|
|
916
|
-
end
|
|
917
|
-
|
|
918
|
-
# @return [Git::Object::Tag] a tag object
|
|
919
|
-
def tag(tag_name)
|
|
920
|
-
Git::Object::Tag.new(self, tag_name)
|
|
921
|
-
end
|
|
922
|
-
|
|
923
|
-
# Find as good common ancestors as possible for a merge
|
|
924
|
-
# example: g.merge_base('master', 'some_branch', 'some_sha', octopus: true)
|
|
925
|
-
#
|
|
926
|
-
# @return [Array<Git::Object::Commit>] a collection of common ancestors
|
|
927
|
-
def merge_base(*)
|
|
928
|
-
shas = lib.merge_base(*)
|
|
929
|
-
shas.map { |sha| gcommit(sha) }
|
|
930
|
-
end
|
|
931
|
-
|
|
932
|
-
# Returns a Git::Diff::Stats object for accessing diff statistics.
|
|
933
|
-
#
|
|
934
|
-
# @param objectish [String] The first commit or object to compare. Defaults to 'HEAD'.
|
|
935
|
-
# @param obj2 [String, nil] The second commit or object to compare.
|
|
936
|
-
# @param opts [Hash] Options to filter the diff.
|
|
937
|
-
# @option opts [String, Pathname, Array<String, Pathname>] :path_limiter Limit stats to specified path(s).
|
|
938
|
-
# @return [Git::DiffStats]
|
|
939
|
-
def diff_stats(objectish = 'HEAD', obj2 = nil, opts = {})
|
|
940
|
-
Git::DiffStats.new(self, objectish, obj2, opts[:path_limiter])
|
|
941
|
-
end
|
|
942
|
-
|
|
943
|
-
# Returns a Git::Diff::PathStatus object for accessing the name-status report.
|
|
944
|
-
#
|
|
945
|
-
# @param objectish [String] The first commit or object to compare. Defaults to 'HEAD'.
|
|
946
|
-
# @param obj2 [String, nil] The second commit or object to compare.
|
|
947
|
-
# @param opts [Hash] Options to filter the diff.
|
|
948
|
-
# @option opts [String, Pathname, Array<String, Pathname>] :path_limiter Limit status to specified path(s).
|
|
949
|
-
# @option opts [String, Pathname, Array<String, Pathname>] :path (deprecated) Legacy alias for :path_limiter.
|
|
950
|
-
# @return [Git::DiffPathStatus]
|
|
951
|
-
def diff_path_status(objectish = 'HEAD', obj2 = nil, opts = {})
|
|
952
|
-
path_limiter = if opts.key?(:path_limiter)
|
|
953
|
-
opts[:path_limiter]
|
|
954
|
-
elsif opts.key?(:path)
|
|
955
|
-
Git::Deprecation.warn(
|
|
956
|
-
'Git::Base#diff_path_status :path option is deprecated. Use :path_limiter instead.'
|
|
957
|
-
)
|
|
958
|
-
opts[:path]
|
|
959
|
-
end
|
|
960
|
-
|
|
961
|
-
Git::DiffPathStatus.new(self, objectish, obj2, path_limiter)
|
|
962
|
-
end
|
|
963
|
-
|
|
964
|
-
# Provided for backwards compatibility
|
|
965
|
-
alias diff_name_status diff_path_status
|
|
966
|
-
|
|
967
|
-
private
|
|
968
|
-
|
|
969
|
-
# Sets default paths in the options hash for direct `Git::Base.new` calls
|
|
970
|
-
#
|
|
971
|
-
# Factory methods like `Git.open` pre-populate these options by calling
|
|
972
|
-
# `normalize_paths`, making this a fallback. It avoids mutating the
|
|
973
|
-
# original options hash by returning a new one.
|
|
974
|
-
#
|
|
975
|
-
# @param options [Hash] the original options hash
|
|
976
|
-
# @return [Hash] a new options hash with defaults applied
|
|
977
|
-
def default_paths(options)
|
|
978
|
-
return options unless (working_dir = options[:working_directory])
|
|
979
|
-
|
|
980
|
-
options.dup.tap do |opts|
|
|
981
|
-
opts[:repository] ||= File.join(working_dir, '.git')
|
|
982
|
-
opts[:index] ||= File.join(opts[:repository], 'index')
|
|
983
|
-
end
|
|
984
|
-
end
|
|
985
|
-
|
|
986
|
-
# Initializes the logger from the provided options
|
|
987
|
-
# @param log_option [Logger, nil] The logger instance from options.
|
|
988
|
-
def setup_logger(log_option)
|
|
989
|
-
@logger = log_option || Logger.new(nil)
|
|
990
|
-
@logger.info('Starting Git')
|
|
991
|
-
end
|
|
992
|
-
|
|
993
|
-
# Initializes the core git objects based on the provided options
|
|
994
|
-
# @param options [Hash] The processed options hash.
|
|
995
|
-
def initialize_components(options)
|
|
996
|
-
@working_directory = Git::WorkingDirectory.new(options[:working_directory]) if options[:working_directory]
|
|
997
|
-
@repository = Git::Repository.new(options[:repository]) if options[:repository]
|
|
998
|
-
@index = Git::Index.new(options[:index], must_exist: false) if options[:index]
|
|
999
|
-
end
|
|
1000
|
-
|
|
1001
|
-
# Normalize options before they are sent to Git::Base.new
|
|
1002
|
-
#
|
|
1003
|
-
# Updates the options parameter by setting appropriate values for the following keys:
|
|
1004
|
-
# * options[:working_directory]
|
|
1005
|
-
# * options[:repository]
|
|
1006
|
-
# * options[:index]
|
|
1007
|
-
#
|
|
1008
|
-
# All three values will be set to absolute paths. An exception is that
|
|
1009
|
-
# :working_directory will be set to nil if bare is true.
|
|
1010
|
-
#
|
|
1011
|
-
private_class_method def self.normalize_paths(
|
|
1012
|
-
options, default_working_directory: nil, default_repository: nil, bare: false
|
|
1013
|
-
)
|
|
1014
|
-
normalize_working_directory(options, default: default_working_directory, bare: bare)
|
|
1015
|
-
normalize_repository(options, default: default_repository, bare: bare)
|
|
1016
|
-
normalize_index(options)
|
|
1017
|
-
end
|
|
1018
|
-
|
|
1019
|
-
# Normalize options[:working_directory]
|
|
1020
|
-
#
|
|
1021
|
-
# If working with a bare repository, set to `nil`.
|
|
1022
|
-
# Otherwise, set to the first non-nil value of:
|
|
1023
|
-
# 1. `options[:working_directory]`,
|
|
1024
|
-
# 2. the `default` parameter, or
|
|
1025
|
-
# 3. the current working directory
|
|
1026
|
-
#
|
|
1027
|
-
# Finally, if options[:working_directory] is a relative path, convert it to an absoluite
|
|
1028
|
-
# path relative to the current directory.
|
|
1029
|
-
#
|
|
1030
|
-
private_class_method def self.normalize_working_directory(options, default:, bare: false)
|
|
1031
|
-
working_directory =
|
|
1032
|
-
if bare
|
|
1033
|
-
nil
|
|
1034
|
-
else
|
|
1035
|
-
File.expand_path(options[:working_directory] || default || Dir.pwd)
|
|
1036
|
-
end
|
|
1037
|
-
|
|
1038
|
-
options[:working_directory] = working_directory
|
|
1039
|
-
end
|
|
1040
|
-
|
|
1041
|
-
# Normalize options[:repository]
|
|
1042
|
-
#
|
|
1043
|
-
# If working with a bare repository, set to the first non-nil value out of:
|
|
1044
|
-
# 1. `options[:repository]`
|
|
1045
|
-
# 2. the `default` parameter
|
|
1046
|
-
# 3. the current working directory
|
|
1047
|
-
#
|
|
1048
|
-
# Otherwise, set to the first non-nil value of:
|
|
1049
|
-
# 1. `options[:repository]`
|
|
1050
|
-
# 2. `.git`
|
|
1051
|
-
#
|
|
1052
|
-
# Next, if options[:repository] refers to a *file* and not a *directory*, set
|
|
1053
|
-
# options[:repository] to the contents of that file. This is the case when
|
|
1054
|
-
# working with a submodule or a secondary working tree (created with git worktree
|
|
1055
|
-
# add). In these cases the repository is actually contained/nested within the
|
|
1056
|
-
# parent's repository directory.
|
|
1057
|
-
#
|
|
1058
|
-
# Finally, if options[:repository] is a relative path, convert it to an absolute
|
|
1059
|
-
# path relative to:
|
|
1060
|
-
# 1. the current directory if working with a bare repository or
|
|
1061
|
-
# 2. the working directory if NOT working with a bare repository
|
|
1062
|
-
#
|
|
1063
|
-
private_class_method def self.normalize_repository(options, default:, bare: false)
|
|
1064
|
-
initial_path = initial_repository_path(options, default: default, bare: bare)
|
|
1065
|
-
final_path = resolve_gitdir_if_present(initial_path, options[:working_directory])
|
|
1066
|
-
options[:repository] = final_path
|
|
1067
|
-
end
|
|
1068
|
-
|
|
1069
|
-
# Determines the initial, potential path to the repository directory
|
|
1070
|
-
#
|
|
1071
|
-
# This path is considered 'initial' because it is not guaranteed to be the
|
|
1072
|
-
# final repository location. For features like submodules or worktrees,
|
|
1073
|
-
# this path may point to a text file containing a `gitdir:` pointer to the
|
|
1074
|
-
# actual repository directory elsewhere. This initial path must be
|
|
1075
|
-
# subsequently resolved.
|
|
1076
|
-
#
|
|
1077
|
-
# @api private
|
|
1078
|
-
#
|
|
1079
|
-
# @param options [Hash] The options hash, checked for `[:repository]`.
|
|
1080
|
-
#
|
|
1081
|
-
# @param default [String] A fallback path if `options[:repository]` is not set.
|
|
1082
|
-
#
|
|
1083
|
-
# @param bare [Boolean] Whether the repository is bare, which changes path resolution.
|
|
1084
|
-
#
|
|
1085
|
-
# @return [String] The initial, absolute path to the `.git` directory or file.
|
|
1086
|
-
#
|
|
1087
|
-
private_class_method def self.initial_repository_path(options, default:, bare:)
|
|
1088
|
-
if bare
|
|
1089
|
-
File.expand_path(options[:repository] || default || Dir.pwd)
|
|
1090
|
-
else
|
|
1091
|
-
File.expand_path(options[:repository] || '.git', options[:working_directory])
|
|
1092
|
-
end
|
|
1093
|
-
end
|
|
1094
|
-
|
|
1095
|
-
# Resolves the path to the actual repository if it's a `gitdir:` pointer file.
|
|
1096
|
-
#
|
|
1097
|
-
# If `path` points to a file (common in submodules and worktrees), this
|
|
1098
|
-
# method reads the `gitdir:` path from it and returns the real repository
|
|
1099
|
-
# path. Otherwise, it returns the original path.
|
|
1100
|
-
#
|
|
1101
|
-
# @api private
|
|
1102
|
-
#
|
|
1103
|
-
# @param path [String] The initial path to the repository, which may be a pointer file.
|
|
1104
|
-
#
|
|
1105
|
-
# @param working_dir [String] The working directory, used as a base to resolve the path.
|
|
1106
|
-
#
|
|
1107
|
-
# @return [String] The final, resolved absolute path to the repository directory.
|
|
1108
|
-
#
|
|
1109
|
-
private_class_method def self.resolve_gitdir_if_present(path, working_dir)
|
|
1110
|
-
return path unless File.file?(path)
|
|
1111
|
-
|
|
1112
|
-
# The file contains `gitdir: <path>`, so we read the file,
|
|
1113
|
-
# extract the path part, and expand it.
|
|
1114
|
-
gitdir_pointer = File.read(path).sub(/\Agitdir: /, '').strip
|
|
1115
|
-
File.expand_path(gitdir_pointer, working_dir)
|
|
1116
|
-
end
|
|
1117
|
-
|
|
1118
|
-
# Normalize options[:index]
|
|
1119
|
-
#
|
|
1120
|
-
# If options[:index] is a relative directory, convert it to an absolute
|
|
1121
|
-
# directory relative to the repository directory
|
|
1122
|
-
#
|
|
1123
|
-
private_class_method def self.normalize_index(options)
|
|
1124
|
-
index = File.expand_path(options[:index] || 'index', options[:repository])
|
|
1125
|
-
options[:index] = index
|
|
1126
|
-
end
|
|
1127
|
-
end
|
|
1128
|
-
end
|